我制作了这个示例程序,它完全代表了我的问题。我正在尝试制作一个字符串列表,因为在编译时将存储在列表中的字符串总数未知,我正在使用 calloc/realloc在运行时分配堆上的大小。我使用函数初始化、修改和释放列表的原因是因为在我的原始程序中要创建 3 个动态列表,所有 3 个都是字符串数组。init_pathlist(),add_to_pathlist()和clear_pathlist()只是我在类似问题的堆栈溢出中找到的代码的包装器。
当它到达 memcmp(element, array[i], MAXSTRLEN) 时,我得到一个 SIGSEGV 错误,valgrind 告诉我 array[i] 是未映射的。为什么动态数组string_element无法正确初始化?注意:我尝试将"*string_element"替换为"**string_element",并将所有对函数的调用从"&string_element"更改为"string_element",结果相同。
我对内存管理相当陌生,非常感谢您的帮助。这是有问题的代码:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
size_t ARRSIZE = 1024;
size_t MAXSTRLEN = 1024;
void clear_list(char** array)
{
int i;
for(i = 0; i < ARRSIZE; i++)
free(array[i]);
free(array);
}
void init_list(char** marray)
{
int i;
char** array;
array = calloc(ARRSIZE , sizeof(char*));
for(i = 0; i < ARRSIZE; i++) {
array[i] = calloc(MAXSTRLEN +1, sizeof (char));
if (array[i] == NULL){
perror("calloc");
exit(1);
}
}
marray = array;
}
void add_to_list(char* element, char** array, int pos)
{
int i;
int NEWSIZE;
if(pos == ARRSIZE) {
NEWSIZE = (ARRSIZE + 2) * 2;
char **newptr = realloc(array, NEWSIZE * sizeof(*array));
if (newptr == NULL){
clear_list(array);
perror("realloc");
exit(1);
}
ARRSIZE = NEWSIZE;
array = newptr;
for (i = pos; i < ARRSIZE; i++) {
array[i] = calloc((MAXSTRLEN + 1) , sizeof (char));
if (array[i] == NULL){
perror("calloc");
exit(1);
}
}
}
strncpy(array[pos], element, MAXSTRLEN);
}
int testloop( char *element, char** array, int pos)
{
int i;
printf("Element to add: %sn", element);
for(i = 0; i < (pos -1); i++){
if (memcmp(element, array[i], MAXSTRLEN) == 0)
return 1;
}
add_to_list(element, array, pos);
return 0;
}
int main(void)
{
int loop_ret, position = 0;
char element[100];
char *string_element;
init_list(&string_element);
printf("Enter an element: n");
while(scanf("%s", element) != EOF) {
loop_ret = testloop(element, &string_element, position);
++position;
if (loop_ret == 0)
continue;
else if (loop_ret == 1) {
printf("%s match one of string_element entriesn", element);
exit(0);
}
}
clear_list(&string_element);
return 0;
}
下面是一个运行示例:
$ ./2d_char_array_funcparam
Enter an element:
bob
Element to add: bob
flo
Element to add: flo
Segmentation fault (core dumped)
以下是瓦尔格林德告诉我的:
$ valgrind --track-origins=yes ./2d_char_array_funcparam
==8944== Memcheck, a memory error detector
==8944== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==8944== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==8944== Command: ./2d_char_array_funcparam
==8944==
Enter an element:
bob
Element to add: bob
==8944== Use of uninitialised value of size 8
==8944== at 0x4C2E7BC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Uninitialised value was created by a stack allocation
==8944== at 0x400B39: main (2d_char_array_funcparam.c:77)
==8944==
==8944== Conditional jump or move depends on uninitialised value(s)
==8944== at 0x4C2E7DC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Uninitialised value was created by a stack allocation
==8944== at 0x400B39: main (2d_char_array_funcparam.c:77)
==8944==
==8944== Conditional jump or move depends on uninitialised value(s)
==8944== at 0x4C2E7F1: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Uninitialised value was created by a stack allocation
==8944== at 0x400B39: main (2d_char_array_funcparam.c:77)
==8944==
==8944== Use of uninitialised value of size 8
==8944== at 0x4C2E84C: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Uninitialised value was created by a stack allocation
==8944== at 0x400B39: main (2d_char_array_funcparam.c:77)
==8944==
==8944== Conditional jump or move depends on uninitialised value(s)
==8944== at 0x4C2E85B: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Uninitialised value was created by a stack allocation
==8944== at 0x400B39: main (2d_char_array_funcparam.c:77)
==8944==
robert
Element to add: robert
==8944== Invalid write of size 1
==8944== at 0x4C2E7BC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== Address 0x747265626f72 is not stack'd, malloc'd or (recently) free'd
==8944==
==8944==
==8944== Process terminating with default action of signal 11 (SIGSEGV)
==8944== Access not within mapped region at address 0x747265626F72
==8944== at 0x4C2E7BC: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8944== by 0x400A97: add_to_list (2d_char_array_funcparam.c:58)
==8944== by 0x400B2D: testloop (2d_char_array_funcparam.c:72)
==8944== by 0x400B90: main (2d_char_array_funcparam.c:86)
==8944== If you believe this happened as a result of a stack
==8944== overflow in your program's main thread (unlikely but
==8944== possible), you can try to increase the size of the
==8944== main thread stack using the --main-stacksize= flag.
==8944== The main thread stack size used in this run was 8388608.
==8944==
==8944== HEAP SUMMARY:
==8944== in use at exit: 1,057,792 bytes in 1,025 blocks
==8944== total heap usage: 1,025 allocs, 0 frees, 1,057,792 bytes allocated
==8944==
==8944== LEAK SUMMARY:
==8944== definitely lost: 8,192 bytes in 1 blocks
==8944== indirectly lost: 1,049,600 bytes in 1,024 blocks
==8944== possibly lost: 0 bytes in 0 blocks
==8944== still reachable: 0 bytes in 0 blocks
==8944== suppressed: 0 bytes in 0 blocks
==8944== Rerun with --leak-check=full to see details of leaked memory
==8944==
==8944== For counts of detected and suppressed errors, rerun with: -v
==8944== ERROR SUMMARY: 2049 errors from 6 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
谢谢你的时间!
Joachim Pileborg和M.M.都添加了正确的答案。
我将"*string_element"替换为"**string_element"(并相应地修改了函数调用),并将"void init_list"替换为"char** init_list",让它返回字符**数组,它有效!
非常感谢大家!