2017-01-18 34 views
-1

我想創建一個C程序,可以從鍵盤輸入中讀取'n'個全名並打印它們。我試圖使用fgets(),但無法弄清楚如何掃描多個條目,所以我最終編寫了下面的代碼。掃描並打印列表中的全名(C語言)

問題是,它將名稱作爲輸入並僅打印垃圾值。

#include <stdio.h> 
#include <conio.h> 
#include <string.h> 

int main() 
{ 
    int n,i; 
    char name[64][64],sur[15][15],a[3]; 

    printf("How many names? "); 
    scanf("%d",&n); 
    printf("\nEnter names:\n"); 

    for(i=0;i<n;i++) 
    { 
     scanf("%s%s",name[i],sur[i]); 
    } 

    for(i=0;i<n;i++) 
    { 
     a[3]=' '; 
     strcat(name[i],a); 
     strcat(name[i],sur[i]); 
    } 

    printf("\nThe names are:\n"); 
    for(i=0;i<n;i++) 
    { 
     printf("%s",name[i]); 
    } 
    getch(); 

    return 0; 
} 
+1

'a [3] ='';'在你的代碼中是problamatic。使用'a [0]'並將'a [1]'設爲NULL – 16tons

+0

打開編譯器警告(通常通過添加'-Wall')。他們會抓住像'a [3] ='''這樣的問題。 – Schwern

回答

1

@16tons addresses the most obvious issue,但有潛伏的記憶問題。 scanfstrcat調用容易受到buffer overflows的影響。他們不會僅限於分配的內存。

for(i=0;i<n;i++) 
{ 
    scanf("%s%s",name[i],sur[i]); 
} 

這將試圖把任何數量的輸入字符到name[i]sur[i]這隻能分別持有的63首14個字符的字符串。這意味着Hubert Wolfe­schlegel­stein­hausen­berger­dorff將導致name[i]包含"Hubert\0"sur[i]將包含"Wolfe­schlegel­st"(無空字節),其餘將溢出到相鄰的內存導致問題。由於缺少空字節,試圖使用sur[i]作爲字符串將導致讀取它後面的任何垃圾。

strcat

for(i=0;i<n;i++) 
{ 
    a[0]=' '; 
    a[1]='\0'; 
    strcat(name[i],a); 
    strcat(name[i],sur[i]); 
} 

如果name[i]已滿,增加了年底便會溢出它的緩衝區塗鴉在相鄰的內存,造成怪異的問題。

How many names? 3 

Enter names: 
Hubert Wolfeschlegelsteinhausenbergerdorff 
Hubert Wolfeschlegelsteinhausenbergerdorff 
Hubert Wolfeschlegelsteinhausenbergerdorff 

The names are: 
Hubert WolfeschlegelstWolfeschlegelstWolfeschlegelsteinhausenbergerdorff WolfeschlegelstWolfeschlegelsteinhausenbergerdorff 
gerdorff WolfeschlegelstWolfeschlegelsteinhausenbergerdorff 
Hubert Wolfeschlegelsteinhausenbergerdorff 

爲了避免這種情況,scanf必須限制在緩衝區的大小。當使用strcat時,要添加的字符串必須有足夠的空間來接受新字符。

由於您使用name[i]來存儲名字和全名,所以重要的是限制名字的大小以便最後留出空間。由於sur[i]可以有14個字符,而name[i]可以有63個,即63 - 14或49.不要忘記空間! 48.

for(i=0;i<n;i++) 
{ 
    scanf("%48s%14s",name[i],sur[i]); 
} 

這確保scanf將讀取不超過48個字符到name[i](使用,因爲空字節的49個字節)和不超過14到sur[i](使用15)。

現在你的strcat是安全的。我們知道肯定有name[i]有空間接受空間和sur[i]結束。 48(最大字符數已經在name[i])+ 1(空格)+14(最大在sur[i])+1(空字節)= 64。

雖然你的技術可以節省一些內存,它的安全有單獨givensurname變量,連接成一個新的name變量。然後,你需要做的就是將given,surname的大小加起來,並且知道空間應該是多大的namescanf的限制只是緩衝區的大小。不需要記住,如果surname變得更大,則一個變量必須保留一些額外的空間,也不必重做所有這些計算(或者更可能忘記重做它們)。

爲了您的特定目的,strcat是不必要的。 printf可以做到更安全。

printf("\nThe names are:\n"); 
for(i=0;i<n;i++) 
{ 
    printf("%s %s\n",name[i], sur[i]); 
} 

將一串變量打印到流中比將它們連接在一起然後將其打印出來更安全,更容易和更快速。

+1

你說得對,我沒有考慮內存管理。感謝您的建議。我會相應地編輯程序。 –

0

正如評論所說,使用a[0]空間和讓a[1]空。下面的代碼工作。

int main() 
{ 
    int n,i; 
    char name[64][64],sur[15][15],a[3]; 

    printf("How many names? "); 
    scanf("%d",&n); 
    printf("\nEnter names:\n"); 

    for(i=0;i<n;i++) 
    { 
     scanf("%s%s",name[i],sur[i]); 
    } 

    for(i=0;i<n;i++) 
    { 
     a[0]=' '; 
     a[1]='\0'; 
     strcat(name[i],a); 
     strcat(name[i],sur[i]); 
    } 

    printf("\nThe names are:\n"); 
    for(i=0;i<n;i++) 
    { 
     printf("%s\n",name[i]); 
    } 
    getch(); 

    return 0; 
} 
+0

非常感謝。我明白如何解決這個問題。 –

+1

不需要'a','strcat(name [i],「」)'可以正常工作。請注意'scanf'和'strcat'仍然包含緩衝區溢出的可能性。 [看我的回答](http://stackoverflow.com/a/41727793/14660)。 – Schwern