1.组织数据
一个用户信息包括
- 姓名
- 邮箱
- 手机号
- 年龄
这里面包括了多个信息,每个信息类型可能不同,这里数组搞不定了。
使用结构体来封装一些属性,设计出新的类型,在C语言中称为结构体类型。
结构体类型定义的一般格式如下:
struct是定义结构体类型的关键字;结构体类型名必须是合法的C标识符,与其前面的struct一起共同构成结构体类型名;花括号内的内容是结构体类型所包括的结构体成员,也称为结构体成员。
struct User
{
char name[50];
char mobile[12];
int age;
char email[255];
};
//无名称结构体
struct
{
char name[50];
char mobile[12];
int age;
char email[255];
};
内存分配,每个元素是独立的,有自己占用的空间
sprintf
函数用于将格式化的数据写入字符串,它将输出存储在sprintf中指定的char缓冲区中,而不是在控制台上进行打印
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。 format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。
返回值
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
struct User
{
char name[50];
char mobile[12];
int age;
char email[255];
};
void main() {
struct User user;//创建了一个结构体变量
user.age = 10;
printf("结构体编号:%d\n", user.age);
sprintf(user.name, "张三");//将张三写入user.name
strcpy(user.mobile, "17600999999");//用copy方式
printf("%s\n", user.name);
printf("%s\n", user.mobile);
system("pause");
}
使用define ,这里只是做了一个简单的替换
#define SUser struct User
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
SUser
{
char name[50];
char mobile[12];
int age;
char email[255];
};
void main() {
SUser user;//创建了一个结构体变量
user.age = 10;
printf("结构体编号:%d\n", user.age);
sprintf(user.name, "张三");//将张三写入user.name
strcpy(user.mobile, "17600999999");//用copy方式
printf("%s\n", user.name);
printf("%s\n", user.mobile);
system("pause");
}
#include<stdio.h>
#include<stdlib.h>
struct Person {
int age;//结构体定义不能赋值
char name[100];
};
void main() {
struct Person p1 = { 99,"张三" };
struct Person p2 = p1;
printf("%d,%s\n", p2.age, p2.name);
//这里用字符串copy
strcpy(p1.name, "李四");
printf("%d,%s\n", p1.age, p1.name);
printf("%d,%s\n", p2.age, p2.name);
getchar();
}
结构体包含
struct Person {
int age;//结构体定义不能赋值
char name[100];
//定义部门信息
struct dept{
char dept_name[20];
int num;
};
};
void main() {
struct Person p1;
p1.age = 99;
p1.num = 10;
strcpy(p1.dept_name, "IT");
strcpy(p1.name, "张三");
printf("%d,%s,%d,%s", p1.age, p1.name,p1.num,p1.dept_name);
}
实例化一个结构体中的子结构体
#include<stdio.h>
#include<stdlib.h>
struct Person {
int age;//结构体定义不能赋值
char name[100];
struct dept {
char dept_name[20];
int num;
}d1;//这里是一个实例了
};
void main() {
struct Person p1;
p1.age = 99;
p1.d1.num = 10;
strcpy(p1.d1.dept_name, "IT");
strcpy(p1.name, "张三");
printf("%d,%s,%d,%s", p1.age, p1.name,p1.d1.num,p1.d1.dept_name);
}
子结构体实例
struct Person {
int age;//结构体定义不能赋值
char name[100];
struct dept {
char dept_name[20];
int num;
}d1;//这里是一个实例了
struct dept d2;
};
void main() {
struct Person p1;
p1.age = 99;
p1.d1.num = 10;
strcpy(p1.d1.dept_name, "IT");
strcpy(p1.name, "张三");
p1.d2.num = 1000;
printf("%d,%s,%d,%s,%d", p1.age, p1.name,p1.d1.num,p1.d1.dept_name,p1.d2.num);
}
匿名结构体
匿名结构体不会出现重合 重命名的情况
有名结构体 名称不能相同 也就是不能重名
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
//这个是匿名结构体
struct
{
char name[50];
int age;
int dept[50];
};
struct
{
char name[50];
int age;
int dept[50];
} u1, u2, u3; //这里实例化
void main() {
u1.age = 10;
u2.age = 20;
u3.age = 40;
sprintf(u1.name, "李四");
printf("%d,%d,%d,%s", u1.age, u2.age, u3.age,u1.name);
}
2.结构体数组
声明的几种方法
struct Person
{
char name[30];
int age;
};
void main() {
struct Person b1[2];
sprintf(b1[0].name, "张三");
printf("%s", b1[0].name);
}
struct Person
{
char name[30];
int age;
}p[20];
void main() {
sprintf(p[0].name, "张三");
printf("%s", p[0].name);
}
struct Person
{
char name[30];
int age;
}p[20];
void main() {
sprintf(p[0].name, "张三");
printf("%s", p[0].name);
}
查看内存
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
struct data
{
int qty;
float f1;
char name[4];
}db[3] = {
{1,1.0,"A"},
{2,2.0,"B"},
{3,3.0,"C"}
};
void main() {
printf("%p\n", &db);
printf("%p\n", &db[0]);
printf("%p\n", &db[1]);
printf("%p\n", &db[2]);
getchar();
}
结构体数组在内存中也是一个个排列的。
3.结构体指针
指向结构体变量的指针
struct person *p
#include<stdio.h>
#include<stdlib.h>
struct Person {
int num;
int age;
char name[100];
};
void main() {
struct Person person;
person.num = 1;
person.age = 99;
strcpy(person.name, "张三");
printf("%s\n", person.name);
//用结构体指针保存一个地址
struct Person* p;
p = &person;
printf("%d,%s\n", (*p).num,(*p).name);
printf("%d,%s", p->num, p->name);
}
可以用→访问一个指针结构体
指向结构体数组的指针
struct data
{
int qty;
float f1;
char name[4];
}db[3] = {
{1,1.0,"A"},
{2,2.0,"B"},
{3,3.0,"C"}
};
void main() {
struct data* d;
d = db;
for (int i = 0; i < 3; i++)
{
printf("%d,%f,%s\n", d->qty, d->f1, d->name);
d++;
}
}
void main() {
for (struct data *p =db ; p < db+3; p++)
{
printf("%d,%f,%s\n", p->qty, p->f1, p->name);
}
}
用指向结构体的指针作函数参数
- 用结构体变量的成员作参数
- 用指向结构体变量或数组的指针作参数
- 用结构体变量作参数
用结构体作参数,内存消耗多
#include<stdio.h>
#include<stdlib.h>
struct data
{
int qty;
float f1;
char name[4];
};
void changedata(struct data *d) {
d->qty = 100;
}
void main() {
struct data d;
d.qty = 1;
printf("%d\n", d.qty);
changedata(&d);
printf("%d", d.qty);
}
4.union共用体
union 共用体名{
成员列表
};
共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。
结构体占用的内存大于等于所有成员占用的内存的总和,共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。
union的大小取决于最大的一个成员变量大小
union Data
{
int i;
float f;
char str[20];
};
int main()
{
union Data data;
printf("内存大小 : %d\n", sizeof(data));
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
union data {
int n;
char name[20];
double d;
};
void main() {
union data d1;
d1.d = 10;
d1.n = 99;
sprintf(d1.name, "张三");
printf("%d\n", d1.n);
printf("%f\n", d1.d);
printf("%s\n", d1.name);
}
看一下这段,内存地址
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
union data {
long l;
int i;
};
void main() {
union data d;
d.l = 5;
printf("%d,%p\n", d.l, &d.l);
d.i = 6;
printf("%d,%p\n", d.i,&d.i);
printf("%d,%p\n", d.l, &d.l);
}
其实总结union,就是一个固定首地址,按最大类型给你一段内存空间。
几种申明方式,这里与struct基本一样的。
union data
{
int i;
char ch;
float f;
}a, b;
union
{
int i;
char ch;
} a,b;
//联合体模板union perdata重新命名为perdata_U
typedef union perdata
{
int i;
char ch;
} perdata_U;
// 使用新名字perdata_U创建两个变量a, b
void main() {
perdata_U a, b;
}
再次看一下长度是怎么计算出来的
union Data
{
int i;
char str[10];
};
int main()
{
union Data data;
printf("内存大小 : %d\n", sizeof(data));
return 0;
}
这里会是12,为什么是12,第一步,成员变量最长是的是int,它是4个字节,char只是1,这里千万不是认为是按变量长度计算的,4的整数倍*3=12,可以大于str[10],因些长度就是12了。
共用体变量引用
union Data
{
int i;
char str[10];
};
int main()
{
union Data data;
union Data* d1 = &data;
data.i = 1;
printf("%d\n", d1->i);
sprintf(data.str, "hi");
printf("%s\n", d1->str);
return 0;
}
共用体在一般的编程中应用较少,在单片机中应用较多。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
struct User {
char name[40];
union Age {
int age;
char status[20];
} AS;
};
void main() {
struct User user1;
sprintf(user1.name, "张三");
int age = 0;
scanf("%d", &age);
if (age < 0 || age>150) {
sprintf(user1.AS.status, "出错了");
printf("%s,%s", user1.name, user1.AS.status);
}
else {
user1.AS.age = age;
printf("%s,%d", user1.name, user1.AS.age);
}
}
5.枚举类型
枚举是 C 语言中的一种基本数据类型,用于定义一组具有离散值的常量。,它可以让数据更简洁,更易读。
枚举类型通常用于为程序中的一组相关的常量取名字,以便于程序的可读性和维护性。
定义一个枚举类型,需要使用 enum 关键字,后面跟着枚举类型的名称,以及用大括号 {} 括起来的一组枚举常量。每个枚举常量可以用一个标识符来表示,也可以为它们指定一个整数值,如果没有指定,那么默认从 0 开始递增。
enum 枚举名 {枚举元素1,枚举元素2,……};
enum DAY
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
enum DAY
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
} day;
enum
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
} day;
enum DAY
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
void main() {
enum DAY day;
day = FRI;
printf("%d", day);//5
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
enum DAY
{
MON = 1, TUE, WED, THU, FRI, SAT, SUN
};
void main() {
enum DAY day;
printf("请输入今天星期几:\n");
scanf("%d", &day);
switch (day)
{
case MON:
printf("怎么就周一了!!!");
break;
case TUE:
printf("痛苦的周二!!!");
break;
case WED:
printf("没有盼头的周二!!!");
break;
case THU:
printf("总算看到希望了!!!");
break;
case FRI:
printf("快乐的周五!!!");
break;
case SAT:
printf("浪!!!");
break;
case SUN:
printf("浪!!!");
break;
default:
break;
}
}
在没有用枚举前,想想这个是不是了可以。
#define Mon 1
#define Tues 2
#define Wed 3
#define Thurs 4
#define Fri 5
#define Sat 6
#define Sun 7
用枚举类型声明枚举变量时,只能取集合中的某项作为其值,这在一定程度上保证了取值的安全性。
6.Typedef
C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。
- 按定义变量方法先写出定义体 如 int i;
- 将变量名换成新类型名 如 int INTEGER;
- 最前面加typedef 如 typedef int INTEGER;
- 用新类型名定义变量 如 INTEGER i,j;
注意:
- typedef 没有创造新数据类型;
- typedef 是定义类型,不能定义变量;
- typedef 与 define 不同(define:预编译时处理、简单字符置换;typedef:编译时处理、为已有类型命名。)
typedef int 整数;
void main() {
整数 x = 100;
}
#define 整数 int
void main() {
整数 x = 100;
}
我们定义一个BYTE类型
typedef unsigned char BYTE;
void main() {
BYTE b1, b2;
b1 = 'A';
printf("%c", b1);
}
定义一个书的自定义类型
typedef struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
int main() {
Book book;
strcpy(book.title, "C 教程");
strcpy(book.author, "MICROSOFT");
strcpy(book.subject, "开发");
book.book_id = 1;
}
7.练习
指针初使化结构体
struct School {
char name[50];
int id;
};
void main() {
struct School* p;
p = (union school*)malloc(sizeof(struct School));
p->id = 10;
strcpy(p->name, "北大");
printf("%d\n", p->id);
printf("%s", p->name);
}
指针初使化共用体
union School {
char name[50];
int id;
};
void main() {
union School* p;
p = (union school*)malloc(sizeof(union School));
p->id = 10;
printf("%d\n", p->id);
strcpy(p->name, "北大");
printf("%s", p->name);
}
复杂结构体
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct School {
char name[50];
int id;
struct Student {
char name[50];
int age;
} ST[10];
};
void main() {
struct School school;
sprintf(school.name, "北京大学");
school.id = 1;
for (int i = 0; i < 10; i++)
{
school.ST[i].age = 10*(i+1);
char no[2];
_itoa(i, no, 10);//将i以10进制的形式写入no中
char name[20] = "张飞";
strcat(name, no);//链接两个字符串
sprintf(school.ST[i].name, name);
}
for (int i = 0; i < 10; i++)
{
printf("%s,%d\n", school.ST[i].name
, school.ST[i].age);
}
}