尝试 malloc 时具有特定输出的 Valgrind 泄漏和分段错误
Valgrind leak and Segmentation Error with a specific output when trying to malloc
所以我有一个程序接收格式为 a word1 word2 word3
的字符串作为输入,并将这些词插入到一个结构中,该结构最终进入链表。对于我已经尝试过的所有输入,它运行完美,没有内存泄漏,但是对于这个特定的输出,我得到了 Segmentation Error
以及内存泄漏,这几乎可以肯定是因为 word1
的长度。
这是输入:
a
Adolph_Blaine_Charles_David_Earl_Frederick_Gerald_Hubert_Irvin_John_Kenneth_Lloyd_Martin_Nero_Oliver_Paul_Quincy_Randolph_Sherman_Thomas_Uncas_Victor_William_Xerxes_Yancy_Zeus_Wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflegeundsorgfaltigkeitbeschutzenvorangreifendurchihrraubgierigfeindewelchevoralternzwolfhunderttausendjahresvorandieerscheinenvonderersteerdemenschderraumschiffgenachtmittungsteinundsiebeniridiumelektrischmotorsgebrauchlichtalsseinursprungvonkraftgestartseinlangefahrthinzwischensternartigraumaufdersuchennachbarschaftdersternwelchegehabtbewohnbarplanetenkreisedrehensichundwohinderneuerassevonverstandigmenschlichkeitkonntefortpflanzenundsicherfreuenanlebenslanglichfreudeundruhemitnichteinfurchtvorangreifenvorandererintelligentgeschopfsvonhinzwischensternartigraum foo@bar.zp 2
这是我的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXINPUT 682
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link;
link head;
void add(char c[]) {
words x;
char *str;
link temp = (link)malloc(sizeof(node));
strtok(c, " ");
str = strtok(NULL, " ");
x.word1 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word1, str);
str = strtok(NULL, " ");
x.word2 = (char *)malloc(sizeof(char) * (strlen(str) + 1)); /* where the error happens with this input */
strcpy(x.word2, str);
str = strtok(NULL, "[=10=]");
x.word3 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word3, str);
temp->cont = x;
temp->next = head;
head = temp;
}
int main() {
char input[MAXINPUT] = " ";
head = NULL;
while (input[0] != 'x') {
fgets(input, MAXINPUT, stdin);
input[strcspn(input, "\r\n")] = 0;
if (input[0] == 'a')
add(input);
...
当我 运行 使用此代码输入时,我得到一个 Segmentation Error
并且 valgrind 说有 3 个分配,只有一个空闲,并且 leak\error 发生在行中代码中提到,专门用了strlen。它还说我出于某种原因无法访问内存位置 0x0。我想知道为什么会这样,谢谢!
您不测试 strtok
是否找到了所有标记。在使用之前,您必须检查由 strtok()
编辑的指针 return。如果不这样做,无效输入将导致未定义的行为。
在您的情况下,输入超过 682 个字节,前 681 个字节被读入数组并且此片段不包含足够的标记,因此 strtok()
调用之一 return NULL
,当您使用 strlen()
.
取消引用此空指针时导致未定义的行为
始终测试并报告错误情况,您将为自己节省无数小时的调试时间。
当程序崩溃时,valgrind 报告的内存泄漏是没有意义的,因为程序没有完成正常执行,当然也没有正确释放分配的内存。程序退出后内存仍然returned到操作系统,但是valgrind通过调用free()
.
报告尚未释放的块
为避免对行长度设置任意限制,您可以使用 POSIX standard function getline()
根据需要重新分配数组。
您还应该使用 strdup
在单个函数调用中分配字符串的副本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link; // hiding pointers behind typedefs is not recommended
link head;
link add(char c[]) {
words x = { NULL, NULL, NULL };
char *str;
link temp;
if (strtok(c, " ") != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word1 = strdup(str)) != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word2 = strdup(str)) != NULL
&& (str = strtok(NULL, "")) != NULL
&& (x.word3 = strdup(str)) != NULL
&& (temp = malloc(sizeof(*temp)) != NULL) {
temp->cont = x;
temp->next = head;
return head = temp;
} else {
free(x.word3);
free(x.word2);
free(x.word1);
return NULL;
}
}
int main() {
char *input = NULL;
size_t input_size = 0;
head = NULL;
while (getline(&input, &input_size, stdin) >= 0 && *input != 'x') {
input[strcspn(input, "\r\n")] = '[=10=]';
if (*input == 'a')
add(input);
...
}
...
}
free(input);
...
return 0;
}
所以我有一个程序接收格式为 a word1 word2 word3
的字符串作为输入,并将这些词插入到一个结构中,该结构最终进入链表。对于我已经尝试过的所有输入,它运行完美,没有内存泄漏,但是对于这个特定的输出,我得到了 Segmentation Error
以及内存泄漏,这几乎可以肯定是因为 word1
的长度。
这是输入:
a
Adolph_Blaine_Charles_David_Earl_Frederick_Gerald_Hubert_Irvin_John_Kenneth_Lloyd_Martin_Nero_Oliver_Paul_Quincy_Randolph_Sherman_Thomas_Uncas_Victor_William_Xerxes_Yancy_Zeus_Wolfeschlegelsteinhausenbergerdorffwelchevoralternwarengewissenhaftschaferswessenschafewarenwohlgepflegeundsorgfaltigkeitbeschutzenvorangreifendurchihrraubgierigfeindewelchevoralternzwolfhunderttausendjahresvorandieerscheinenvonderersteerdemenschderraumschiffgenachtmittungsteinundsiebeniridiumelektrischmotorsgebrauchlichtalsseinursprungvonkraftgestartseinlangefahrthinzwischensternartigraumaufdersuchennachbarschaftdersternwelchegehabtbewohnbarplanetenkreisedrehensichundwohinderneuerassevonverstandigmenschlichkeitkonntefortpflanzenundsicherfreuenanlebenslanglichfreudeundruhemitnichteinfurchtvorangreifenvorandererintelligentgeschopfsvonhinzwischensternartigraum foo@bar.zp 2
这是我的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXINPUT 682
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link;
link head;
void add(char c[]) {
words x;
char *str;
link temp = (link)malloc(sizeof(node));
strtok(c, " ");
str = strtok(NULL, " ");
x.word1 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word1, str);
str = strtok(NULL, " ");
x.word2 = (char *)malloc(sizeof(char) * (strlen(str) + 1)); /* where the error happens with this input */
strcpy(x.word2, str);
str = strtok(NULL, "[=10=]");
x.word3 = (char *)malloc(sizeof(char) * (strlen(str) + 1));
strcpy(x.word3, str);
temp->cont = x;
temp->next = head;
head = temp;
}
int main() {
char input[MAXINPUT] = " ";
head = NULL;
while (input[0] != 'x') {
fgets(input, MAXINPUT, stdin);
input[strcspn(input, "\r\n")] = 0;
if (input[0] == 'a')
add(input);
...
当我 运行 使用此代码输入时,我得到一个 Segmentation Error
并且 valgrind 说有 3 个分配,只有一个空闲,并且 leak\error 发生在行中代码中提到,专门用了strlen。它还说我出于某种原因无法访问内存位置 0x0。我想知道为什么会这样,谢谢!
您不测试 strtok
是否找到了所有标记。在使用之前,您必须检查由 strtok()
编辑的指针 return。如果不这样做,无效输入将导致未定义的行为。
在您的情况下,输入超过 682 个字节,前 681 个字节被读入数组并且此片段不包含足够的标记,因此 strtok()
调用之一 return NULL
,当您使用 strlen()
.
始终测试并报告错误情况,您将为自己节省无数小时的调试时间。
当程序崩溃时,valgrind 报告的内存泄漏是没有意义的,因为程序没有完成正常执行,当然也没有正确释放分配的内存。程序退出后内存仍然returned到操作系统,但是valgrind通过调用free()
.
为避免对行长度设置任意限制,您可以使用 POSIX standard function getline()
根据需要重新分配数组。
您还应该使用 strdup
在单个函数调用中分配字符串的副本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct words {
char *word1;
char *word2;
char *word3;
} words;
typedef struct node{
words cont;
struct node *next;
} node;
typedef node *link; // hiding pointers behind typedefs is not recommended
link head;
link add(char c[]) {
words x = { NULL, NULL, NULL };
char *str;
link temp;
if (strtok(c, " ") != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word1 = strdup(str)) != NULL
&& (str = strtok(NULL, " ")) != NULL
&& (x.word2 = strdup(str)) != NULL
&& (str = strtok(NULL, "")) != NULL
&& (x.word3 = strdup(str)) != NULL
&& (temp = malloc(sizeof(*temp)) != NULL) {
temp->cont = x;
temp->next = head;
return head = temp;
} else {
free(x.word3);
free(x.word2);
free(x.word1);
return NULL;
}
}
int main() {
char *input = NULL;
size_t input_size = 0;
head = NULL;
while (getline(&input, &input_size, stdin) >= 0 && *input != 'x') {
input[strcspn(input, "\r\n")] = '[=10=]';
if (*input == 'a')
add(input);
...
}
...
}
free(input);
...
return 0;
}