Segfault在C程序中,malloc调用

时间:2017-02-01 02:53:32

标签: c gdb valgrind

我正在编写一个程序,它接受路径列表(环境变量),分割路径并打印它。编译时,我得到一个段错误。以下是我在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);
}

3 个答案:

答案 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);

这是非法的内存写入操作。