【问题标题】:Using gdb--still can't find malloc error使用 gdb--仍然找不到 malloc 错误
【发布时间】:2018-05-13 22:28:23
【问题描述】:

我看过以前的帖子,但它们并没有帮助我找到我的问题......为了简短起见,我正在制作一个函数应该逐行读取文本文件(是的,我确实意识到有很多这样的帖子)。但是当我通过 CMD 运行我的程序时,它给了我这个错误:

Program received signal SIGSEGV, Segmentation fault.
__GI___libc_realloc (oldmem=0x10011, bytes=1) at malloc.c:2999
2999    malloc.c: No such file or directory.

漂亮确定我正确地写出了我的 malloc/realloc 行。我试过找到很多类似的帖子,但所提供的解决方案都没有帮助。如果您有任何我可能错过的帖子建议,请告诉我。无论如何,这是我的功能:

char* read_single_line(FILE* fp){
  char* line = NULL;
  int num_chars = 0;
  char c;
  fscanf(fp, "%c", &c);
  while(!feof(fp)) {
    num_chars++;
    line = (char*) realloc(line, num_chars * sizeof(char));
    line[num_chars -1] = c;
    if (c == '\n') {
      break;
    }
    fscanf(fp, "%c", &c);
  }
  if(line != NULL) {
    line = realloc(line, (num_chars+1) * sizeof(char));
    line[num_chars] = '\0';
  }
  return line;
}


void read_lines(FILE* fp, char*** lines, int* num_lines) {
  int i = 0;
  int num_lines_in_file = 0;
  char line[1000];
  if (fp == NULL) {
    *lines = NULL;
    *num_lines = 0;
  } else {
    (*lines) = (char**)malloc(1 * sizeof(char*));
    while (read_single_line(fp) != NULL) {
      (*lines)[i] = (char*)realloc((*lines)[i], sizeof(char));
      num_lines_in_file++;
      i++;
    }
    *lines[i] = line;
    *num_lines = num_lines_in_file;

  }
}

非常感谢任何帮助——我是 C 初学者,请听我说!

【问题讨论】:

  • malloc 中的分段错误通常是先前存储覆盖的结果,而不是因为传递给 malloc 的参数错误。请提供MVCE
  • 编译所有警告和调试信息:gcc -Wall -Wextra -gGCC。不仅可以使用gdb,还可以使用valgrind
  • 顺便说一句,你为什么不使用getline 而不是让你的(低效的)read_single_line
  • 通常在使用 gdb 调试崩溃时,查看 back trace 并遍历调用堆栈非常有用。

标签: c file gdb malloc realloc


【解决方案1】:
char line[1000];
:
while (read_single_line(fp) != NULL) {
:
}
*lines[i] = line;

这在我看来不太对劲。你的read_single_line 函数返回一个实际的行,但是除了对照NULL 检查它之外,你从来没有真正存储它在任何地方。相反,您将行指针指向line,这是一个自动作用域的变量,可以包含任何内容(更令人担忧的是,可能没有终止符)。

我认为您可能应该存储来自read_single_line 的返回值并使用它来设置您的行指针。


顺便说一句,一次扩展一个字符的缓冲区也可能效率很低。我建议最初分配更多字节,然后保留该容量和当前使用的字节。然后,只有当你即将使用超出你的能力时,你才会扩展,并且不止一个。在伪代码中,类似于:

def getLine:
    # Initial allocation with error check.

    capacity = 64
    inUse = 0
    buffer = allocate(capacity)
    if buffer == null:
        return null

    # Process each character made available somehow.

    while ch = getNextChar:
        # Expand buffer if needed, always have room for terminator.

        if inUse + 1 == capacity:
            capacity += 64
            newBuff = realloc buffer with capacity

            # Failure means we have to release old buffer.

            if newBuff == null:
                free buffer
                return null

        # Store character in buffer, we have enough room.

        buffer[inUse++] = ch

    # Store terminator, we'll always have room.

    buffer[inUse] = '\0';
    return buffer

您会注意到,以及更有效的重新分配,对所述分配进行更好的错误检查。

【讨论】:

    【解决方案2】:
    while (read_single_line(fp) != NULL) {
          (*lines)[i] = (char*)realloc((*lines)[i], sizeof(char));
          num_lines_in_file++;
          i++;
        }
        *lines[i] = line;
    

    这个短片段中的错误多于行。让我们一一来介绍。

     while (read_single_line(fp) != NULL) 
    

    你读了一行,检查它是否是一个空指针,然后把它扔掉,而不是把它放在一边,把它累积到lines数组中。

       (*lines)[i] = (char*)realloc((*lines)[i], sizeof(char));
    

    您正在尝试重新分配 (*lines[i])。首先,它不存在于i==0 之外,因为(*lines) 只被分配包含一个元素。其次,重新分配各个行是没有意义的,因为您(应该)从行读取功能中获得完美的现成行。你想重新分配*lines

    *lines = realloc (*lines, i * sizeof(char*));
    

    现在这两行

      num_lines_in_file++;
      i++;
    

    本身不是错误,但为什么有两个变量总是具有完全相同的值?此外,您希望它们(它)位于 realloc 行之前,按照通常的 increment-realloc-assign 模式(您在另一个函数中使用它)。

    说到分配部分,没有。您现在应该插入一个:

    (*lines)[i-1] = // what? 
    

    调用 read_single_line 时应该保存的行指针,就是这样。从头开始:

    char* cur_line;
    int i = 0;
    *lines = NULL;
    while ((cur_line=read_single_line(fp)) != NULL) 
    {
       ++i;
       *lines = realloc (*lines, i * sizeof(char*));
       (*lines)[i-1] = cur_line;
    }
    *num_lines = i;
    

    最后一个

       *lines[i] = line;
    

    真的很丑。

    首先,lines 不是一个数组,它是一个指向单个变量的指针,所以lines[i] 访问的是星际尘埃。其次,您试图为其分配一个局部变量的地址,一旦您的函数返回,该地址将不复存在。第三,它在循环之外做什么?如果你想用空指针终止你的线数组,这样做:

    } 
    *num_lines = i;
    ++i;
    *lines = realloc (*lines, i * sizeof(char*));
    (*lines)[i-1] = NULL;
    

    但鉴于您返回的行数,这可能没有必要。

    免责声明:以上均未经过测试。如果有任何错误,请修复它们!

    【讨论】:

      猜你喜欢
      • 2017-04-27
      • 1970-01-01
      • 2013-10-15
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 2012-03-09
      相关资源
      最近更新 更多