2013-12-19 28 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