1

以下は、char の値を出力する C コードですが、予期しない結果が得られます。コードは

#include<stdio.h>

main()
{

  char sendBuffer[1000];
  float count;
  int i;
  for(count=1.5;count<=2.5;)
  {
   for(i=0;i<=15;)
   {
     sendBuffer[0]=count+48;
     sendBuffer[1]='a';
     sendBuffer[2]='b';
     sendBuffer[3]='c';
     sendBuffer[4]=i+48;
     sendBuffer[5]='\0';
     printf("%s\n",sendBuffer);
     i=i+5;
    }
   count=count+0.5;
  }
}

私が得ている結果は次のとおりです。

1abc0
1abc5
1abc:
1abc?
2abc0
2abc5
2abc:
2abc?
2abc0
2abc5
2abc:
2abc?

一方、私は次のようなものを期待していました

1.5abc0
1.5abc5
1.5abc10
1.5abc15 

等々。Cのchar配列に整数値と浮動小数点値を格納する方法を誰か教えてもらえますか?

4

3 に答える 3

8

あなたが得ている答えが問題に答えているのはわかりますが、説明はしません。見た目からすると、適切な説明を使用できるので、何が起こっているのですか:

C の型

int異なる型 ( 、charfloatdouble) が異なるサイズのメモリを使用することを理解する必要があります。C では、acharは常に 1 バイトを占めると見なされ、-127 から 128 の範囲です。 (unsigned charは 0 から 255 になります。) ints は 4 バイトを占め、その範囲は -2M から 2M - 1 です。 . floatそしてdouble、それぞれ 4 バイトと 8 バイトを取り、巨大な範囲を持ちますが、精度は限られています。(詳細については、「c 型の範囲」を検索するだけで、Stack Overflow のこれらのリンクを含む多くの情報が見つかります。これらのリンクからも適切な説明が得られます:データ型の範囲の定義、保証された最小サイズ/範囲C データ型の)。

また、char バージョンを取得するために桁に 48 を追加することを知るのに十分な ascii を知っていますが、近くに ascii テーブルがあることを確認してください。便利なことに、 http://www.asciitable.comで見つけることができます。

また、コンパイラが 1 から別の変換に最善を尽くすことも理解する必要がありますが、 afloatを anにキャストするなど、場合によってintは、明示的に変換しない場合、コンパイラは少なくとも警告を発行する必要があります。

文字列は C の型として存在しません。代わりに、配列に出力します。他の答えは、それを行う方法を教えてくれます。彼らのコードが行っていることは、必要な値を文字配列に出力することです。必要なのはこれだけです。

あなたのコードが何をしているか

それでは、現在のコードが何をしているか見てみましょう。

まず、簡単なサイドバー: ループを実行しているときはfor、ループ自体にインクリメントを配置するのが最善です。

for(count=1.5;count<=2.5;count=count+0.5)
{
  for(i=0;i<=15;i=i+5)

より標準化されます。

さて、最初の行はsendBuffer[0]=count+48;. 何が起こるかは次のとおりです。

  1. 1.5 から始まるカウントに 48 を足すと、最初の数は 49.5 になります。
  2. コンパイラは自動的に afloatを anintに変更しますが、警告が表示されるはずです。これは、値を切り捨てて 49.5 を 45 に変更することによって行われます。
  3. (int)49その後、同じ値に変わります(char)49が、4 ではなく 1 バイトを使用します。Ascii 49 は '1' であるため、これがたまたま必要な数値になります。
  4. コンパイラは残りの float に対して何もしません。この値に sendBuffer[1] または [2] を設定することはありません。

次の 3 行では、文字列の 2 番目、3 番目、4 番目の文字をabc. 最初の行で完全な float 値を に設定したとしても、sendBuffer上書きされてしまいます。

最後の行は、0、5、10、15 になる i を取り、それを 48 に追加しfloatます。最初に ascii 48 ('0') を検索し、次に ascii 53 ('5') を検索します。が 10 の場合i、int 58 を受け取り、それを文字に変換します (再び、4 バイトから 1 バイトに変更します)。ascii 58 を印刷すると「:」になり、ascii 63 を印刷すると「?」になります。そして、それがあなたの出力がそのようになった方法です。

可能な解決策

最後に、与えられた解決策について一言:

結果を出力するだけなので、 no は必要ありsendBufferませんsnprintf。単に使用する

printf("%.1fabc%d\n", count, i);

で十分だったでしょう。

ただし、関数の printf ファミリーが何をするかを考えるのは有益です。効率は劣りますが、いくつかsnprintfの s を使用して、何をしているかを見てみましょう。

int index = 0;
index = snprintf(&sendbuf[index], sizeof(sendbuf) - index, "%.1f", count);
index += snprintf(&sendbuf[index], sizeof(sendbuf) - index, "abc");
index += snprintf(&sendbuf[index], sizeof(sendbuf) - index, "%d", i);
sendbuf[index++] = '\n';
sendbuf[index] = '\0';

これが何をするか*printfは、複数の引数を渡した場合と同じです: 書いた量を追跡し、それを使用して次の部分をどこに書いているかを伝えます。

ご存じない方のために説明すると、a += b構文は の省略形ですa = a + ba++は、「a の値を指定してから、それをインクリメントする」という意味です。

したがって、私のコードの 2 行目は、0 の位置から始まる float 値を sendbuf に出力します。 *printfは常に印刷された文字数を返すため、この例では常に 3 文字を印刷し、3 に設定indexします。

次の行は文字列 abc を sendbuf に書き込み、位置 3 から開始し、その次の行は値をi位置 6 に出力します。最後に、新しい行に \n を追加し、最後の行はヌル ターミネータです。index++インデックスはもう気にしないので入れません。わざわざインクリメントする必要はありません。整数配列ではなく char 配列を扱っていることをプログラマーに思い出させるため\0です。\0

繰り返しますが、これらすべての行が必要というわけではありませんが、問題の一部が何を理解しているように見えたのでprintf、役立つと思いました.

于 2013-07-25T14:30:58.500 に答える