C语言数组操作出现double free错误及输出异常问题排查
C语言代码错误修复:double free与输出异常问题
功能要求
函数elabora接收长度为n的数组a,需根据参数k创建并返回新数组,同时将新数组长度存入*newn:
- 当
k>0时,新数组包含a中每个元素连续重复k次,例:a=[1 0 8 2]、k=3时返回[1 1 1 0 0 0 8 8 8 2 2 2] - 当
k=0时,新数组长度与a相同,元素全为0,例:a=[1 0 8 2]时返回[0 0 0 0] - 当
k<0时,新数组包含a中元素逆序后每个重复|k|次,例:a=[1 0 8 2]、k=-2时返回[2 2 8 8 0 0 1 1]
主函数需从命令行读取输入文件名和若干整数,读取文件中的整数存入数组,对每个命令行整数调用elabora,将返回数组元素输出到stdout,需关闭文件并释放所有内存。
现有代码
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <assert.h> #include <string.h> #include <errno.h> void termina(const char *messaggio); int *elabora(int a[], int n, int k, int *nuovon) { int c = 0; nuovon = malloc(n*sizeof(int)); if(nuovon==NULL) termina("Memoria insufficiente"); for(int i=0; i<n; i++) { if(k>0) { for(int j=0; j<k; j++) { nuovon[c]=a[j]; c++; } } else if(k==0) { nuovon[c] = 0; c++; } else { for(int j=k-1; j>=0; j--) { nuovon[c]=a[j]; c++; } } } *nuovon = n*k; return nuovon; } int main(int argc, char *argv[]) { if(argc<2) { fprintf(stderr, "Uso: %s i1 [i2 i3 ...]\n", argv[0]); exit(1); } int n = 10; int *nuovon = NULL; int k = atoi(argv[2]); int i; int *a = malloc(n*sizeof(int)); if(a==NULL) termina("Memoria insufficiente"); // lettura file FILE *f = fopen(argv[1], "r"); if(f==NULL) termina("Impossibile aprire il file di inpt"); // lettura interi int e = fscanf(f, "%d", &n); if(e!=1) { termina("Non ci sono interi nel file"); fprintf(stderr, "Errore di lettura nella riga %d\n", i); } //chiusura file fclose(f); for(int i=2; i<argc; i++) { nuovon = elabora(a, n, k, nuovon); for(int j=0; j<n*k; j++) { fprintf(stdout, "%d", nuovon[j]); } } free(nuovon); free(a); return 0; } void termina(const char *messaggio){ if(errno!=0) perror(messaggio); else fprintf(stderr,"%s\n", messaggio); exit(1); }
问题现象
运行程序时出现错误:double free detected in tcache 2;执行命令main test1 2 0 5 1时,输出仅为随机值,无编译警告。
错误分析与修复步骤
1. elabora函数核心逻辑错误
原函数完全混淆了返回数组和**输出参数nuovon**的作用:
- 错误地给
nuovon参数分配内存,实际上nuovon是用来传递新数组长度的指针,返回值才是要创建的新数组。 - 元素赋值逻辑错误:
k>0时,循环中错误使用a[j],应该重复当前元素a[i]。k<0时,循环范围完全错误,应该先逆序遍历原数组,再重复每个元素|k|次。
- 新数组长度计算错误:
k=0时长度应为n,k<0时长度是n*(-k),原代码直接用n*k会得到负数,导致后续循环越界。
2. 主函数的问题
- 未读取文件中的整数到数组
a:原代码只读取了n的值,没有读取后续的n个整数,导致a中是随机值。 - 未根据读取的
n调整数组a的大小:一开始malloc了10个元素的空间,若文件中n不等于10会导致越界或浪费。 - 循环中固定使用
argv[2]的k值,没有遍历每个命令行参数转换为k。 - 未释放每次调用
elabora返回的旧数组,导致内存泄漏,同时原elabora的错误逻辑引发double free。
修复后的完整代码
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <errno.h> void termina(const char *messaggio); int *elabora(int a[], int n, int k, int *nuovon) { int *new_arr; int repeat = k > 0 ? k : -k; // 计算新数组长度 if (k == 0) { *nuovon = n; } else { *nuovon = n * repeat; } // 分配新数组内存 new_arr = malloc(*nuovon * sizeof(int)); if (new_arr == NULL) { termina("Memoria insufficiente"); } int c = 0; if (k > 0) { // 正序重复每个元素k次 for (int i = 0; i < n; i++) { for (int j = 0; j < k; j++) { new_arr[c++] = a[i]; } } } else if (k == 0) { // 填充全0 for (int i = 0; i < n; i++) { new_arr[c++] = 0; } } else { // 逆序后每个元素重复|k|次 for (int i = n - 1; i >= 0; i--) { for (int j = 0; j < repeat; j++) { new_arr[c++] = a[i]; } } } return new_arr; } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Uso: %s <file_input> <k1> [k2 k3 ...]\n", argv[0]); exit(1); } int n; int *a = NULL; // 打开文件 FILE *f = fopen(argv[1], "r"); if (f == NULL) { termina("Impossibile aprire il file di input"); } // 读取数组长度n if (fscanf(f, "%d", &n) != 1) { termina("Non ci sono interi nel file"); } // 分配数组a的内存 a = malloc(n * sizeof(int)); if (a == NULL) { termina("Memoria insufficiente"); } // 读取n个整数到数组a for (int i = 0; i < n; i++) { if (fscanf(f, "%d", &a[i]) != 1) { fprintf(stderr, "Errore di lettura dell'elemento %d\n", i+1); fclose(f); free(a); exit(1); } } fclose(f); // 遍历每个命令行参数中的k值 for (int i = 2; i < argc; i++) { int k = atoi(argv[i]); int new_len; int *result = elabora(a, n, k, &new_len); // 输出结果数组 for (int j = 0; j < new_len; j++) { fprintf(stdout, "%d ", result[j]); } fprintf(stdout, "\n"); // 释放当前结果数组的内存 free(result); } // 释放原数组内存 free(a); return 0; } void termina(const char *messaggio) { if (errno != 0) { perror(messaggio); } else { fprintf(stderr, "%s\n", messaggio); } exit(1); }
修复说明
elabora函数修正:- 明确
nuovon是输出参数,用来传递新数组的长度,返回值为新分配的结果数组。 - 正确计算不同
k值对应的新数组长度。 - 修复元素赋值逻辑:正序重复当前元素、逆序遍历原数组后重复元素、k=0时填充全0。
- 明确
- 主函数修正:
- 读取文件中的
n后,分配对应大小的数组a。 - 读取文件中的
n个整数到数组a,确保数据正确。 - 遍历每个命令行参数转换为
k,每次调用elabora后释放结果数组,避免内存泄漏。 - 修正命令行提示信息,明确参数格式。
- 读取文件中的
内容的提问来源于stack exchange,提问作者user22770145
相关产品推荐
相关产品推荐

