为什么 char** 的 realloc 在分配后给出地址为 0 字节
Why realloc of char** gives Address is 0 bytes after alloc'd
我有以下代码:
#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));
??
fscanf
不是 return EOF
,它 return 是 分配的输入项数 (man fscanf
).为了您的目的,您需要检查
while ( c == 1 )
...
然而,这本身并不会导致段错误!这是由于尝试打印 prefix[i]
(重复)而未设置为正确值引起的。您可能打算改为打印 prefix[x]
:
for (;x < i; ++x) {
printf("%s\n", prefix[x]);
}
通过这两个更正,您的程序运行没有错误。
fscanf
returns int
所以你应该有:
int c = fscanf(file_prefix, "%s", buff);
由于 char
是唯一可以是 signed
或 unsigned
的类型,具体取决于实现,您的代码实际上可能无法检测到 EOF
条件。如果 scanf
returns EOF(-1)
并且它被分配给 unsigned char c
你将得到 255。while(c!=EOF){...}
循环中的条件将始终是 true
.
fscanf
可以 return EOF(-1)
或处理元素的数量。在这种情况下,您希望处理一个字符串,因此您应该检查 while
循环:
while ( c == 1 ) { ... }
最后一个循环有错误。
int x = 0; for (;x < i; ++x) {printf("%s\n", prefix[x]);} // change i to x
进行这些更改后,程序会从文件中提取单词。
我有以下代码:
#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));
??
fscanf
不是 return EOF
,它 return 是 分配的输入项数 (man fscanf
).为了您的目的,您需要检查
while ( c == 1 )
...
然而,这本身并不会导致段错误!这是由于尝试打印 prefix[i]
(重复)而未设置为正确值引起的。您可能打算改为打印 prefix[x]
:
for (;x < i; ++x) {
printf("%s\n", prefix[x]);
}
通过这两个更正,您的程序运行没有错误。
fscanf
returnsint
所以你应该有:int c = fscanf(file_prefix, "%s", buff);
由于
char
是唯一可以是signed
或unsigned
的类型,具体取决于实现,您的代码实际上可能无法检测到EOF
条件。如果scanf
returnsEOF(-1)
并且它被分配给unsigned char c
你将得到 255。while(c!=EOF){...}
循环中的条件将始终是true
.fscanf
可以 returnEOF(-1)
或处理元素的数量。在这种情况下,您希望处理一个字符串,因此您应该检查while
循环:while ( c == 1 ) { ... }
最后一个循环有错误。
int x = 0; for (;x < i; ++x) {printf("%s\n", prefix[x]);} // change i to x
进行这些更改后,程序会从文件中提取单词。