0

私はその機能を使うべきではないことを知っています、そして私は気にしません。前回、strcat の仕様を確認したところ、最初の値を更新し、同じ値を返すという行に沿って何かが述べられていました。

さて、これは本当にばかげた質問です。本当にばかげた人に話しているように説明してほしいです。

なぜこれがうまくいかないのですか?

char* foo="foo";
printf(strcat(foo,"bar"));

編集: char[] と char* の違いがわかりません。255 文字の文字列を割り当てるにはどうすればよいですか?

編集 2: OK、OK、では char[number] はそのバイト数の文字列を割り当てますか? 理にかなっています。ありがとう。

編集 3: また、宣言せずに文字配列を使用するにはどうすればよいですか? char[255] として型キャストしますか?

編集 4: strcat((char[256])"foo","bar") はエラーを返します。私はCにうんざりしています。

編集 5: strcat((char[256])"foo",(char[])"bar") も同様です。

編集5:

char[256] foo="bar";

本当にスムーズ。「識別子が必要です」

4

4 に答える 4

3

いくつかの問題...

1. fooここでは定数です。文字列リテラルは変更できません。

2. の契約strcatは、最初のパラメーターが連結された文字列に適合するのに十分な大きさであることです。より現実的には、これを行うでしょう...

char foo[8] = "foo";  /* Note that buffer size is larger than the string... */

strcat(foo, "bar");

3. ご想像のとおり、これがどのように機能するかは、初心者には明らかではありません。これには理由があると私は言いstrcatます。潜在的に任意の長さのバッファーと対話するための優れた C インターフェイスは、これをより明確にします。strncatまたはstrlcatどのトラックサイズを見たいと思うかもしれません。

一般的に言えば、strcatファミリーを使用している場合は、何か間違ったことをしているということです。への各呼び出しstrcatは、文字列をトラバースして、末尾がどこにあるかを見つける必要があります。これらの操作をたくさん行っていると想像してみてください。O(n) ステップで簡単に実行できる何かが、文字列を繰り返しトラバーサルするために突然 O(n 2 ) になることを想像するのは非常に簡単です。文字列に繰り返し連結する必要がある場合は、文字列の現在の末尾へのポインターを維持し、そこからコピーを行う必要があります。

更新:この最後の提案を行う方法の例は次のとおりです...

struct string
{
   char *current_end;
   size_t bytes_remaining;
};

int
smart_concat(struct string *str, const char *tail)
{
   size_t new_length = strlen(tail);

   /* Do we have enough space?  (include NUL character) */
   if (new_length + 1 < str->bytes_remaining)
   {
      /* Evidently not... */
      return -1;
   }

   /* Copy the string...  (including NUL character) */
   memcpy(str->current_end, tail, new_length + 1);

   /* Update the pointer to the end of our string, and bytes remaining.. */
   str->current_end += new_length;
   str->bytes_remaining -= new_length;

   return 0;
}

次に、これを次のように使用できます。

struct string str;
char buffer[some_size];

/* Initialize the structure to point at our buffer... */
str.current_end = buffer;
str.bytes_remaining = sizeof(buffer);

/* Strictly speaking, you should check the return code for overflow... */
smart_concat(&str, "foo");
smart_concat(&str, "bar");

/* Print out the result: */
puts(buffer);
于 2011-01-16T20:46:54.497 に答える
2

strcat非常に単純です。文字列を含むバッファーへのポインターと別の文字列へのポインターを取り、その 2 番目の文字列を、既に存在する文字列の末尾にあるバッファーにコピーします。

2 つの引数の違いに注意してください。どちらもchar *ですが、最初のものは実際にはバッファーへのポインターであり、偶然にも文字列へのポインターです (既にバッファー内にあります)。バッファーとして、単純な文字列にはない次の 2 つのものが必要です。

  • 書き込み可能である必要があります
  • コピーされる2番目の文字列を保持するのに十分な空き容量が必要です

あなたの例ではchar *foo="foo";、最初の引数として使用しようとしていますが、それは単なる文字列であり、バッファの両方の要件がありません。代わりに、次のようなことをする必要があります:

char foo[16] =  "foo";
printf(strcat(foo, "bar"));

ここでfoo、両方の文字列を保持する十分なスペース (十分なバッファー) を持つ書き込み可能な char 配列として宣言しています。これは、上記の 2 番目の要件である strcat でほとんどの人が抱えている問題につながります。バッファに十分なスペースがあるかどうかをどうやって知るのでしょうか? このような単純な例ではそうですが、より複雑な例 (文字列の長さが必ずしもわからない場合) では、はるかに難しくなります。バッファの大きさを追跡する必要があり、strcat を呼び出す前に、strlen を使用して文字列の長さを確認し、文字列が収まることを確認します。これは非効率的であり (文字列文字列を複数回スキャンして長さを見つけてからコピーすることになります)、エラーが発生しやすくなります。

于 2011-01-16T20:53:19.503 に答える
2

必要なもの:

  • 書き込み可能メモリ
  • 十分なスペース

文字列定数は、リテラル内の正確な量のメモリのみを提供し、書き込まれることは想定されていません。

代わりに、次のようにします。

char foo[255] = "foo";
于 2011-01-16T20:45:57.273 に答える
1
char* foo="foo";

文字列リテラルです。

変更できません。代わりに実行しますが、そのようchar [] foo = "foo";に strcat を使用すると問題が発生することに注意してくださいstrcatchar foo[30] = "foo";

編集:あなたのタイプキャスティング...申し訳ありませんが、あなたが何をしようとしているのかを説明しようとするほど多くの脳細胞がありません. それは間違っているとしか言いようがない。機能するようにメモリの場所を提供する必要がありますstrcat()

それを試してください:

int main()
{
    char foo[255]="foo";
    printf("%s",strcat(foo,"bar"));
}
于 2011-01-16T20:41:55.420 に答える