当我尝试释放动态分配的指针数组时,Valgrind 抛出无效的 free()
Valgrind throws invalid free() when I try to free an array of dynamically allocated pointers
我正在分配动态分配的指针数组,并尝试在程序结束时释放它们。问题是我总是在 valgrind 上遇到 "invalid free()" 错误,尽管我真的找不到问题所在。
例如:我使用 malloc 为 argv[0] 和 argv1 分配内存,然后尝试在 for 循环中释放它们。
我使用以下方法分配指针数组:
char ucom[10], bin[15] = "/bin/";
char* str = (char *) malloc(MAX_LINE_LENGTH*sizeof(char));
char** argv = (char **) malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int status, i = 0;
printf("Shell2$**");
strcpy(bin, "/bin/");
fgets(str, MAX_LINE_LENGTH, stdin);
char *token;
token = strsep(&str, " ");
while(token != NULL && i < 4){
if(token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=10=]';
argv[i] = (char *) malloc(MAX_ARGUMENT_LENGTH*sizeof(char)); //ALLOCATING MEMORY FOR POINTERS INSIDE ARGV, running two times in my example
printf("\n\nI:%d\n\n",i);
if(argv[i] == NULL) printf("Memory Allocation Problem");
argv[i] = token;
token = strsep(&str, " ");
i++;
argv = (char **)realloc(argv, (i+2)*sizeof(char*));
}
然后我尝试释放它们:
wait(&status);
for(int f = 0; f < i; f++){
if(argv[f] != NULL)
free(argv[f]); //Free runs two times as the number of time malloc has been called, but fails at the second free.
}
free(str);
free(argv);
即使在我的示例中 malloc 运行 2 次,它为 argv[0] 和 argv1 分配了内存,当最后的 for 循环试图释放 argv1,它失败了,valgrind 说它是一个免费的无效的,但它成功地释放了 argv[0]。
提前谢谢大家!
valgrind 的输出:
LINK
除了@FredLarson 和我已经指出的错误之外还有更多错误。
函数strsep()
实际上修改了传递给它的指针,所以char *token = strsep(&str, " ")
; 更改指针。由于 str
是从 malloc
获取的,因此无法正确释放它。
如果你想在 malloc 的内存上调用 strsep()
,你必须保存原始指针的副本并在最后释放它。
此外,并非严格可移植但高度可用的函数 strdup()
对复制字符串非常有用,因此与其分配一堆内存然后将字符串复制到其中,您还可以strdup()
那个字符串(稍后释放它)。
#define _BSD_SOURCE // for strsep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 80
#define MAX_ARGUMENT_LENGTH 10 // made up numbers
int main()
{
char *str = malloc(MAX_LINE_LENGTH);
char *str_save = str;
char **argv = malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int i = 0;
printf("Shell2$**"); fflush(stdout); // make sure user sees the prompt
strcpy(bin, "/bin/");
fgets(str, MAX_LINE_LENGTH, stdin);
char *token;
while ( (token = strsep(&str, " ")) != NULL && i < 4 )
{
if(token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=10=]';
argv[i] = strdup(token);
if(argv[i] == NULL) printf("Memory Allocation Problem");
i++;
argv = realloc(argv, i * sizeof(char*));
}
argv[i] = NULL; // GOOD IDEA TO ADD THIS
// run the shell
// wait(&status);
for(int f = 0; f < i; f++){
if(argv[f] != NULL)
free(argv[f]);
}
free(str_save);
free(argv);
}
这基本上与您的一样,但实际上您可能甚至不需要为输入行分配内存。为什么不只定义一个本地缓冲区?然后你不必为行缓冲区 或标记 分配,因为它们都位于 linebuffer
:
#define _BSD_SOURCE // for strsep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 80
int main()
{
char **argv = malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int i = 0;
printf("Shell2$**"); fflush(stdout); // make sure user sees the prompt
char linebuf[MAX_LINE_LENGTH];
fgets(linebuf, sizeof linebuf, stdin);
char *token;
char *str = linebuf;
while ( (token = strsep(&str, " ")) != NULL && i < 4 )
{
if (token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=11=]';
argv[i++] = token;
argv = realloc(argv, i * sizeof(char*));
}
argv[i] = NULL; // GOOD IDEA TO ADD THIS
// run the shell
// wait(&status);
free(argv);
}
这消除了很多并发症——据我所知——同样安全。
我正在分配动态分配的指针数组,并尝试在程序结束时释放它们。问题是我总是在 valgrind 上遇到 "invalid free()" 错误,尽管我真的找不到问题所在。 例如:我使用 malloc 为 argv[0] 和 argv1 分配内存,然后尝试在 for 循环中释放它们。 我使用以下方法分配指针数组:
char ucom[10], bin[15] = "/bin/";
char* str = (char *) malloc(MAX_LINE_LENGTH*sizeof(char));
char** argv = (char **) malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int status, i = 0;
printf("Shell2$**");
strcpy(bin, "/bin/");
fgets(str, MAX_LINE_LENGTH, stdin);
char *token;
token = strsep(&str, " ");
while(token != NULL && i < 4){
if(token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=10=]';
argv[i] = (char *) malloc(MAX_ARGUMENT_LENGTH*sizeof(char)); //ALLOCATING MEMORY FOR POINTERS INSIDE ARGV, running two times in my example
printf("\n\nI:%d\n\n",i);
if(argv[i] == NULL) printf("Memory Allocation Problem");
argv[i] = token;
token = strsep(&str, " ");
i++;
argv = (char **)realloc(argv, (i+2)*sizeof(char*));
}
然后我尝试释放它们:
wait(&status);
for(int f = 0; f < i; f++){
if(argv[f] != NULL)
free(argv[f]); //Free runs two times as the number of time malloc has been called, but fails at the second free.
}
free(str);
free(argv);
即使在我的示例中 malloc 运行 2 次,它为 argv[0] 和 argv1 分配了内存,当最后的 for 循环试图释放 argv1,它失败了,valgrind 说它是一个免费的无效的,但它成功地释放了 argv[0]。
提前谢谢大家!
valgrind 的输出: LINK
除了@FredLarson 和我已经指出的错误之外还有更多错误。
函数strsep()
实际上修改了传递给它的指针,所以char *token = strsep(&str, " ")
; 更改指针。由于 str
是从 malloc
获取的,因此无法正确释放它。
如果你想在 malloc 的内存上调用 strsep()
,你必须保存原始指针的副本并在最后释放它。
此外,并非严格可移植但高度可用的函数 strdup()
对复制字符串非常有用,因此与其分配一堆内存然后将字符串复制到其中,您还可以strdup()
那个字符串(稍后释放它)。
#define _BSD_SOURCE // for strsep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 80
#define MAX_ARGUMENT_LENGTH 10 // made up numbers
int main()
{
char *str = malloc(MAX_LINE_LENGTH);
char *str_save = str;
char **argv = malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int i = 0;
printf("Shell2$**"); fflush(stdout); // make sure user sees the prompt
strcpy(bin, "/bin/");
fgets(str, MAX_LINE_LENGTH, stdin);
char *token;
while ( (token = strsep(&str, " ")) != NULL && i < 4 )
{
if(token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=10=]';
argv[i] = strdup(token);
if(argv[i] == NULL) printf("Memory Allocation Problem");
i++;
argv = realloc(argv, i * sizeof(char*));
}
argv[i] = NULL; // GOOD IDEA TO ADD THIS
// run the shell
// wait(&status);
for(int f = 0; f < i; f++){
if(argv[f] != NULL)
free(argv[f]);
}
free(str_save);
free(argv);
}
这基本上与您的一样,但实际上您可能甚至不需要为输入行分配内存。为什么不只定义一个本地缓冲区?然后你不必为行缓冲区 或标记 分配,因为它们都位于 linebuffer
:
#define _BSD_SOURCE // for strsep
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 80
int main()
{
char **argv = malloc(sizeof(char*)); //ALLOCATING MEMORY FOR ARGV
int i = 0;
printf("Shell2$**"); fflush(stdout); // make sure user sees the prompt
char linebuf[MAX_LINE_LENGTH];
fgets(linebuf, sizeof linebuf, stdin);
char *token;
char *str = linebuf;
while ( (token = strsep(&str, " ")) != NULL && i < 4 )
{
if (token[strlen(token)-1] == '\n')
token[strlen(token)-1] = '[=11=]';
argv[i++] = token;
argv = realloc(argv, i * sizeof(char*));
}
argv[i] = NULL; // GOOD IDEA TO ADD THIS
// run the shell
// wait(&status);
free(argv);
}
这消除了很多并发症——据我所知——同样安全。