C 试图收集我的linux环境的环境变量,但我不断遇到分段错误

C 试图收集我的linux环境的环境变量,但我不断遇到分段错误,c,C,尝试打印环境变量,将它们存储到令牌上,将所述令牌放入数组,然后使用冒泡排序对它们进行排序。 到目前为止,我无法将它们放在阵列上而不遇到分段错误 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 100 #define MIN 5 int main(int argc, char *argv[], char *envp[]) { int i = 0; char *de

尝试打印环境变量,将它们存储到令牌上,将所述令牌放入数组,然后使用冒泡排序对它们进行排序。 到目前为止,我无法将它们放在阵列上而不遇到分段错误

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
#define MIN 5


int main(int argc, char *argv[], char *envp[])
{
int i = 0;

char *delimiter;

delimiter= ".:;";

char *token;

char *tokenArray[50];


while(envp[i])
{
        //token = malloc(20*sizeof(char));
        token = strtok(envp[i], delimiter);
        printf(" %s \n", token);
        token = strtok(NULL, delimiter);
        tokenArray[i] = malloc(50);
        strcpy(tokenArray[i], token);
        //free(token);
        i++;

}

for(int j = 0; j < i; j++)
{

printf(" %s \n ", tokenArray[j]);
        free(tokenArray[j]);
}
return 0;
}
#包括
#包括
#包括
#定义最大值100
#定义最小值5
int main(int argc,char*argv[],char*envp[]
{
int i=0;
字符*分隔符;
分隔符=“.:;”;
字符*令牌;
char*tokenArray[50];
while(envp[i])
{
//令牌=malloc(20*sizeof(char));
token=strtok(envp[i],分隔符);
printf(“%s\n”,标记);
token=strtok(空,分隔符);
令牌数组[i]=malloc(50);
strcpy(令牌数组[i],令牌);
//免费(代币);
i++;
}
对于(int j=0;j
这是一段工作代码,它将所有环境变量放入
标记中

int main(int argc, char *argv[], char *envp[])
{
    const char *delimiter = "=";

    // Calculate the number of env variables. This is much better than
    // assuming a maximum size.
    size_t no_env = 0;
    while(envp[no_env])
        no_env++;

    // Allocate space for no_env pointers
    char **tokens = malloc(sizeof(*tokens) * no_env);

    for(int i=0; i<no_env; i++)
    {
        // Token is not used outside this loop, so there's no point in declaring
        // it outside. Same goes for the indexing variable i.
        char *token = strtok(envp[i], delimiter);
        // Allocate space for the string
        tokens[i] = malloc(strlen(token) * sizeof(*tokens[i]));
        strcpy(tokens[i], token);
    }

    // Free all the strings and then the last pointer
    for(int i = 0; i < no_env; i++)
        free(tokens[i]);
    free(tokens);
}
对于您的代码,您可以使用一个简单的
if(!(p=malloc(…){return EXIT_FAILURE;}
来代替所有这些
goto
语句


使用
malloc
时,请始终使用
p=malloc(sizeof(*p)*size)
。这样可以显著降低出错风险。如果要为字符串(char)分配空间,则可以跳过
sizeof
,直接进入
p=malloc(size)
但请确保您知道自己在做什么。

虽然不清楚为什么要使用
分隔符=“.:;”;
对每个环境变量进行日化,但它没有任何问题(我也会添加
“*”
),而不是在环境变量上循环两次(一次计算分配指针的数量,下一次将变量标记为单个标记),您只需根据需要对
envp
一次和
realloc
指针进行迭代即可

从一定数量的指针开始(比如
2
),然后将
使用的
指针与可用的(
avail
)指针数量进行比较,当它们相等时,将
realloc
可用的指针数量增加一倍

另一个注意事项。
strtok
在标记化时修改原始字符串。因此,您可以(可选)在标记化副本之前简单地复制环境,而不是直接标记化
envp[x]
,从而修改
envp
中的内容

分配和重新分配指针,然后为每个令牌分配存储的简短实现可以是:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NPTRS 2     /* if you need a constant, #define one (or more) */
#define MAXC 8192

int main (int argc, char *argv[], char *envp[])
{
    size_t i = 0, used = 0, avail = NPTRS;  /* counters */
    const char *delim = ".:;*";             /* delimiters */
    char **tarray = NULL;                   /* pointer to pointer */

    /* allocate/validate NPTRS pointers initially */
    if (!(tarray = malloc (avail * sizeof *tarray))) {
        perror ("malloc-tarray");
        return 1;
    }

    while (envp[i]) {               /* loop over each env var */
        char envstr[MAXC];          /* array to hold current env var */
        size_t envlen = strlen (envp[i]);   /* get env var len */
        /* tokenize envp[i] */
        if (envlen >= MAXC - 1) {   /* check env fits in envstr */
            fputs ("error: envstr exceeds MAXC chars.\n", stderr);
            continue;
        }
        /* strtok modifies original, make copy of env var before strtok */
        memcpy (envstr, envp[i], envlen + 1);
        /* tokenize env var based on delim */
        for (char *p = strtok (envstr, delim); p; p = strtok (NULL, delim)) {
            size_t len = strlen (p);/* length of token */
            if (used == avail) {    /* check if realloc of pointers req'd */
                /* always realloc using a temporary pointer */
                void *tmp = realloc (tarray, 2 * avail * sizeof *tarray);
                if (!tmp) {     /* validate reallocation */
                    perror ("realloc-tarray");
                    goto done;  /* tarray still good, break nested loops */
                }
                tarray = tmp;   /* assign realloc'ed block to tarray */
                avail *= 2;     /* update avaialble no. of pointers */
            }
            /* allocate/validate storage for token */
            if (!(tarray[used] = malloc (len + 1))) {
                perror ("malloc tarray[used]");
                goto done;  /* goto req'd to break nested loops */
            }
            memcpy (tarray[used++], p, len + 1);    /* copy to new memory */
        }
        i++;    /* advance to next environment variable */
    }
    done:;

    for (i = 0; i < used; i++) {    /* output all tokens */
        printf ("tarray[%3zu] : %s\n", i, tarray[i]);
        free (tarray[i]);   /* free storage of strings */
    }
    free (tarray);  /* free pointers */

    (void)argc, (void)argv;     /* suppress unused varaible warnings */
}

始终确认已释放所有已分配的内存,并且没有内存错误。

是否尝试运行调试器以查看代码在哪一行崩溃?您是否了解指针和内存分配是如何工作的?您不止一次设置了指向malloc的指针(某个东西),然后在随后的一行中覆盖它,从而导致内存泄漏。我读了至少五个教程,同一点出现了多次。这些教程都说,每次调用malloc时,内存中的地址都会被分配。当然,接下来我会访问类似Stack的网站,显然它的工作方式不同,因为调用malloc multiLE时代意味着我在写最后一个内存调用,当我检查“在线教程”时,他们从不提任何东西,除了每个Maloc都有它自己的内存地址。好,让我们举一个小例子。如果我们采用这个代码:<代码> int x;x=5;x=3;< /代码>我认为很明显,<代码> x=5 < /代码>没有任何影响。这和指针没什么不同。有点像,但也不完全一样。每个malloc都应该有一个空闲的。但是这两个代码片段是100%等效的:
char*p=malloc(1);p=“foo”
malloc(1);char*p=“foo”
。对malloc的调用除了导致内存泄漏之外没有任何效果。而不是
strlen()
/
malloc()
pair请使用
strdup()
。它完全满足您的需要,让您的意图更加清晰。@如果该函数是标准的一部分,我会很忙,但事实并非如此。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NPTRS 2     /* if you need a constant, #define one (or more) */
#define MAXC 8192

int main (int argc, char *argv[], char *envp[])
{
    size_t i = 0, used = 0, avail = NPTRS;  /* counters */
    const char *delim = ".:;*";             /* delimiters */
    char **tarray = NULL;                   /* pointer to pointer */

    /* allocate/validate NPTRS pointers initially */
    if (!(tarray = malloc (avail * sizeof *tarray))) {
        perror ("malloc-tarray");
        return 1;
    }

    while (envp[i]) {               /* loop over each env var */
        char envstr[MAXC];          /* array to hold current env var */
        size_t envlen = strlen (envp[i]);   /* get env var len */
        /* tokenize envp[i] */
        if (envlen >= MAXC - 1) {   /* check env fits in envstr */
            fputs ("error: envstr exceeds MAXC chars.\n", stderr);
            continue;
        }
        /* strtok modifies original, make copy of env var before strtok */
        memcpy (envstr, envp[i], envlen + 1);
        /* tokenize env var based on delim */
        for (char *p = strtok (envstr, delim); p; p = strtok (NULL, delim)) {
            size_t len = strlen (p);/* length of token */
            if (used == avail) {    /* check if realloc of pointers req'd */
                /* always realloc using a temporary pointer */
                void *tmp = realloc (tarray, 2 * avail * sizeof *tarray);
                if (!tmp) {     /* validate reallocation */
                    perror ("realloc-tarray");
                    goto done;  /* tarray still good, break nested loops */
                }
                tarray = tmp;   /* assign realloc'ed block to tarray */
                avail *= 2;     /* update avaialble no. of pointers */
            }
            /* allocate/validate storage for token */
            if (!(tarray[used] = malloc (len + 1))) {
                perror ("malloc tarray[used]");
                goto done;  /* goto req'd to break nested loops */
            }
            memcpy (tarray[used++], p, len + 1);    /* copy to new memory */
        }
        i++;    /* advance to next environment variable */
    }
    done:;

    for (i = 0; i < used; i++) {    /* output all tokens */
        printf ("tarray[%3zu] : %s\n", i, tarray[i]);
        free (tarray[i]);   /* free storage of strings */
    }
    free (tarray);  /* free pointers */

    (void)argc, (void)argv;     /* suppress unused varaible warnings */
}
$ ./bin/main_envp
tarray[  0] : XDG_VTNR=7
tarray[  1] : LESSKEY=/etc/lesskey
tarray[  2] : bin
tarray[  3] : MANPATH=/usr/local/man
tarray[  4] : /usr/share/man
tarray[  5] : /opt/kde3/share/man
tarray[  6] : NNTPSERVER=news
tarray[  7] : XDG_SESSION_ID=1
tarray[  8] : SSH_AGENT_PID=3195
tarray[  9] : KDE_MULTIHEAD=false
tarray[ 10] : HOSTNAME=wizard
tarray[ 11] : DM_CONTROL=/var/run/xdmctl
<snip>
$ valgrind ./bin/main_envp
==16243== Memcheck, a memory error detector
==16243== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==16243== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==16243== Command: ./bin/main_envp
==16243==
tarray[  0] : XDG_VTNR=7
tarray[  1] : LESSKEY=/etc/lesskey
tarray[  2] : bin
tarray[  3] : MANPATH=/usr/local/man
tarray[  4] : /usr/share/man
tarray[  5] : /opt/kde3/share/man
tarray[  6] : NNTPSERVER=news
tarray[  7] : XDG_SESSION_ID=1
tarray[  8] : SSH_AGENT_PID=3195
tarray[  9] : KDE_MULTIHEAD=false
tarray[ 10] : HOSTNAME=wizard
tarray[ 11] : DM_CONTROL=/var/run/xdmctl
<snip>
==16243==
==16243== HEAP SUMMARY:
==16243==     in use at exit: 0 bytes in 0 blocks
==16243==   total heap usage: 292 allocs, 292 frees, 11,723 bytes allocated
==16243==
==16243== All heap blocks were freed -- no leaks are possible
==16243==
==16243== For counts of detected and suppressed errors, rerun with: -v
==16243== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)