结构体
概念:用户自定义的数据类型,在结构体中可以包含若干个不同类型数据的成员变量(也可以相同), 使这些数据项组合起来反映某一个信息
定义格式
struct 结构体名
{
数据类型 成员变量 1;
数据类型 成员变量 2;
数据类型 成员变量 3;
......
};
结构体变量
概念: 通过结构体类型定义的变量
定义格式
先定义结构体,再定义结构体变量
struct 结构体名
{
成员变量;
};
struct 结构体名 变量名;
#include <stdio.h>
struct student
{
int id;
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu;
return 0;
}
定义结构体的同时,定义结构体变量
struct 结构体名
{
成员变量;
} 变量名;
#include <stdio.h>
struct student
{
int id;
int age;
float score;
}stu;
int main(int argc, char const *argv[])
{
return 0;
}
缺省结构体名,定义结构体变量
struct
{
成员变量;
} 变量名;
#include <stdio.h>
struct
{
int id;
int age;
float score;
}stu;
int main(int argc, char const *argv[])
{
return 0;
}
赋值
定义变量时直接用大括号赋值
#include <stdio.h>
struct student
{
int id;
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu = {1, 20, 88};
return 0;
}
定义变量时未初始化,然后对变量单独赋值
#include <stdio.h>
struct student
{
int id;
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu;
stu.id = 1;
stu.age = 20;
stu.score = 88;
return 0;
}
大括号点等法赋值
#include <stdio.h>
struct student
{
int id;
char name[32];
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu =
{
.id = 1,
.age = 20,
.score = 88
};
return 0;
}
访问
通过.访问:结构体变量名.成员变量名
输出:printf("%d %d %f\n", stu.id, stu.age, stu.score,stu.name);
输入:scanf("%d %d %f %s", &stu.id, &stu.age, &stu.score, stu.name);
stu.name 就不用加&,因为这个数组名本身就是地址
#include<stdio.h>
struct student
{
char name[32];
int id;
int age;
float score;
}stu;
int main(int argc, char const *argv[])
{
scanf("%s %d %d %d",stu.name,&stu.id,&stu.age,&stu.score);
printf("name:%s id:%d age:%d\n",stu.name,stu.id,stu.age,stu.score);
return 0;
}
结构体数组
概念:结构体类型相同的变量组成的数组
定义格式
定义结构体同时定义结构体数组
struct student
{
int id;
int age;
float score;
}stu[3];
先定义结构体,然后定义结构体数组
#include <stdio.h>
struct student
{
int id;
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu[3];
return 0;
}
赋值
定义结构体数组同时赋值
#include <stdio.h>
struct student
{
int id;
int age;
float score;
};
int main(int argc, char const *argv[])
{
struct student stu[3] =
{
{1, 20, 88},
{2, 21, 89},
{3, 19, 90}
};
return 0;
}
先定义结构体数组,然后对数组的每一个元素分别赋值
#include <stdio.h>
struct student
{
int id;
int age;
float score;
} stu[3];
int main(int argc, char const *argv[])
{
stu[0].id = 1;
stu[0].age = 20;
stu[0].score = 88;
stu[1].id = 2;
stu[1].age = 21;
stu[1].score = 89;
return 0;
}
数组大小
结构体类型大小*元素个数
sizeof(结构体数组名);
输入输出(for 循环)
#include <stdio.h>
struct student
{
int id;
int age;
float score;
}stu[3];
int main(int argc, char const *argv[])
{
for (int i = 0; i < 3; i++)
{
scanf("%d %d %f", &stu[i].id, &stu[i].age, &stu[i].score);
}
for (i = 0; i < 3; i++)
{
if (stu[i].score >= 60)
printf("name:%s id:%d age:%d score:%f\n", stu[i].name, stu[i].id, stu[i].age,stu[i].score);
}
return 0;
}
结构体指针
概念:指向结构体变量的指针
定义格式
struct 结构体名 *结构体指针名;
#include <stdio.h>
struct student
{
int id;
int age;
float score;
}stu1, stu2;
struct work
{
int id;
int age;
float score;
}w1, w2;
int main(int argc, char const *argv[])
{
struct student *p = &stu1;
struct student *p1 = &w1; // 错误,结构体类型不匹配
return 0;
}
赋值
指针变量名 -> 成员变量名
p -> id = 1;
p -> age = 20;
p -> score = 88;
(*指针变量名).成员变量名
(*p).id = 2;
#include <stdio.h>
struct student
{
int id;
int age;
float score;
}stu1;
int main(int argc, char const *argv[])
{
struct student *p = &stu1;
scanf("%d %d %f", &p->id, &p->age, &p->score);
printf("%d %d %f\n", p->id, p->age, (*p).score);
return 0;
}
结构体大小
结构体大小并不是简单的将每个结构体成员的大小相加就能得到的
sizeof(struct 结构体名); // 结构体类型大小
struct student
{
int id; //8
int age;
float score; //8
char a;
double b; //8
};
sizeof(struct student); // 24
结构体内存对齐规则
第一个成员变量偏移量为 0 地址处。(结构体的首地址处)
其他成员变量要对齐到自身大小的的整数倍
如果嵌套了结构体,嵌套的结构体对齐到自己的最大整数的倍数处,结构体整体的大小就是所有最大对齐数的整数倍
对齐数:该结构体成员自身的大小与编译器默认的大小比较,取小值
注意:32位操作系统默认的对齐数4 | 64位操作系统默认的对齐数8
字节对齐原则
用结构体里面最大的数据类型的大小和8进行比较,按照字节数小的为单位开辟空间
例子:
struct student
{
double a;
char b;
int c;
};
// 16
总结
- 不能把结构体变量作为整体引用,只能对结构体变量中各个成员变量分别引用
- 如果成员变量本身属于另一种结构体类型,用若干个成员运算符一级级找到你想要的成员变量
#include <stdio.h>
struct work
{
int ip;
};
struct student
{
int id;
int age;
struct work w1;
} stu;
int main(int argc, char const *argv[])
{
stu.w1.ip = 10;
return 0;
}
- 可以把成员变量当成普通变量运算
- 在数组中,数组之间是不能彼此赋值的,结构体变量可以相互赋值
共用体
概念:不同类型的成员变量共用同一块地址空间
定义格式
union 共用体名
{
成员变量1;
成员变量2;
}
共用体变量
定义格式
union 共用体名 变量名;
#include <stdio.h>
union val
{
int a;
char ch;
};
int main(int argc, char const *argv[])
{
union val v;
v.a = 10;
// 他俩不能同时出现,以最后一次赋值为准
v.ch = 'a';
printf("%d\n", v.a);
return 0;
}
特性
1) 共用体成员共用同一块地址空间
2) 赋值顺序以最后一次赋值为准
3) 共用体的大小为成员中类型最大的数据的大小
枚举
概念:用户自定义的数据类型,可以用于声明一组常数
定义格式
enum 枚举名
{
value1,
value2,
value3,
...
};
#include <stdio.h>
enum week
{
MON = 1,
TUE,
WED,
Thurs,
Fri,
Set,
Sum
};
int main(int argc, char const *argv[])
{
int day;
scanf("%d", &day);
switch (day)
{
case MON:
printf("这是周一的内容\n");
break;
case TUE:
printf("这是周二的内容\n");
break;
case WED:
printf("这是周三的内容\n");
break;
default:
break;
}
return 0;
}
未赋初值,第一个常数会默认为 0,后面常数依次加一(如果第一个值被设置为 1,则默认从 1 开始递增)
存储类型
auto static extern register
auto 自动型
修饰变量,一般省略的时候会认为是 auto 类型
static 静态型
修饰局部变量
1) 变量的存放位置在全局区(静态区) 如果静态变量有初值,存放在数据段,没有初始化存放在.bss 段
2) 生命周期为整个程序
3) 限制作用域:
修饰局部变量:和普通局部变量的作用域没有区别,但是生命周期被延长了
修饰全局变量:限制在本文件中使用
4) 只初始化一次,不手动赋值,初始值 0
#include <stdio.h>
void fun()
{
static int a = 0;
a++;
printf("%d\n", a);
}
int main(int argc, char const *argv[])
{
int b;
printf("%d\n", b);
fun(); // 1
fun(); // 2
return 0;
}
修饰函数
static 修饰函数,限制在本文件中使用
extern 外部引用
通过extern 可以引用其他文件中的全局变量或函数
//a.c
int a=10;
void fun()
{
printf("asd");
}
//extern.c
include<stdio.h>
extern int a;
extern void fun();
int main(int argc, char const *argv[])
{
fun();
printf("%d\n",a);//10
return 0;
}
代码示例
#include <stdio.h>
// 定义一个枚举类型,列出一周的天数
enum Weekday {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
};
// 定义一个共用体,用于存储整数或字符
union Value {
int i;
char c;
};
// 定义一个结构体,包含枚举类型、共用体和字符数组
struct Person {
enum Weekday day;
union Value value;
char name[50];
};
int main() {
// 创建一个结构体变量
struct Person person;
// 设置枚举值
person.day = Wednesday;
// 使用共用体的整数部分
person.value.i = 42;
// 设置名字
snprintf(person.name, sizeof(person.name), "John Doe");
// 打印结构体信息
printf("Name: %s\n", person.name);
printf("Day: %d\n", person.day);
printf("Integer value: %d\n", person.value.i);
// 修改共用体为字符部分,并打印
person.value.c = 'A';
printf("Character value: %c\n", person.value.c);
// 注意:由于共用体在同一时间只能存储一个值,打印整数部分将不再正确
// 这将打印未定义的值,因为共用体的内存位置现在用于存储字符
printf("Integer value after changing to character: %d\n", person.value.i);
return 0;
}