我对一个(非常大的)c程序有点问题,并且发现问题不是来自我的程序本身,而是我创建数组的方式,我认为。
我的问题如下,我需要创建一个与包含环境变量(extern char **environ
)相同的数组,然后在最后添加另一个值。
以下是我检查environ
是否复制良好的代码:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int ft_length(char **arr)
{
int i = 0;
while (arr[i])
i++;
return (i);
}
int main(void)
{
extern char **environ;
char **env;
int err;
int x;
err = 0;
x = 0;
env = (char**)malloc(sizeof(char*) * ft_length(environ) + 2);
while (environ[x])
{
// printf("%s\n", environ[x]);
env[x] = (char*)malloc(sizeof(char) * strlen(environ[x]) + 1);
bzero(env[x], strlen(environ[x]));
strncpy(env[x], environ[x], strlen(environ[x]));
// printf("%s\n", env[x]);
x++;
}
env[x] = (char*)malloc(sizeof(char) * 4);
env[x] = "ccc\0";
env[++x] = NULL;
x = 0;
while (environ[x])
{
if (strcmp(environ[x], env[x]) != 0)
{
err++;
printf("error on env[%d]\n", x);
printf("environ[%d] : |%s|\n", x, environ[x]);
printf("env[%d] : |%s|\n", x, env[x]);
printf("----------------\n");
}
x++;
}
while (env[x])
{
if (strcmp(env[x], "ccc") != 0)
{
err++;
printf("env[%d] contain |%s| instead of |ccc|\n", x, env[x]);
}
x++;
}
printf("done with %d error(s)\n", err);
return (1);
}
当我在Mac OSX上运行此代码时,env[0]
在结尾处为空,当我将最后一个数组值设置为NULL
(env[++x] = NULL
)时会发生这种情况。但是,如果我想在没有segfault的情况下打印我的数组,我需要这个NULL
。
所以,首先我想知道我的代码是否在某处出错?
我试图在我的Linux计算机(Ubuntu 16.04)上运行此代码,似乎没有问题。
答案 0 :(得分:2)
result = pd.Series(result)
如果阵列中还需要两个额外的元素,那就是
malloc(sizeof(char*) * ft_length(environ) + 2)
或使用malloc(sizeof(char*) * (ft_length(environ) + 2));
:
calloc
另外
calloc (ft_length(environ) + 2, sizeof(char*));
是每个人似乎陷入的另一个陷阱。你将指针值分配给env[x] = (char*)malloc(sizeof(char) * 4);
env[x] = "ccc\0";
,然后立即后悔并为其分配另一个指针值,忘记第一个,在进程中创建内存泄漏,并使你的env[x]
env
不可能,因为新字符串未指向动态分配的内存。这尤其令人困惑,因为您似乎正确地(即使有很多冗余)将字符串复制几行。
free
由于您的代码可以在两个地方动态分配字符串的副本,因此您可能希望将此代码转换为函数,或者使用现有的(尽管是非标准的)函数env[x] = malloc(4); // sizeof(char) is always one; casting not needed
// also see below
strcpy (env[x], "ccc"); // of course no `\0` is needed
。这一点特别重要,因为否则无法复制字符串文字。
strdup
假设长度。如果文字会改变怎么办?
env[x] = malloc(4);
strcpy (env[x], "ccc");
如果有人更改了一个字面并忘记了另一个字面怎么办?
env[x] = malloc(strlen("ccc")+1);
strcpy (env[x], "ccc");
这有效,但你有一个额外的行来声明一个变量。这听起来不是很多,但为什么呢?
const char ccc[] = "ccc";
env[x] = malloc(sizeof(ccc));
strcpy (env[x], ccc);
看起来更好,保持更好。
如果你自己写env[x] = strdup("ccc");
,请不要这样做
strdup
而是
out = (char*)malloc(sizeof(char) * strlen(in) + 1);
bzero(out, strlen(in));
strncpy(out, in, strlen(in));
out = malloc(strlen(in) + 1);
strcpy(out, in);
是多余的,因为它会将bzero
将在下一行用非零值覆盖的字节精确归零。 strcpy
+ strncpy
组合明显错误,因为它不会终止目标字符串。 strlen
是正确但多余的,因为它与普通strncpy(out, in, strlen(in)+1)
完全相同。