C语言 分配 char*[] 结构数据元素会发出警告



我有一个结构,其中包含 char*[] 类型的值。它的定义是这样的:

struct background_element
{
pid_t pid;
int number;
char *full_command[MAX_ARGS];
};

我还有一个全局 char*[] 变量,args。

char *args[MAX_ARGS];

我尝试创建一个结构background_element类型的新变量,并像这样分配full_command值:

struct background_element bg_elem = { .pid = child, .number = num_background, .full_command = args};

但是,将 args 分配给 .full_command 似乎会抛出以下警告:"警告:从不兼容的指针类型初始化。

我尝试使用 strcpy,但由于它们不是 char[] 而是 char*[],它似乎不起作用。我有点不知道如何分配这个。任何帮助将不胜感激。

正如@user3386109所说,这是因为char *full[MAX_ARGS]无法分配。从这里开始有两条路径,具体取决于你的方案。如果 args 不会被其他代码或释放其字符串元素修改,那么我们可以像这样将full_command元素指向它们:

struct background_element bg_elem = {.pid = child, .number = num_background};
for (unsigned int i = 0; i < MAX_ARGS; i++) {
bg_elem.full_command[i] = args[i];
}

但是,如果您需要复制字符串,则必须使用 malloc 为字符串创建空间,然后 strcpy 将数据复制到:

for (unsigned int i = 0; i < MAX_ARGS; i++) {
int str_len = strlen(args[i]);
bg_elem.full_command[i] = malloc((str_len + 1) * sizeof(char));
strcpy(bg_elem.full_command[i], args[i]);
}

以上为循环先:

  1. 获取第 i 个参数的长度
  2. 为 bg_elem.full_command 的第 i 个指针分配足够的内存
    • 我们需要str_len + 1因为我们需要空字符的空间
  3. 将字符串从参数复制到 bg_elem.full_command

最后,如果您需要从 args 复制字符串,请不要忘记遍历并在完成后释放该内存。

for (unsigned int i = 0; i < MAX_ARGS; i++) {
free(bg_elem.full_command[i]);
}

注意:如果您需要将要复制的内存归零,calloc 会更好。但是,由于我们使用strcpy,malloc工作得很好。

C 中的数组对象仅限于两种初始值设定项:

  1. {}封闭的初始值设定项,即一对{},其中包含数组元素的单独初始值设定项
  2. char []数组的字符串文本。

初始值设定项不属于任何这些类别。它是无效的。您不能用另一个数组初始化一个数组(上面的情况 2 除外(。

正式地,您可以明确拼写出来

struct background_element bg_elem = 
{ 
.pid = child, 
.number = num_background, 
.full_command = { args[0], args[1], /* ... and so on */ }
};

但这并不是一个真正可行的方法。一个更好的主意是

struct background_element bg_elem = 
{ 
.pid = child, 
.number = num_background
};
static_assert(sizeof bg_elem.full_command == sizeof args, "");
memcpy(bg_elem.full_command, args, sizeof args);

尽管它可能会受到"双重初始化"问题的影响。

附言您尝试执行的操作称为初始化,而不是赋值。赋值在 C 中是一件非常不同的事情。

char *args[MAX_ARGS];

args是一组MAX_ARGS指针。args本身指向第一个指针的内存。args保存第一个指针所在的内存地址。args[0]是第一个指针的值。args[0][0]的意思是,我们转到第一个指针的内存,然后转到该指针指向的内存地址,然后获取该内存地址中第一个字节的值。

char *full_command[MAX_ARGS];

现在,这也是一个MAX_ARGS指针数组。full_command指向字节长度为MAX_ARGS * sizeof(char*)的内存区域。full_command[0]是该内存区域内第一个指针的值。
现在让我们尝试分配:

full_command = args;

现在我们获取args中第一个指针的内存地址值,并将该值分配给full_command变量中。full_command的内存丢失,任何其他句柄都无法再访问它。现在args[0] = smth只有当full_command[0] = smth.full_command指向args指向的内存区域。
要复制数组值,您需要复制数组的每个值:

for (size_t i = 0; i < MAX_ARGS; ++i) { 
full_command[i] = args[i];
}

或使用内存:

memcpy(full_command, args, sizeof(full_command));

经过这样的操作full_command指向args的不同区域,两者都有sizeof(char*) * MAX_ARGS字节长。它们都拥有相同的价值观。
您需要为每个数组分配值:

struct background_element bg_elem = {
.pid = child, 
.number = num_background, 
.full_command = { args[0], args[1], args[2], ....<up until MAX_ARGS> }, 
};

这不是很有用,每次更改时都需要对其进行修改MAX_ARGS。所以使用memcpy或循环:

struct background_element bg_elem = {
.pid = child, 
.number = num_background, 
};
memcpy(bg_elem.full_command, args, sizeof(bg_elem.full_command));

你上面有很多正确答案。 简单地说:数组在 C 中很奇怪。 您可以初始化它们,但不能分配它们。 不能在结构初始值设定项中单独初始化它们,但可以将它们作为结构赋值的一部分进行分配。

#include <string.h>
int main(int argc, char *argv[])
{
char *test1 [3] = {"a", "b", "c"}; //initialization, not assignment; allowed
char *test2 [3];
//test2 = test1; //assignment of arrays; not allowed
memcpy(test2, test1, sizeof(test1)); //the right way to do a shallow array copy
}

而且,令人困惑的是:

#include <string.h>
struct _array_holder
{
char *array[3];
};
int main(int argc, char *argv[])
{
struct _array_holder test1 = {{"a", "b", "c"}}; //_struct_ initialization; allowed
struct _array_holder test2;
test2 = test1; //assignment of _structs_; allowed!
memcpy(&test2, &test1, sizeof(test1)); //also a fine way to copy a struct
}

所以,不幸的是,没有漂亮的方法(即优雅的语法(来做你想做的事。 这里至少是一种合理的自包含方法,可以使用结构中的数组赋值工作的事实,以防止每次要填充新结构时都必须编写几行初始化:

#include <string.h>
#include <unistd.h>
#define MAX_ARGS 5
struct background_element
{
pid_t pid;
int number;
char *full_command[MAX_ARGS];
};
//something akin to a constructor for the struct
struct background_element init_background_element(pid_t pid, int number, char *full_command[])
{
struct background_element ret = {.pid = pid, .number=number};
memcpy(ret.full_command, full_command, sizeof(ret.full_command));
return ret;
}
int main(int argc, char *argv[])
{
pid_t child = 1;
int num_background = 5;
char *args[MAX_ARGS] = {"a", "b"};
//use of the constructor-like thing
struct background_element bg_elem = init_background_element(child, num_background, args);
return bg_elem.pid;
}

最新更新