2013-12-19 27 views
3

我有一个嵌套结构的问题。程序初始化结构数组,其中结构的一个成员是另一个结构。如果第二个名字给该程序检查,并提出在形式上完全数据嵌套结构的成员以某种方式附加到结构的前一个成员

`Last_name, First name, (First character of the second name if it had been given). -- number 

的问题是,我不知道为什么,但不知何故,名字被添加到PESEL构件的端部和输出我们越来越

Jordan, Michael J. -- 65092301159Michael 
T, Thomas -- 985Thomas 
Christie, Agatha S. -- 25941325923Agatha 

代替

Jordan, Michael J. -- 65092301159 
T, Thomas -- 985
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" 
     } 
    }, 
    { 
     "985", 
     { 
     .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); 
} 
+1

sizeof(“65092301159”)是12. – BLUEPIXY

回答

4

PELSEL的大小为11个字符,并且在初始化时将11个可见字符放入其中。这不会为空终止符[1]('\0')留下空间,导致所有C字符串函数溢出,直到它们在内存中碰到一个值为'\0'的字符,这恰好是名字的结尾(尽管如果你有81个字符的名字,它可能会进一步超限,可能会导致受保护的内存在极端情况下导致程序崩溃)。增加SIZE2到12应该解决这个问题。

请记住:C字符串总是需要一段内存至少比实际可见字符数大一个。

[1]严格来说,它实际上是在为名字的第一个字符保留的空间中写入空终止符,然后在写入名字字段时立即覆盖它。在这种情况下,这是相当无害的,但是在不那么幸运的结构布局中可能会非常有害。

+0

“*在这种情况下相当无害......”但仍然会引发未定义的行为。不太好。 – alk

4

你把一个名字溢出缓冲区的大小为11 * sizeof(char),所以你必须增加缓冲区大小以避免这些类型的问题。

放置的字符数量需要小于缓冲区的大小。

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++; 
} 

在你的情况,你只能分配11个字节PESEL。用来分隔PESEL的'\ 0'字符将被名称的第一个字符覆盖。上层进程不会停止,直到它运行到名称变量的'\ 0'字符。这就是为什么您的程序在PESEL之后打印出额外名称的原因。

,这意味着你可以把10个字符到数组最多但不11.你需要改变#define SIZE1 11#define SIZE1 12,都将被设置。

+0

Minor nitpick:C风格*字符串*以'\ 0'结尾。没有什么说你需要用'\ 0'来结束* char数组*。如果你只是因为某种原因想要一个字节数组(如果有足够好的字符,比如'char [4]'来编码truecolor RGBA值),那么有一个没有空终止符的char数组是完全有效的。如果你打算把它当作一个字符串(即使用strcat,“%s”,strcpy等),那么它就很重要。 – LinearZoetrope

+0

@Jsor是的,只有当你的函数基于这个空终止符时才重要。 :) –

+0

@ richard.g:为什么不把这个(显着的)添加到你的答案? – alk