为什么 Valgrind 在错误的地方给我错误?
Why is Valgrind giving me errors in the wrong place?
我正在修复以下 C 程序中的三个错误。前两个给出并保证是正确的。第三个是我最后写的,与我的问题无关。最后三个是问题所在,每个都有一个错误。
这是我的程序:
/* is correct*/
Node *create_list(int arr[], int size) {
Node *n, *list= NULL;
if (arr != NULL && size != 0)
while (size-- > 0) {
n= malloc(sizeof(*n));
if (n == NULL)
return NULL; /* we just return NULL if memory allocation fails */
else {
n->value= arr[size];
n->next= list;
list= n;
}
}
return list;
}
/* is correct*/
void list_to_string(Node *list, char result[]) {
char temp[MAX_LEN + 1];
strcpy(result, ""); /* clear out any existing contents */
while (list != NULL) {
sprintf(temp, "%d", list->value);
if (strlen(result) + strlen(temp) + 1 < MAX_LEN) {
strcat(result, temp);
/* add a space if it's not the last element */
if (list->next != NULL)
strcat(result, " ");
}
list= list->next;
}
}
/*****************************************************************************/
/* functions below this have something wrong with them */
/*****************************************************************************/
/* this function's parameter is a pointer to the head node of a list; it
* should release all of the memory of the list, and set the head pointer
* (meaning the pointer that its parameter points to) to NULL. (Empty for now).
*/
void clear(Node **list) {
}
/* should return the sum of the values in the even-numbered positions of a
* list (the value in the second node, the fourth node, etc.), but has a bug
* (the first node is considered to be position #1, in other words, the list
* has no position zero)
*/
int sum_even(Node *list) {
Node *ptr= list->next;
int sum= 0;
if (list != NULL){
while (ptr != NULL) {
sum += ptr->value;
ptr= ptr->next->next;
}
}
return sum;
}
/* should remove the last element from a list, returning 1 upon success or 0
* if start is NULL, but has a bug
*/
int remove_last(Node **start) {
Node *prev= NULL, *travel;
int result= 0;
if (start != NULL) {
result= 1;
travel= *start;
while (travel != NULL && travel->next != NULL) {
prev= travel;
travel= travel->next;
}
if (prev != NULL) {
free(prev->next);
prev->next= NULL;
}
}
return result;
}
/* should remove the first element from a list, returning 1 upon success or
* 0 if the list is empty or start is NULL, but has a bug
*/
int remove_first(Node **start) {
Node **temp= NULL;
int result= 0;
if (start != NULL && *start != NULL) {
result= 1;
temp= start;
*start= (*start)->next;
free(temp);
}
return result;
}
我的主要测试功能:
int main(void) {
int arr[]= {10, 20, 30, 40, 50, 60, 70};
Node *list= NULL;
char elements[MAX_LEN + 1];
list= create_list(arr, sizeof(arr) / sizeof(arr[0]));
/* test sum_even() */
assert(sum_even(list) == 120);
/* test remove_last() */
remove_last(&list);
list_to_string(list, elements);
assert(strcmp(elements, "10 20 30 40 50 60") == 0);
printf("Score!\n"); /* both assertions passed */
/* if your clear() function works, this program should not have any memory
leaks, and list should be NULL afterwards */
clear(&list);
return 0;
}
我知道 'clear()' 是空的,但这是我将在最后写的函数。我感到困惑的是,当我 运行 valgrind 时:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes my_program.x
我收到这条消息:
==25457== Memcheck, a memory error detector
==25457== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==25457== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==25457== Command: public1.x
==25457==
Score!
==25457==
==25457== FILE DESCRIPTORS: 3 open at exit.
==25457== Open file descriptor 2: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457== Open file descriptor 1: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457== Open file descriptor 0: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457==
==25457== HEAP SUMMARY:
==25457== in use at exit: 96 bytes in 6 blocks
==25457== total heap usage: 7 allocs, 1 frees, 112 bytes allocated
==25457==
==25457== 80 bytes in 5 blocks are indirectly lost in loss record 1 of 2
==25457== at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457== by 0x40077F: create_list (broken-lists.c:16)
==25457== by 0x400698: main (public1.c:14)
==25457==
==25457== 96 (16 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==25457== at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457== by 0x40077F: create_list (broken-lists.c:16)
==25457== by 0x400698: main (public1.c:14)
==25457==
==25457== LEAK SUMMARY:
==25457== definitely lost: 16 bytes in 1 blocks
==25457== indirectly lost: 80 bytes in 5 blocks
==25457== possibly lost: 0 bytes in 0 blocks
==25457== still reachable: 0 bytes in 0 blocks
==25457== suppressed: 0 bytes in 0 blocks
==25457==
==25457== For counts of detected and suppressed errors, rerun with: -v
==25457== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
这清楚地表明对 create_list() 的函数调用存在问题。既然我知道 create_list() 是正确的,而 remove_last() 有问题,为什么它告诉我 create_list() 有问题?
我目前正在尝试学习 Valgrind,所以如果这个问题对你们中的一些人来说很明显,请原谅。
create_list
在循环中调用 malloc
。如果循环内的 malloc
前 N 次正常但 N+1 次失败,则您 return NULL
从而从前 N 个 mallocs 泄漏内存。所以这显然是 create_list
中的错误,我希望 valgrind
报告。
你需要这样的东西:
if (n == NULL)
{
clear(&list);
return NULL; /* we just return NULL if memory allocation fails */
}
除此之外,我不确定在实现 clear
函数之前 运行 valgrind
是否有意义。 valgrind
如何知道您打算释放尚未编写的函数中的内存?
我发现了问题所在。
事实证明,需要在 main 存在之前调用 clear() ,否则列表将包含未释放的内存。
起初我认为不是这样的,因为三个函数中的错误。 sum_even() 和 remove_last() 中的错误不适用于 main() 中生成的特定列表。所以对于这个运行,没有任何问题。
我正在修复以下 C 程序中的三个错误。前两个给出并保证是正确的。第三个是我最后写的,与我的问题无关。最后三个是问题所在,每个都有一个错误。
这是我的程序:
/* is correct*/
Node *create_list(int arr[], int size) {
Node *n, *list= NULL;
if (arr != NULL && size != 0)
while (size-- > 0) {
n= malloc(sizeof(*n));
if (n == NULL)
return NULL; /* we just return NULL if memory allocation fails */
else {
n->value= arr[size];
n->next= list;
list= n;
}
}
return list;
}
/* is correct*/
void list_to_string(Node *list, char result[]) {
char temp[MAX_LEN + 1];
strcpy(result, ""); /* clear out any existing contents */
while (list != NULL) {
sprintf(temp, "%d", list->value);
if (strlen(result) + strlen(temp) + 1 < MAX_LEN) {
strcat(result, temp);
/* add a space if it's not the last element */
if (list->next != NULL)
strcat(result, " ");
}
list= list->next;
}
}
/*****************************************************************************/
/* functions below this have something wrong with them */
/*****************************************************************************/
/* this function's parameter is a pointer to the head node of a list; it
* should release all of the memory of the list, and set the head pointer
* (meaning the pointer that its parameter points to) to NULL. (Empty for now).
*/
void clear(Node **list) {
}
/* should return the sum of the values in the even-numbered positions of a
* list (the value in the second node, the fourth node, etc.), but has a bug
* (the first node is considered to be position #1, in other words, the list
* has no position zero)
*/
int sum_even(Node *list) {
Node *ptr= list->next;
int sum= 0;
if (list != NULL){
while (ptr != NULL) {
sum += ptr->value;
ptr= ptr->next->next;
}
}
return sum;
}
/* should remove the last element from a list, returning 1 upon success or 0
* if start is NULL, but has a bug
*/
int remove_last(Node **start) {
Node *prev= NULL, *travel;
int result= 0;
if (start != NULL) {
result= 1;
travel= *start;
while (travel != NULL && travel->next != NULL) {
prev= travel;
travel= travel->next;
}
if (prev != NULL) {
free(prev->next);
prev->next= NULL;
}
}
return result;
}
/* should remove the first element from a list, returning 1 upon success or
* 0 if the list is empty or start is NULL, but has a bug
*/
int remove_first(Node **start) {
Node **temp= NULL;
int result= 0;
if (start != NULL && *start != NULL) {
result= 1;
temp= start;
*start= (*start)->next;
free(temp);
}
return result;
}
我的主要测试功能:
int main(void) {
int arr[]= {10, 20, 30, 40, 50, 60, 70};
Node *list= NULL;
char elements[MAX_LEN + 1];
list= create_list(arr, sizeof(arr) / sizeof(arr[0]));
/* test sum_even() */
assert(sum_even(list) == 120);
/* test remove_last() */
remove_last(&list);
list_to_string(list, elements);
assert(strcmp(elements, "10 20 30 40 50 60") == 0);
printf("Score!\n"); /* both assertions passed */
/* if your clear() function works, this program should not have any memory
leaks, and list should be NULL afterwards */
clear(&list);
return 0;
}
我知道 'clear()' 是空的,但这是我将在最后写的函数。我感到困惑的是,当我 运行 valgrind 时:
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --track-fds=yes my_program.x
我收到这条消息:
==25457== Memcheck, a memory error detector
==25457== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==25457== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==25457== Command: public1.x
==25457==
Score!
==25457==
==25457== FILE DESCRIPTORS: 3 open at exit.
==25457== Open file descriptor 2: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457== Open file descriptor 1: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457== Open file descriptor 0: /dev/pts/11
==25457== <inherited from parent>
==25457==
==25457==
==25457== HEAP SUMMARY:
==25457== in use at exit: 96 bytes in 6 blocks
==25457== total heap usage: 7 allocs, 1 frees, 112 bytes allocated
==25457==
==25457== 80 bytes in 5 blocks are indirectly lost in loss record 1 of 2
==25457== at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457== by 0x40077F: create_list (broken-lists.c:16)
==25457== by 0x400698: main (public1.c:14)
==25457==
==25457== 96 (16 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==25457== at 0x4C28A2E: malloc (vg_replace_malloc.c:270)
==25457== by 0x40077F: create_list (broken-lists.c:16)
==25457== by 0x400698: main (public1.c:14)
==25457==
==25457== LEAK SUMMARY:
==25457== definitely lost: 16 bytes in 1 blocks
==25457== indirectly lost: 80 bytes in 5 blocks
==25457== possibly lost: 0 bytes in 0 blocks
==25457== still reachable: 0 bytes in 0 blocks
==25457== suppressed: 0 bytes in 0 blocks
==25457==
==25457== For counts of detected and suppressed errors, rerun with: -v
==25457== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6)
这清楚地表明对 create_list() 的函数调用存在问题。既然我知道 create_list() 是正确的,而 remove_last() 有问题,为什么它告诉我 create_list() 有问题?
我目前正在尝试学习 Valgrind,所以如果这个问题对你们中的一些人来说很明显,请原谅。
create_list
在循环中调用 malloc
。如果循环内的 malloc
前 N 次正常但 N+1 次失败,则您 return NULL
从而从前 N 个 mallocs 泄漏内存。所以这显然是 create_list
中的错误,我希望 valgrind
报告。
你需要这样的东西:
if (n == NULL)
{
clear(&list);
return NULL; /* we just return NULL if memory allocation fails */
}
除此之外,我不确定在实现 clear
函数之前 运行 valgrind
是否有意义。 valgrind
如何知道您打算释放尚未编写的函数中的内存?
我发现了问题所在。 事实证明,需要在 main 存在之前调用 clear() ,否则列表将包含未释放的内存。 起初我认为不是这样的,因为三个函数中的错误。 sum_even() 和 remove_last() 中的错误不适用于 main() 中生成的特定列表。所以对于这个运行,没有任何问题。