c - free() 导致段错误

标签 c

在这个程序中,有一个段错误。程序可以成功打印出“loop end”,在“loop end”后出现segmentation fault,说明read_name函数没有错误。但是我无法找出我的 free_memory 函数中的任何错误。谁能帮我弄清楚?谢谢。

输入文件:

9
Clinton, Hillary R.
Bonds, Bobby S.
Bonds, Barry L.
Clinton, William I.
Clinton, Chelsea T.
Bush, Laura M.
Bush, George W.
Bush, Jenna F.
Bush, Barbara G.

程序:

#include <stdio.h> 
#include <malloc.h>
#include<string.h>

void alloc(char ***surname, char ***first, char **mid_init, int num);
void read_names(FILE *inp, char **surname, char **first, char *mid_init, int num );
void free_memory(char **surname, char **first, char *mid_init, int num);

int main(int argc, char *argv[])
{
  int num = 0;
  char **surname, **first, *mid_init;
  FILE *inp = fopen(argv[1], "r");  
  FILE *outp = fopen(argv[2], "w");
  char array[79];

  fscanf(inp, "%d", &num);
  printf("%d\n", num);

  fgets(array, 79, inp);

  alloc(&surname, &first, &mid_init, num);
  read_names(inp, surname, first, mid_init, num);
  free_memory(surname, first, mid_init, num);

  fclose(inp);
  fclose(outp);

  return 0;
}

void alloc(char ***surname, char ***first, char **mid_init, int num)
{
  int i;

  *surname = (char**)malloc(num * sizeof(char*));
  *first = (char**)malloc(num * sizeof(char*));
  *mid_init = (char*)malloc(num * sizeof(char));

  for(i=0; i<num; i++)
  {
    (*surname)[i] = (char*)malloc(15*sizeof(char));
    (*first)[i] = (char*)malloc(10*sizeof(char));
  }
}

void read_names(FILE *inp, char **surname, char **first, char *mid_init, int num )
{
  char *token, array[79];
  char delim[6] = ", .\n";
  int i=0;

  fgets(array, 79, inp);
  printf("loop begins\n");

  for(i=0; i<num; i++)
  {
      fgets(array, 79, inp);
      printf("%s", array);

       token = strtok(array, delim);
    strcpy( (surname[i]), token);
    printf("%s   ", (surname[i]));

    token = strtok(NULL, delim);    
    strcpy( (first[i]), token);
    printf("%s  ", (first[i]));

    token = strtok(NULL, delim);
    *mid_init = token[0];
    printf("%s\n", mid_init);

    printf("\n\n");

  }
     printf("\nloop ends\n");
}

void free_memory(char **surname, char **first, char *mid_init, int num)
{
  int i;

  for(i=0;i<num;i++)
  {
    free((surname)[i]);
    free((first)[i]);
  }

  free(surname);
  free(first);
  free((mid_init));
}

最佳答案

首先,您将自己限制在 14 个字符的名字和 9 个字符的姓氏中,所以这将是我检查的第一事情,您的名字不再比这个。

如果是,您可能会在复制它们时破坏内存区域。

检查这一点的一种方法是在每次设置时简单地打印 token 的长度,例如:

token = strtok(array, delim);
printf ("DEBUG: token length is %d\n", strlen (token));

请记住,腐败不一定会立即甚至永远可见。在这种情况下,最有可能发生的情况是您覆盖了内存区域中的重要内联控制信息,例如内存块大小或指向另一个内存块的指针。

但是,当您写入内存时,没有代码主动检查它,因此它可能只有在您下次尝试进行内存分配或取消分配调用时才会被发现。

损坏后你的下一个调用是你的免费调用,而且几乎可以肯定它是在哪里找到的,因为竞技场已损坏。

最重要的是,超出已分配内存末尾的写入是未定义的行为。这意味着您不应该这样做。


如果事实证明你的名字不是太长(正如你在评论中所说),你需要问问自己为什么你有一个多余的fgets(array, 79, inp); 在你的代码中。我理解为什么在 main 中需要它以便在调用 fscanf 输入行数后移动到下一行。那个很好地完成了它的工作。

但是,您在 read_names 的开头有一个另一个,它有效地丢弃了列表中的第一个名字。这会导致问题,因为当您的代码认为文件中有 X 名称时,您已经丢弃了第一个名称,这意味着只有 X - 1 剩余。您可以看出这一点,因为当您开始打印名称时,文件中的第一个名称似乎丢失了。

如果您删除 read_names 开头的 fgets,您应该会发现它没问题。

As an aside, there's a couple of other changes I'd make to the code. First you really should check all those malloc calls in case one of them fails. That's the general rule for all functions that can fail when you rely later on them not having failed.

Second, I'm not really a big fan of ever multiplying by sizeof(char) - this is guaranteed by the standard to always be 1, so multiplying by it clogs up the code and makes it less readable.

关于c - free() 导致段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19946208/

相关文章:

c - 从 CSV 读取数据并放入数据库

c - TCP 流量控制错误

在c中创建按钮gtk数组

c - 结构的 Scanf 输入,C 中的位字段

c++ - 通过引用传递 3-Dim 固定长度数组

c - 如何在c中返回指向数组的指针

c - 如何使用结构体声明

c - 为什么 printf 在 macOS 上会破坏信号处理程序,但在 ubuntu 上却不会?

c - 从 C 程序连接 PostgreSql 需要哪些库?

c - 镜像 int 的值