我遇到嵌套结构的问题。程序初始化结构数组,其中一个结构成员是另一个结构。该程序检查是否给出了第二个名称,并以表格
显示完整数据`Last_name, First name, (First character of the second name if it had been given). -- number
问题在于我不知道为什么但是某种方式将第一个名字添加到PESEL成员的末尾并作为输出我们得到了
Jordan, Michael J. -- 65092301159Michael
T, Thomas -- 98501233151Thomas
Christie, Agatha S. -- 25941325923Agatha
而不是
Jordan, Michael J. -- 65092301159
T, Thomas -- 98501233151
Christie, Agatha S. -- 25941325923
这是一个代码,它使用C99指定初始化功能:
#include <stdio.h>
#include <string.h>
#define SIZE1 11
#define SIZE2 81
#define N 3
struct person
{
char name[SIZE2];
char second_name[SIZE2];
char last_name[SIZE2];
};
struct one
{
char PESEL[SIZE1];
struct person data;
};
void show(struct one *, int);
int main(void)
{
struct one personal_data[N] =
{
{
"65092301159",
{
"Michael",
"James",
"Jordan"
}
},
{
"98501233151",
{
.name = "Thomas",
.last_name = "T"
}
},
{
"25941325923",
{
"Agatha",
"Sam",
"Christie"
}
}
};
int i;
for(i = 0; i < N; i++)
{
if(strlen(personal_data[i].data.second_name) != 0)
show(&personal_data[i], 1);
else
show(&personal_data[i], 0);
}
return 0;
}
void show(struct one *pt, int flag)
{
if(flag)
printf("%s, %s %c. -- %s\n",pt->data.last_name, pt->data.name, pt->data.second_name[0] , pt->PESEL);
else
printf("%s, %s -- %s\n",pt->data.last_name, pt->data.name , pt->PESEL);
}
答案 0 :(得分:4)
PELSEL
的大小为11个字符,您在初始化时会在其中放入包含11个可见字符的字符串。这不会为空终止符[1]('\0'
)留出空间,导致所有C字符串函数溢出,直到它们在内存中遇到值为'\0'
的char,这恰好是第一个名字的结尾(虽然如果你有一个81个字符的名字,它很可能会进一步超出,可能会受到保护的内存在极端情况下崩溃你的程序)。将SIZE2
增加到12可以解决此问题。
请记住:C字符串总是需要一段至少比实际可见字符数大一个的内存部分。
[1]严格地说,它实际上是在为第一个名字的第一个字符保留的空间中写入空终止符,然后在写入第一个名字段时立即覆盖它。在这种情况下相当无害,但在不太幸运的结构布局中可能非常有害。
答案 1 :(得分:4)
你输入一个溢出大小为11 * sizeof(char)
的缓冲区的名称,所以你必须增加缓冲区大小以避免这些类型的问题。
放入的字符数必须小于缓冲区的大小。
答案 2 :(得分:3)
C样式字符串以\0
字符结尾。当您使用printf(“%s”,..)打印出字符串的值时,它将逐个打印出字符,直到它符合'\ 0'字符。
因为您的结构类型是POD类型,这意味着结构的成员按顺序放在内存中。您的嵌套类的内存模型是:
char PESEL[11]] -> char name[81] -> char second_name[81]...
名称[81]与PESEL [11]字符串相邻。因此,当您打印PESEL时,它基本上就像:
char * c= pt->PESEL;
while(*c != '\0')
{
printf("%c",*c);
c++;
}
在您的情况下,您只为PESEL分配11个字节。 '\ 0'字符用于分隔PESEL,名称将由名称的第一个字符覆盖。上面的进程不会停止,直到它运行到name变量的'\ 0'字符。这就是为什么你的程序在PESEL之后打印出额外的名字。
这意味着您可以将10个字符放入数组 AT MOST 但不是11个。您需要将#define SIZE1 11
更改为#define SIZE1 12
,所有字符都将被设置。