我正在编写一个程序,它接受路径列表(环境变量),分割路径并打印它。编译时,我得到一个段错误。以下是我在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]='\0';
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);
}
答案 0 :(得分:2)
dest[i] = malloc(srclen + 1);
您需要为指向char指针(dest)的指针以及存储在dest中的每个char指针分配内存。在您提供的代码中,不采取任何步骤。
答案 1 :(得分:2)
使用strdup()。保存步骤(帐户
'\'也是)。您必须事先为您正在使用的方法分配一些内存。否则,您可能需要链接列表并分配数据包而不是使用数组模式。当你说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结尾的字符串传递给get_dest()函数,因为main是处理finicky fgets()的地方。一般来说,你想在最有意义且最相关的地方做事。如果您使用了get_dest()函数并将其用于fgets()未读取字符串的地方,那么在那里覆盖终结符只是浪费的一步。因此,通过在fgets()之前将char数组初始化为零,您不必担心将尾随字节设置为'\ 0'。
最后,将函数名称与返回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;
}
答案 2 :(得分:1)
来自getenv的联机帮助页:
注 ... 通常实现时,getenv()返回指向字符串的指针 在环境列表中。 来电者必须注意不要修改 这个字符串,因为这会改变过程的环境。
您的代码违反了该规则:
vp=getenv(name);
...
token =strtok(vp,s);
这是非法的内存写入操作。