You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}

修复说明

  1. elabora函数修正:
    • 明确nuovon是输出参数,用来传递新数组的长度,返回值为新分配的结果数组。
    • 正确计算不同k值对应的新数组长度。
    • 修复元素赋值逻辑:正序重复当前元素、逆序遍历原数组后重复元素、k=0时填充全0。
  2. 主函数修正:
    • 读取文件中的n后,分配对应大小的数组a。
    • 读取文件中的n个整数到数组a,确保数据正确。
    • 遍历每个命令行参数转换为k,每次调用elabora后释放结果数组,避免内存泄漏。
    • 修正命令行提示信息,明确参数格式。

内容的提问来源于stack exchange,提问作者user22770145

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:25:06