为什么char的realloc给出地址是alloc'd后的0字节

时间:2015-06-13 14:08:56

标签: c segmentation-fault realloc dynamic-allocation

我有以下代码:

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

int main(int argc, char *argv[])
{
  char* filename = "file_prefix.txt";
  FILE* file_prefix = fopen(filename, "r");

  char buff[1024];
  int i = 0;
  char** prefix = NULL;

  char c = fscanf(file_prefix, "%s", buff);
  while ( EOF != c )
  {
    printf("%d : %s\n", i, buff);
    char** temp  = realloc(prefix, sizeof(char*) * (i+1));
    temp[i] = malloc( (sizeof(char) * strlen(buff)) + 1);
    strcpy(temp[i], buff );
    prefix = temp;
    memset(buff, 0, sizeof(buff));
    c = fscanf(file_prefix, "%s", buff);
    ++i;
  } 

  int x = 0;
  for (;x < i; ++x) {
    printf("%s\n", prefix[i]);
  }
  free(prefix);

  fclose(file_prefix);
  return 0;
}

假设存在file_prefix.txt,我将使用valgrind获得以下内容:

==7322== Memcheck, a memory error detector
==7322== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7322== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==7322== Command: ./main
==7322== 
0 : pdf
1 : txt
==7322== Invalid read of size 8
==7322==    at 0x400A6D: main (main.c:29)
==7322==  Address 0x51fc370 is 0 bytes after a block of size 16 alloc'd
==7322==    at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7322==    by 0x400976: main (main.c:18)
==7322== 
==7322== Invalid read of size 1
==7322==    at 0x4C2E0E2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7322==    by 0x4EA6E3B: puts (ioputs.c:36)
==7322==    by 0x400A77: main (main.c:29)
==7322==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==7322== 
==7322== 
==7322== Process terminating with default action of signal 11 (SIGSEGV)
==7322==  Access not within mapped region at address 0x0
==7322==    at 0x4C2E0E2: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7322==    by 0x4EA6E3B: puts (ioputs.c:36)
==7322==    by 0x400A77: main (main.c:29)
==7322==  If you believe this happened as a result of a stack
==7322==  overflow in your program's main thread (unlikely but
==7322==  possible), you can try to increase the size of the
==7322==  main thread stack using the --main-stacksize= flag.
==7322==  The main thread stack size used in this run was 8388608.
==7322== 
==7322== HEAP SUMMARY:
==7322==     in use at exit: 592 bytes in 4 blocks
==7322==   total heap usage: 5 allocs, 1 frees, 600 bytes allocated
==7322== 
==7322== LEAK SUMMARY:
==7322==    definitely lost: 0 bytes in 0 blocks
==7322==    indirectly lost: 0 bytes in 0 blocks
==7322==      possibly lost: 0 bytes in 0 blocks
==7322==    still reachable: 592 bytes in 4 blocks
==7322==         suppressed: 0 bytes in 0 blocks
==7322== Reachable blocks (those to which a pointer was found) are not shown.
==7322== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==7322== 
==7322== For counts of detected and suppressed errors, rerun with: -v
==7322== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
[1]    7322 segmentation fault (core dumped)  valgrind --leak-check=full ./main

有什么问题:

char** temp  = realloc(prefix, sizeof(char*) * (i+1));

...

2 个答案:

答案 0 :(得分:4)

fscanf不返回EOF,它会返回分配的输入项数man fscanf)。为了您的目的,您需要检查

 while ( c == 1 )
   ...

然而,这本身并不会导致段错误!它是由于尝试打印prefix[i](重复)而导致的,该prefix[x]未设置为正确的值。您可能打算改为打印for (;x < i; ++x) { printf("%s\n", prefix[x]); }

<arg>

通过这两项更正,您的程序可以正常运行。

答案 1 :(得分:1)

  • fscanf返回int,因此您应该:

    int c = fscanf(file_prefix, "%s", buff);

    由于char是唯一可以signedunsigned的类型,具体取决于实现,因此您的代码实际上可能无法检测到EOF条件。如果scanf返回EOF(-1)并且已分配给unsigned char c,则会获得255. while(c!=EOF){...}循环中的条件始终为true

  • fscanf可以返回EOF(-1)或已处理元素的数量。在这种情况下,您希望处理一个字符串,因此您应该检查while循环:

    while ( c == 1 ) { ... }

  • 最后一个循环中有一个错误。

    int x = 0; for (;x < i; ++x) {printf("%s\n", prefix[x]);} // change i to x

在这些更改后,程序从文件中提取单词。