2017-01-18 3 views
-1

キーボード入力からフルネームのn個の数字を読み取り、それを印刷できるCプログラムを作成します。 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] = '';'はあくまでも予言的です。 '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]とのみ、それぞれ63と14文字の文字列を保持することができますsur[i]に入力任意の数の文字を入れしようとします。つまり、Hubert Wolfe­schlegel­stein­hausen­berger­dorffは、"Hubert\0"sur[i]が含まれ、"Wolfe­schlegel­st"(NULLバイトなし)を含み、残りは問題を引き起こす隣接メモリに流出します。ヌルバイトがないため、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は、(15を使用して)sur[i]にせいぜい14(49なぜならヌル・バイトのバイトを使用して)name[i]にせいぜい48個の文字を読まないことを保証します。

あなたのstrcatは安全です。 name[i]にスペースを受け入れるスペースがあり、最後にsur[i]があることがわかります。 48(最大文字は既にname[i]にあります)+ 1(スペース)+14(最大でsur[i])+1(ヌルバイト)= 64です。

あなたの技術はいくつかのメモリを節約できますが、それは新鮮なname変数に連結された別々のgivensurname変数を持ってくらい安全です。次に、givensurnameのサイズと、どれくらい大きいかを知るためのスペースを追加してください。namescanfの制限は、単純にバッファーのサイズです。 surnameが大きくなると、1つの変数が余分なスペースを残しておかなければならず、それらの計算をすべてやり直さなくてもよく(または、やり直すのを忘れる可能性が高い)ことを覚えておく必要はありません。あなたの特定の目的のために

strcat sが不要です。 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

関連する問題