C程序中的段错误,malloc调用
Segfault in C program, malloc call
我正在编写一个程序,它获取路径列表(环境变量),拆分路径并打印它。编译时出现段错误。以下是我在 GDB 上的输出:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400eb0 in dest (name=0x7fffffffbce0 "PATH") at executables.c:100
100 dest[i] = malloc(srclen+1);
在 valgrind 上:
==21574== 1 errors in context 2 of 3:
==21574== Use of uninitialised value of size 8
==21574== at 0x400EB0: dest (executables.c:100)
==21574== by 0x400B5B: main (main.c:9)
这是我的功能:
char** dest(char *name){
int i=0;
char *vp;
const char s[2]=":";
char *token;
char **dest;
name[strlen(name)-1]='[=12=]';
vp=getenv(name);
if(vp == NULL){
exit(1);
}
token =strtok(vp,s);
while( token != NULL ){
size_t srclen = strlen(token);
dest[i] = malloc(srclen+1);
strcpy(dest[i], token);
token = strtok(NULL, s);
i++;
}
dest[i]=NULL;
return dest;
}
这是我的主要内容:
#include "executables.h"
int main(int argc, char **argv){
char *path;
char name[BUFSIZ];
printf("enter name of environment variable:\n");
fgets(name,BUFSIZ,stdin);
char **p=dest(name);
int j=0;
while(p[j]!=NULL){
printf("%s\n",p[j]);
j++;
}
return(0);
}
dest[i] = malloc(srclen + 1);
您需要为指向char指针(dest)的指针以及存储在dest中的每个char指针分配内存。在您提供的代码中,没有采取任何步骤。
使用strdup()。节省步骤(占
'\0' 也是)。您必须事先为您正在使用的方法分配一些内存。否则,您可能需要一个链表并分配数据包,而不是使用数组模式。当你说 dest[i] = <ptr value>
时,你正在索引到未分配内存的偏移量并在那里存储一些东西,所以它是一个 segvio。
#include <string.h>
#define MAXTOKENS 10000
char **get_dest(char *name) {
// Since dest has to be exposed/persist beyond this function all
// need dynamically allocate (malloc()) rather than stack allocate
// of the form of: char *dest[MAXTOKENS].
char *dest = malloc(MAXTOKENS * sizeof (char *)); // <--- need to allocate storage for the pointers
char *vp;
if ((vp = getenv(name)) == NULL)
exit(-1); // -1 is err exit on UNIX, 0 is success
int i = 0;
char *token = strtok(vp, ":");
while (token != NULL) {
dest[i] = strdup(token); // <=== strdup()
token = strtok(NULL, ":");
i++;
}
// dest[i] = NULL; // Why are you setting this to NULL after adding token?
return dest;
}
最好是 main() 负责将适当的 null-terminated 字符串传递给 get_dest() 函数,因为 main 是处理挑剔的 fgets() 的地方。通常,您想在最有意义和最相关的地方做事。如果您曾经使用 get_dest() 函数并在 fgets() 未读取字符串的地方使用它,那么覆盖那里的终止符只是浪费了一步。因此,通过在 fgets() 之前将 char 数组初始化为零,您不必担心将尾随字节设置为 '\0'。
最后,让函数名 dest 与变量 it returns dest 同名可能不太好。在某些情况下,您的程序中有多个同名符号会给您带来麻烦。
#include "executables.h"
int main(int argc, char **argv) {
char *path;
char name[BUFSIZ] = { 0 }; // You could initialize it to zero this way
printf("enter name of environment variable:\n");
// bzero(name, BUFSIZ); //... or you could initialize it to zero this way then
fgets(name, BUFSIZ, stdin);
char **p = get_dest(name);
int j = 0;
while(p[j] != NULL) {
printf("%s\n", p[j]);
j++;
free(p[j]); // like malloc(), strdup'd() strings must be free'd when done
}
free(p);
return 0;
}
来自 getenv 的联机帮助页:
Notes
...
As typically implemented, getenv() returns a pointer to a string
within the environment list. The caller must take care not to modify
this string, since that would change the environment of the process.
您的代码违反了该规则:
vp=getenv(name);
...
token =strtok(vp,s);
这是一个非法的内存写入操作。
我正在编写一个程序,它获取路径列表(环境变量),拆分路径并打印它。编译时出现段错误。以下是我在 GDB 上的输出:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400eb0 in dest (name=0x7fffffffbce0 "PATH") at executables.c:100
100 dest[i] = malloc(srclen+1);
在 valgrind 上:
==21574== 1 errors in context 2 of 3:
==21574== Use of uninitialised value of size 8
==21574== at 0x400EB0: dest (executables.c:100)
==21574== by 0x400B5B: main (main.c:9)
这是我的功能:
char** dest(char *name){
int i=0;
char *vp;
const char s[2]=":";
char *token;
char **dest;
name[strlen(name)-1]='[=12=]';
vp=getenv(name);
if(vp == NULL){
exit(1);
}
token =strtok(vp,s);
while( token != NULL ){
size_t srclen = strlen(token);
dest[i] = malloc(srclen+1);
strcpy(dest[i], token);
token = strtok(NULL, s);
i++;
}
dest[i]=NULL;
return dest;
}
这是我的主要内容:
#include "executables.h"
int main(int argc, char **argv){
char *path;
char name[BUFSIZ];
printf("enter name of environment variable:\n");
fgets(name,BUFSIZ,stdin);
char **p=dest(name);
int j=0;
while(p[j]!=NULL){
printf("%s\n",p[j]);
j++;
}
return(0);
}
dest[i] = malloc(srclen + 1);
您需要为指向char指针(dest)的指针以及存储在dest中的每个char指针分配内存。在您提供的代码中,没有采取任何步骤。
使用strdup()。节省步骤(占
'\0' 也是)。您必须事先为您正在使用的方法分配一些内存。否则,您可能需要一个链表并分配数据包,而不是使用数组模式。当你说 dest[i] = <ptr value>
时,你正在索引到未分配内存的偏移量并在那里存储一些东西,所以它是一个 segvio。
#include <string.h>
#define MAXTOKENS 10000
char **get_dest(char *name) {
// Since dest has to be exposed/persist beyond this function all
// need dynamically allocate (malloc()) rather than stack allocate
// of the form of: char *dest[MAXTOKENS].
char *dest = malloc(MAXTOKENS * sizeof (char *)); // <--- need to allocate storage for the pointers
char *vp;
if ((vp = getenv(name)) == NULL)
exit(-1); // -1 is err exit on UNIX, 0 is success
int i = 0;
char *token = strtok(vp, ":");
while (token != NULL) {
dest[i] = strdup(token); // <=== strdup()
token = strtok(NULL, ":");
i++;
}
// dest[i] = NULL; // Why are you setting this to NULL after adding token?
return dest;
}
最好是 main() 负责将适当的 null-terminated 字符串传递给 get_dest() 函数,因为 main 是处理挑剔的 fgets() 的地方。通常,您想在最有意义和最相关的地方做事。如果您曾经使用 get_dest() 函数并在 fgets() 未读取字符串的地方使用它,那么覆盖那里的终止符只是浪费了一步。因此,通过在 fgets() 之前将 char 数组初始化为零,您不必担心将尾随字节设置为 '\0'。
最后,让函数名 dest 与变量 it returns dest 同名可能不太好。在某些情况下,您的程序中有多个同名符号会给您带来麻烦。
#include "executables.h"
int main(int argc, char **argv) {
char *path;
char name[BUFSIZ] = { 0 }; // You could initialize it to zero this way
printf("enter name of environment variable:\n");
// bzero(name, BUFSIZ); //... or you could initialize it to zero this way then
fgets(name, BUFSIZ, stdin);
char **p = get_dest(name);
int j = 0;
while(p[j] != NULL) {
printf("%s\n", p[j]);
j++;
free(p[j]); // like malloc(), strdup'd() strings must be free'd when done
}
free(p);
return 0;
}
来自 getenv 的联机帮助页:
Notes ... As typically implemented, getenv() returns a pointer to a string within the environment list. The caller must take care not to modify this string, since that would change the environment of the process.
您的代码违反了该规则:
vp=getenv(name);
...
token =strtok(vp,s);
这是一个非法的内存写入操作。