2017-07-26 5 views
-1

私はUbuntuの14.04とgccを使用しています4.8.4C:のscanf文で文字を読む返しごみ値

#include<stdio.h> 
void main() 
{ 
    char c[15]; 
    printf("enter a character\n"); 
    scanf("%15c",c); 
    printf("%s\n",c); 
} 

出力:

enter a character 
qwertyuiopasdfghjkl 
qwertyuiopasdfg 

私は15以上の文字で、上記プログラムを実行します入力として、出力はガベージ値を返しません。しかし、私は以下のプログラムを実行するとき:

#include<stdio.h> 
void main() 
{ 
    char c[5]; 
    printf("enter a character\n"); 
    scanf("%5c",c); 
    printf("%s\n",c); 
} 

私は5文字以上の入力を与えています。ガベージ値を含む出力を返します。

+1

問題は、 '%15c'と'%5c'で読み取られた値がヌルで終了していないため、両方のコードに未定義の動作があることです。 –

+0

'main()'の戻り値の型は常に 'int'であり、決して' void'ではありません。これがここの中心的な問題ではない –

+0

@JohnBollinger中心的な問題ではありませんが、Cでは 'main()'を "または他の実装定義の方法で許可します。" C11§5.1.2.2.11 – chux

答えて

3

%cディレクティブは、個々の文字および文字配列を読み込むためのものですが、Cの文字列として特に使用される配列のためのものではありません。特に、入力から転送された最後の文字の後にヌル文字を格納しません。

したがって、scanf()コールは両方とも完全に正常ですが、その後のprintf()コールは正しくありません。どちらの場合も、cで指定された配列の内容はNULLで終端されていないため、%sディレクティブを使用して配列を出力しようとすると、scanf()は配列の最後を読み取って未定義の動作をします。あるケースでは未定義の動作があなたにとって合理的であり、他のケースでは未定義の動作は無関係であるということです。

あなたは、終わっていない文字列のような配列を使って作業することをお勧めします。ターミネータに十分な大きさの配列を作成し、実際にターミネータが終端されていることを確認する方がよいでしょう。あなたはprintf()を経由して、おそらく終端されていないか、終端されていない文字配列を印刷する必要がある場合しかし、その後、印刷することができる文字数を制限するディレクティブの精度フィールドを使用してください:

#include<stdio.h> 

int main(void) { 
    char c[5]; 
    printf("enter a character\n"); 
    scanf("%5c", c); 
    printf("%.5s\n", c); 
} 
+0

いいえ、@chux。フィールド幅にかかわらず、 '%c'指示文は' printf() 'に対応する' int'引数を期待し、 'unsigned char'に変換して出力します。 'char *'は対応する引数として受け入れられません。もしそれが渡された場合、結果としての未定義の振る舞いは、ポインタ値の一部を 'unsigned char'として解釈する行に沿って、指し示された文字。 –

+0

はい、もちろん、あなたは正しいです。 「60年代を覚えていれば、そこにはいなかった」瞬間 – chux

0

あなたの入力が5つ以上ある場合あなたのプログラムは5文字を完全に表示し、文字列を印刷する間に '\ 0'文字まで印字するため、ガベージ値の表示を開始します。そして、最後に '\ 0'が存在しなければ、ゴミを印刷します。

1

文字列にscanfの形式指定が間違っています。

#include <stdio.h> 

int main(void) { 
    char c[15]; 
    printf("enter a string\n"); 
    scanf("%14s", c);    // change %c to %s 
    printf("%s\n", c); 
    return 0; 
} 

長さの制限がnulターミネーターのための空間を可能にするために、アレイのサイズより1つ少ないことに留意されたいです。

関連する問題