本教程视频已同步到B站: 程序员的C——实用编程,不玩虚的!
语法补充
共用体
结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。结构体占用的内存大于等于所有成员占用的内存的总和(内存对齐),共用体占用的内存等于最长的成员占用的内存。共用体使用内存覆盖技术,同一时刻只能保存一个成员的值,如果对其他成员赋值,就会覆盖掉原来成员的值。
union data{
int n;
char c;
short s;
};
// 在结构体中声明
struct person{
char name[20];
char sex;
short age;
union{
float score;
char course[20];
} sc;
};
变长数组和柔性数组
在C99之前,数组的长度必须是整数或者常量表达式, 而C99则做了改进,允许数组长度是变量。这种数组称为变长数组(variable-length array)。
int len = 10;
char str[len];
变长数组需要注意一点,不能在声明的同时初始化。譬如:char str[len] = {0};
编译报错。可以使用memset(str, '\0', len);
来做零值初始化。
柔性数组(Flexible Array)也是C99引入的一个新特性。它允许你在定义结构体的最后一个元素时,声明一个长度为0的数组,而这个数组的大小可以在程序运行的过程中动态设定。
typedef struct {
int len;
int array[0]; //可省略0,写作:int array[]
} MyArray;
柔性数组小结:
- 结构体中的最后一个元素允许是未知大小的数组,称为柔性数组成员
- 结构体中的柔性数组成员前面必须至少包含一个其他成员
sizeof
返回的此结构体大小时不包括柔性数组内存(即柔性数组不占用结构体内存)
思考:结构体中的柔性数组和指针有什么区别?为什么使用柔性数组?
// 定长缓冲区
struct Buffer {
int len;
char data[MAX_LEN];
};
由于缓冲区的大小是在编译时无法确定的,为了能适应各种场景,只能把缓冲区大小定得尽可能大,但也不能太大,这种情形下,往往存在浪费内存的问题。
有一种解决办法,就是把结构体中数组字段换成指针:
struct Buffer {
int len;
char *data;
};
但是这样一来,就需要对结构体进行两次动态内存分配:
buf = (struct Buffer *)malloc(sizeof(struct Buffer));
if(buf != NULL){
buf->data = (char *)malloc(sizeof(char) * need_length))
}
并且这两次动态分配的内存是不连续的,导致的问题就是需要对结构体和数据字段分别进行内存管理(申请和释放)。
想要完美解决这个问题,柔性数组就出场了!
// 使用柔性数组
struct Buffer {
int len;
char data[];
};
// 为带有柔性数组成员的结构体动态分配内存
buf = (struct Buffer *)malloc(sizeof(struct Buffer) + sizeof(char) * need_length);
总的来说,柔性数组比指针的优势在于:
- 更方便管理内存,且减少一次内存分配,提升性能。
- 减少内存碎片化。因为结构体的柔性数组和结构体成员的地址是连续的,即可一同申请内存。
goto 语句
goto 语句是一种无条件流程跳转语句,通常 goto 语句与 if 语句结合使用,当满足一定条件时,程序流程跳转到指定标签处。
// 使用goto语句实现循环
int main(){
printf("main... \n");
int i = 0;
start:
printf("gogogo...\n");
i++;
if (i<100){
goto start;
}
printf("end... \n");
return 0;
}
定义标签的语法格式:
标签: 语句;
关注公众号:编程之路从0到1