5

では、char があり、それを 1 行のコードで strcat() して char 配列にしたいとします。[非実用的な] 例:

strcat("ljsdflusdfg",getchar());

または、逆のことをしたかったのですが、データ型に関係なく、文字列を連結または型キャストするための適切な関数は何でしょうか? または、私が見逃している構文があるかもしれません...

これが例です。コンパイルは問題なく実行できますが、クラッシュします。

char* input(){
 char* inp="";
 while(1){
  char c=getchar();
  if(c){
   if(c=='\n'||c==EOF){
    break;
   }else{
    strcat(inp,(char*)c);
   }
  }
 }
 return inp;
}
4

8 に答える 8

3

strcat引数をヌル終了文字列へのポインタとして扱います。charaを a にキャストするのchar *は危険であり、それが有用であるとは思えません (それを試すのが愚かだと言っているわけではありません。誰もが学ぶときにばかげた間違いを犯します。それが私たちがここにいる理由です)。

その理由は、1 バイトcharに加えて、それを囲む余分なsizeof(char*) - sizeof(char)(通常は 3) バイトをcharポインターとして解釈し、それが ... を指すためです。これらのバイトのうち 3 バイトは制御できないため、有効なデータを指しているかどうかを知る方法はありません。

これを 2 番目のアプローチとして使用できます。

strcat(inp, &c);

今回&cは、 は型の式char *であり、キャストは必要ないため、うまくいくでしょう。しかし、繰り返しにstrcatなりますが、引数がヌルで終わる文字列であると仮定します。データの後にヌルバイトを保証する方法がないためchar、これはうまくいきません。

最良の方法はこれです:

size_t len = strlen(inp); // this may already be calculated somewhere else
...
inp[len++] = c; // add c as the last character, and adjust our len
inp[len] = '\0'; // add a new nul terminator to our string

アップデート:

実は嘘をつきました。最善の方法は、標準ライブラリの function を使用するfgetsことです。これは、多かれ少なかれ、あなたがしようとしていることを実行しているように見えます。正直なところ忘れていましたが、これが宿題である場合、fgets手動で行う方法を学べるように、教授は使用を望まないかもしれません。ただし、これが宿題でない場合は、fgets探していることを正確に実行します。(実際には、3 番目のアプローチは、機能の再実装fgetsまたはfgets類似の機能に向けて順調に進んでいます。)

inputまた、関数に関する他のコメントも追加します。

  1. char* inp = "";読み取り専用データを指します。C標準の欠陥(後方互換性のため)により、文字列リテラルをchar*型ではなく型に割り当てることができますconst char *(IMHO)。

    これにはいくつかの方法がありますが、最適なのは動的割り当てです。関数を使用してmalloc一部のデータを予約し、関数で使用した量を追跡し、保存するためreallocにより多くのスペースが必要になった場合に関数を使用します。ヘルプが必要な場合は、別の質問で (できればすぐに)ここに戻ってくると思います:)
  2. getchar()は a の通常の範囲外に定義されているintため、 を返します。とを区別するには、を. そうしないと、完全に有効な文字が. ただし、文字列に追加するときは必ず a にキャストしてください。EOFcharcharEOFcintEOFcchar
于 2011-01-14T03:09:35.083 に答える
2
strcat(inp,(char*)c);

これは、ゼロが見つかるまで、「c」(メモリ位置として) がある場所でメモリの内容を連結しようとしています。

より良い方法は、合理的と思われる最大サイズの空の文字列を作成し、ゼロで埋めてから、現在の最後の位置に「c」を挿入することです

于 2011-01-14T03:06:05.270 に答える
2

単一charの文字列を文字列に連結する場合は、 を使用strncat()して、連結する文字数を指定できます1。ただし、次の点に注意してください。

  • 宛先バッファーには十分なスペースが必要です。と
  • C89 ではchar、アドレスを取得する実際のオブジェクトが必要です (そのため、 の結果を直接連結することはできませんgetchar()

例えば:

char str[5] = "foo";
char c;
int ch;

if ((ch = getchar()) != EOF) {
    c = ch;
    strncat(str, &c, 1);
}

C99 では、複合リテラルを使用でき、2 番目の制限は適用されません。

char str[5] = "foo";
int ch;

if ((ch = getchar()) != EOF) {
    strncat(str, &(char){ ch }, 1);
}
于 2011-01-14T05:00:23.420 に答える
1

*inp char ポインタにはそれをバックアップするメモリがないため、これは機能しません。char *inp = ""; と宣言したときに、空の文字列のアドレスだけを指定しました。次の宣言 char *inp = "abcdefg" を指定した場合、'\0' を上書きして問題が発生する前に、7 文字を書き込むことができたはずです。

入力する文字数が増えるにつれて、バッキング メモリのサイズを動的に増やす必要があります。また、メモリリークが発生しないようにメモリを解放するタイミングを知るという問題もあります。

また、strcat には c の前に「&」が必要です。

于 2011-01-14T03:07:13.657 に答える
0

簡単な方法の 1 つは、snprintf を使用することです。

char newString[50+1];
snprintf(newString, sizeof(newString), "%s%c", "ljsdflusdfg", getchar());

これは単純な解決策ですが、事前に文字列がどのくらいの大きさになるかを大まかに知っている必要があります。

注: +1 を使用して、null 終了の余地が必要であることを思い出します。snprintf は、バッファー オーバーランを防ぐためにバッファーのサイズが与えられているため、sprintf よりも優れています。

于 2013-08-08T05:59:12.767 に答える
0

まず、スタックに割り当てられた配列へのポインターを返しています。これは未定義の動作です。次に、割り当てられていないメモリに文字を書き込もうとしています。第三に、 の型inpconst char*notchar*です。

次のようなものが必要です。

char* input(char *dest) {
  strcpy(dest,"");
  while(1){
  char c=getchar();
  if(c){
   if(c=='\n'||c==EOF){
    break;
   }else{
    strcat(inp,&c);
   }
  }
 }
 return dest;
}
于 2011-01-14T03:07:46.953 に答える
0

strcat は両方のパラメーターに null で終わる文字列を想定しているため、コードがクラッシュします。

char を連結する場合は、最初に null で終わる文字列を作成する必要があります。

char c[2] = {0,0};
c[0] = getchar();
strcat(inp, c);

ただし、入力文字列がその余分な文字にスペースを割り当てていることを保証できない限り、strcat を使用しないでください。strncat には、最初のパラメーター (dest) にスペースの量のパラメーターも含まれています。

最初にこれを読むことをお勧めします。

于 2011-01-14T03:08:58.890 に答える
-1

char を char 配列にキャストしますか?
char を string にキャストしたいと言っているようなものです。
それを直接行うことはできません。
char の代わりに、配列 (myChar[]) に配置します。
その後、元の char 配列で strcat します。

于 2011-01-14T03:09:03.987 に答える