0

我有一个学校作业,一切都很好,除了一个我无法弄清楚的部分。以下是我的问题发生的代码片段:

    //something goes wrong here, wont copy over
    puts("bravo");
    //add to end of the list
    int size_list = sizeof(environ);
    //char** tmp_ptr = ( char** )calloc( size_list + 1, ( size_list + 1 ) * sizeof( char* ) );
    char** tmp_ptr = ( char** ) malloc ( ( size_list + 1 ) * sizeof( char* ) );
    int k;
    for ( k = 0; k < size_list; ++k )
    {
        tmp_ptr[k] = environ[k];
        //memcpy(tmp_ptr[k],environ[k],sizeof(environ[k]));
    }
    //char** tmp_ptr= (char**)realloc(*environ, size_list+2);
    environ = tmp_ptr;
    environ[size_list] = (char*)malloc(len_string+1);
    strcpy(environ[size_list],full_string);
    return 1;

您可以忽略“bravo”,这是由我来定位问题发生的位置。我试图让 environ 拥有新的变量列表,但是当我将它设置为等于 tmp_ptr 时,它是空的。我很确定这些值被复制了,但我不知道出了什么问题。函数结束时是否会删除 tmp_ptr 中的数据?这是一个可能的解释吗?如何正确分配和复制内存。我尝试使用 realloc,但这给了我无效的指针错误,所以我依赖 calloc 或 malloc。提前致谢。

4

2 回答 2

4

environ的长度不是sizeof(environ),因为environ是 a char **(因此sizeof(environ)是 4 或 8,具体取决于您的平台)。您所做的实际上是清除了大部分内容,environ因为您只复制了前几个条目。

要找出有多少条目environ,请执行

int cnt = 0;
char **envp = environ;
while(*envp++) cnt++;

我还应该注意该方法的一个问题:因为environ它是一个NULL- 终止的字符串数组(不要与'null-terminated string'混淆),你必须用你自己的条目替换最后的,然后在你之后添加一个新的新条目。目前,您的代码(如果它正确计算了大小)将在 , 之后添加您的条目​​,并且对程序不可见。NULLNULLNULL

旁注:environ绝对不建议使用这种方式。使用getenv/setenv代替;如果您需要批量设置环境,请尝试使用execve。(因此,在您的情况下,您可以简单setenv("varname", "varvalue", 1)地添加到环境中(如果已设置varname=varvalue现有映射,则将其替换为)。varname

于 2012-09-25T01:31:48.633 回答
3

environ是一个指针,这意味着它sizeof(environ)不是该数组中的项目数。相反,它是指针的大小,在您的情况下可能是四或八。

如果environ是与(最后一个是空指针的字符指针数组)相同的结构argv,则需要通过遍历数组来确定其大小,直到找到 NULL。

类似的东西(未经测试,但这个想法是合理的):

char **envPtr = environ;
int size_list = 0;            // probably should be size_t
while (*envPtr != NULL) {
    envPtr++;
    size_list++;
}

您可以在这个完整的程序中看到效果(进行了一些更改以绕过其他一些错误):

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)

int main (int argc, char **argv) {
    int k, size_list = sizeof(environ);
    char **tmp_ptr = malloc ((size_list + 1) * sizeof ( char*));

    for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
    for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
    tmp_ptr[size_list] = NULL;

    environ = tmp_ptr;
    environ[size_list] = malloc (len_string + 1);
    strcpy(environ[size_list],full_string);

    printf ("=====\n");
    for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);

    return 0;
}

这仅输出我的四个环境变量,因为我有四字节指针:

[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[xyzzy=plugh]

更改代码以正确确定环境的大小:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define full_string "xyzzy=plugh"
#define len_string strlen(full_string)

int main(int argc, char **argv) {
    int k, size_list = 0;
    char **envPtr = environ;
    while (*envPtr != NULL) {
        envPtr++;
        size_list++;
    }
    char **tmp_ptr = malloc ((size_list + 1) * sizeof (char*));

    for (k = 0; k < size_list; ++k) printf ("[%s]\n", environ[k]);
    for (k = 0; k < size_list; ++k) tmp_ptr[k] = environ[k];
    tmp_ptr[size_list] = NULL;

    environ = tmp_ptr;
    environ[size_list] = malloc (len_string + 1);
    strcpy(environ[size_list],full_string);

    printf ("=====\n");
    for (k = 0; k <= size_list; ++k) printf ("[%s]\n", environ[k]);

    return 0;
}

给了我很多:

[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
=====
[ORBIT_SOCKETDIR=/tmp/orbit-pax]
[SSH_AGENT_PID=1978]
[GPG_AGENT_INFO=/tmp/seahorse-tNDhG9/S.gpg-agent:2005:1]
[TERM=xterm]
[SHELL=/bin/bash]
[GTK_RC_FILES=/etc/gtk/gtkrc:/home/pax/.gtkrc-1.2-gnome2]
[WINDOWID=62914564]
[GNOME_KEYRING_CONTROL=/tmp/keyring-RADe9n]
[GTK_MODULES=canberra-gtk-module]
[USER=pax]
:
[XAUTHORITY=/var/run/gdm3/auth-for-pax-AO1dYc/database]
[_=./testprog]
[xyzzy=plugh]

对于它的价值,您的代码存在以下问题:

  • 显然,环境大小的计算不正确。
  • 从 - 转换返回值malloc- 这在 C 中是不明智的,因为它可能会导致代码问题对您隐藏。
  • 不将新列表的最后一个元素设置为 NULL。
  • 不检查内存不足的情况。

除了最后一个之外,所有这些都固定在我上面的最终代码示例中。

于 2012-09-25T01:31:40.570 回答