3

私は Kernighan と Ritchie の C の本に従っていますが、文字列を扱うのに苦労しています。

次のコードでは、ユーザーから入力された文字列に、ヌル ( ) 文字getchar()の前に追加のジャンク文字が含まれているように見えます。\0

コードは次のとおりです。

#include <stdio.h>
main() {

        char s[200];
        int c, i;

        printf("Enter input string:\n");
        for (i = 0; ( c = getchar()) != '\n'; i++) {
                s[i] = c;
        }   

        printf("Contents of input string:\n");
        for (i = 0; s[i] != '\0'; i++) {
                printf("%d: (%d) = ", i, s[i]);
                putchar(s[i]);
                printf("\n");
        }   

        return 0;
}

文字配列の各要素を 1 つずつ示す出力を次に示します。これは次のことを意味します。

Array_element: (ascii_number) = ascii_character

0: (72) = H
1: (101) = e
2: (108) = l
3: (108) = l
4: (111) = o
5: (32) =  
6: (87) = W
7: (111) = o
8: (114) = r
9: (108) = l
10: (100) = d
11: (33) = !
12: (-1) = ?
13: (127) = 

要素12と13が見えますか?(要素 14 はおそらくヌル文字です\0)。ウィスキー。タンゴ。フォックストロット。

そして、これが本当のキッカーです。文字配列を200 ではなく100 要素のみを持つように定義すると、出力は合理的になります。たとえば、単純に置き換えると

char s[200]char s[100]

出力は次のようになります。

0: (72) = H
1: (101) = e
2: (108) = l
3: (108) = l
4: (111) = o
5: (32) =  
6: (87) = W
7: (111) = o
8: (114) = r
9: (108) = l
10: (100) = d
11: (33) = !
12: (9) = 

(改行文字がどこにあるのかまだわかりません。アスキー文字 #10 ではないですか?)

繰り返しますが、ウィスキー タンゴ フォックストロットです。

ここで何が起こっているのですか?

アップデート

したがって、以下の回答のように、文字配列のサイズを 100 要素または 200 要素に設定したときの出力の違いは、本当に偶然の一致です。初期化されていないメモリでガベージ/ノイズをいじっているだけです。

\0答えが鋭く示すように、配列を明示的に終了する必要があります。

4

3 に答える 3

7

この演習で、入力後の文字列にヌル文字が存在すると予想される場合は、自分で追加する必要があります。

C の変数と配列は初期化されていないため、奇妙な文字が観察れます。ランダムに配置された null 文字を含む可能性のあるガベージ値を含めることができます。

配列のサイズを変更すると、異なる出力が観察される場合がありますが、合理的、予想される、または再現可能な動作は期待しないでください。これは未定義です。これらの配列の値は何でもかまいません。

于 2012-08-23T01:48:41.943 に答える
3

\0次のチェックを文字列の最後で停止させるには、受け取った文字列の最後にヌル ターミネータ ( ) を配置する必要があります。

そうしないと、ループがガベージ メモリに入ります。

于 2012-08-23T01:48:32.043 に答える
1

s[i] = '\0';キーボード入力の読み取りが終了したら、プログラムに追加する必要があります。そうしないと、文字列の形式が崩れます。'\0' 終了文字は含まれません。

変更されたコードは次のとおりです。

#include <stdio.h> main() 
{         
 char s[200];        
 int c, i;        
  printf("Enter input string:\n");       
  for (i = 0; ( c = getchar()) != '\n'; i++)
 {               
  s[i] = c;        
 }     

s[i] = '\0';  //here, I added the '\0' character. (the only change i made in your code.)

  printf("Contents of input string:\n");      
   for (i = 0; s[i] != '\0'; i++) {        
         printf("%d: (%d) = ", i, s[i]);  
               putchar(s[i]);            
     printf("\n");       
  }           
  return 0;
 } 

2 - 文字列 s のサイズは 200 であるため、バッファ オーバーフローに注意する必要があります : for (i = 0; ( c = getchar()) != '\n' && i < 199 ; i++)(最後の文字は\0)。入力文字を読み取るときに、文字列のサイズを調整することもできます。

int size = 200;
char* s = malloc(size);
 for (i = 0; ( c = getchar()) != '\n'; i++)
 {  
   if(i >= size)
   {
      char* tmp = malloc(size + 200);
      memcpy(tmp , s , size);
      size += 200;
      free(s);
   }   

   s[i] = c;        
 }  

そして、コードの最後に、次を追加します。

free(s);// 最後に作成された文字列が不要になったときに解放します。

于 2012-08-23T06:48:21.093 に答える