C语言struct中char数组长度≥30时调用add函数后程序崩溃如何解决
问题产生原因
- 核心根源是栈上可变长度数组(VLA)越界访问:你在main函数中定义的
struct Data emp[n]是长度固定为n的栈上数组,仅能容纳n个员工数据。但add函数中直接将n加5后,向emp[n]到emp[n+4]的非法地址写入数据,属于未定义行为。- 当结构体char数组长度为20及以下时,结构体整体占用空间小,越界写入的内容暂时没有覆盖栈上的函数返回地址、栈帧基址等关键内存,所以程序看起来可以正常运行;
- 当结构体char数组长度大于等于30时,结构体整体占用空间变大,越界写入的内容直接破坏了栈上的关键数据,导致
add函数执行完循环准备返回/调用display时触发内存访问错误,程序直接崩溃。
- 额外存在两个风险代码:
fflush(stdin)是C标准未定义行为,仅部分编译器支持该用法,无法保证跨平台正常清理输入缓冲区;gets函数已经被C标准完全废弃,该函数不检查输入长度,极易触发缓冲区溢出。
修复方案
- 替换栈上VLA为动态分配内存:使用
malloc初始化员工数组,需要新增数据时用realloc扩容,从根本上解决数组越界问题。 - 替换风险函数:删掉
fflush(stdin),改用fgets替代gets读取字符串,输入后手动清理缓冲区残留的换行符。 - 调整add函数逻辑:需要将扩容后的数组地址和新的长度返回给主调函数。
关键修改代码示例
主函数初始化部分修改:
int main(void) { int n; int a; printf("enter the number of employees:\n"); scanf("%d", &n); // 改用动态内存分配 struct Data *emp = malloc(n * sizeof(struct Data)); if(emp == NULL) { printf("内存分配失败\n"); return 1; } input(emp, n); printf("enter the operation you want to perform:\n"); printf("1 - to find employee record from employee id\n"); printf("2 - to sort employee record on basis of employee id\n"); printf("3 - to alphabetically sort array of characters\n"); printf("4 - to count the number of employees in database\n"); printf("5 - to add 5 more records\n"); scanf("%d", &a); switch (a) { case 1: find(emp, n); break; case 2: sortid(emp, n); display(emp, n); break; case 3: sortAlp(emp, n); display(emp, n); break; case 4: count(emp, n); break; case 5: // 接收add返回的新地址,n传指针修改原值 emp = add(emp, &n); break; } // 最后释放内存 free(emp); return 0; }
add函数修改:
struct Data* add(struct Data *emp, int *n) { // 扩容数组 *n += 5; struct Data *temp = realloc(emp, (*n) * sizeof(struct Data)); if(temp == NULL) { printf("扩容失败\n"); return emp; } emp = temp; for (int i = *n - 5; i < *n; i++) { printf("enter employee id of %d employee: \n", i + 1); scanf("%d", &emp[i].Emp_id); // 清理输入缓冲区残留换行 while(getchar() != '\n'); printf("enter employee name of %d employee: \n", i + 1); fgets(emp[i].Emp_name, sizeof(emp[i].Emp_name), stdin); // 去掉fgets读取的末尾换行 emp[i].Emp_name[strcspn(emp[i].Emp_name, "\n")] = '\0'; printf("enter employee city of %d employee: \n", i + 1); fgets(emp[i].Emp_city, sizeof(emp[i].Emp_city), stdin); emp[i].Emp_city[strcspn(emp[i].Emp_city, "\n")] = '\0'; } display(emp, *n); return emp; }
其他修改:
同步将input函数中的gets和fflush(stdin)也按照上面的方式替换即可。
内容的提问来源于stack exchange,提问作者SWAPNIL SRIVASTAVA
相关产品推荐
相关产品推荐

