使用 char 数组进行 C 结构初始化
Posted
技术标签:
【中文标题】使用 char 数组进行 C 结构初始化【英文标题】:C struct initialization with char array 【发布时间】:2013-09-28 19:20:01 【问题描述】:我有一个 C 结构定义如下:
struct Guest
int age;
char name[20];
;
当我创建了一个Guest
变量并使用以下内容对其进行初始化时:
int guest_age = 30;
char guest_name[20] = "Mike";
struct Guest mike = guest_age, guest_name;
我收到关于第二个参数初始化的错误,它告诉我guest_name
不能用于初始化成员变量char name[20]
。
我可以这样做来初始化所有:
struct Guest mike = guest_age, "Mike";
但这不是我想要的。我想通过变量初始化所有字段。如何在 C 中做到这一点?
【问题讨论】:
您不能复制数组。使用std::string
。
我知道我可以使用std::string
。但是如果我想坚持使用 C 风格的 char 数组呢?
您说的是 C 或 C++。现在你说 C。
我应该说清楚。我想在 C char 数组中执行此操作。编辑了我的问题。有可能吗?
【参考方案1】:
其实你可以静态初始化这个结构体:
struct Guest
int age;
char name[20];
;
Guest guest = 30, 'M','i','k','e','\0';
数组的每个元素都必须明确设置,而这不能使用 c-strings 来完成。如果结构是用 char* 名称定义的,那么我们可以这样做:
struct Guest
int age;
char* name;
;
Guest guest = 30, "Mike";
【讨论】:
【参考方案2】:mike.name 是一个字符数组。您不能仅使用 = 运算符来复制数组。
相反,您需要使用strncpy
或类似的东西来复制数据。
int guest_age = 30;
char guest_name[20] = "Mike";
struct Guest mike = guest_age ;
strncpy(mike.name, guest_name, sizeof(mike.name) - 1);
您已将此问题标记为 C++,因此我想指出,在这种情况下,您几乎应该始终使用 std::string
而不是 char[]
。
【讨论】:
谢谢。所以在struct的声明中使用C struct初始化来初始化char数组成员是不可能的吧? 一般来说strncpy
使用时需要添加空终止符。
在这个例子中,我用括号符号初始化了struct
,它将指定成员之后的所有内容归零。然而,在 strncpy 调用中有一个相关的错误,以及一些错别字,我很惊讶没有人关注。 ;) 谢谢【参考方案3】:
您可以在 C 中静态分配具有固定 char[] 数组的结构。例如,gcc 允许以下操作:
#include <stdio.h>
typedef struct
int num;
char str[];
test;
int main(void)
static test x=.num=sizeof("hello"),.str="hello";
printf("sizeof=%zu num=%d str=%s\n",sizeof(x),x.num,x.str);
return 0;
它做了正确的事情(虽然要注意 sizeof(x):它在我的机器上返回 4;而不是静态分配的总内存的长度)。
这对于从堆栈分配的结构不起作用,您可能会怀疑。
【讨论】:
(1) 我不认为 GCC 坏到不能为sizeof("hello")
返回 6 — 但也许你指的是 sizeof(x)
,在这种情况下 4
是正确的回答。 (2) 这称为结构中的灵活数组成员。 (3) 初始化是一个 GCC 扩展,尽管您必须调用 -pedantic
才能让它在 static test x=.num=sizeof("hello"),.str="hello";
处“公开:initialization of a flexible array member [-Werror=pedantic]
— 编译器选项 gcc -O3 -g -std=c11 -Wall -Wextra -Werror -pedantic xx37.c
”。我在 Mac OS X 10.11.6 上使用 GCC 6.1.0。
@JonathanLeffler 这个扩展是否也扩展了分配的空间以允许初始化器适应?
@M.M:我不确定,但我认为是的。我没有很好地阅读 x86_64 汇编程序,但 size xx37.o
的输出(其中 xx37.c
包含此答案中的代码副本)给出了大小为 10 的数据部分,它对应于 x
的大小应该是如果它被分配为一个单元(这是必须处理 FAM 的方式)。所以,我推断 GCC 正确地完成了这项工作(考虑到它确实做到了,这并不奇怪),但我愿意证明我在这方面是错误的。
虽然这个成语确实是 gcc 扩展 [1],但我在 ISO C99 [2] 中没有看到任何禁止它的内容。 [1] gcc.gnu.org/onlinedocs/gcc-4.3.5/gcc/Zero-Length.html [2] ISO/IEC 9899 第 6.7.8 节第 20、22 段。如果您想复习 [],第 31 段也值得一看。【参考方案4】:
mike.name
是结构内的 20 字节保留内存。 guest_name
是指向另一个内存位置的指针。通过尝试将guest_name
分配给结构的成员,您尝试了一些不可能的事情。
如果您必须将数据复制到结构中,您必须使用memcpy
和朋友。在这种情况下,您需要处理 \0
终止符。
memcpy(mike.name, guest_name, 20);
mike.name[19] = 0; // ensure termination
如果你有\0
终止的字符串,你也可以使用strcpy
,但由于name
的大小是20,我建议strncpy
。
strncpy(mike.name, guest_name, 19);
mike.name[19] = 0; // ensure termination
【讨论】:
因此,我无法使用Guest mike = ...
形式初始化此结构的其他成员。如果我有更多字段,我必须使用mike.age = ...,; mike.id=...; memcpy(mike.name, guest_name, 20);
。
如果你事先不知道字符串(在编译时),是的。以上是关于使用 char 数组进行 C 结构初始化的主要内容,如果未能解决你的问题,请参考以下文章
具有 char 数组的 C++ 结构以不寻常的方式初始化为零