1

これらの関数の 1 つを dev-C++ で使用しているときはいつでも (古いことは知っていますが、何らかの理由で大学でまだ教えられています。)

strcat,strcpy,strcmp,strchr...//And their variants stricmp...

これらの関数の最初の引数は常に配列でなければなりません (つまり:

char ch[]="hello";

ただし、何らかの理由で文字列 bc へのポインターにすることはできません。これにより、クラッシュが発生します。実際、例として、これらのコードの両方を見てください。

コード 1:

#include<stdio.h>
#include<string.h>
main()
{char ch[20]="Hello world!";
 char *ch2="Hello Galaxy!";
 strcat(ch,ch2);
 printf("%s",ch);
 scanf("%d")//Just to see the output.
}

このコードは正常に動作し、期待どおりの結果が得られます (Hello World!Hello Galaxy!)

しかし、逆 code2 はクラッシュします。

コード 2:

#include<stdio.h>
#include<string.h>
main()
{char ch[20]="Hello world!";
 char *ch2="Hello Galaxy!";
 strcat(ch2,ch);
 printf("%s",ch2);
 scanf("%d")//Just to see the output.
}

このコードはクラッシュし、

file.exe has stopped working Error.

これは、2 つの引数を取るほとんどすべての文字列関数で同じです。この問題の原因は何ですか。

4

6 に答える 6

9

char *ch2 = "Hello Galaxy!";文字通りの文字列へのポインターを取得しています。これは未定義の動作を呼び起こすため、文字列リテラルを変更しようとしないでください(あなたの場合、クラッシュとして現れました)。

char ch[20] = "Hello World!";文字列リテラルの内容を使用して配列を初期化しているため、ch.

また、20 文字では収まらないことに注意してHello World!Hello Galaxy!ください。これも未定義の動作であり、バッファ オーバーフローとして知られています。

于 2012-07-26T22:39:11.303 に答える
2
 char ch[20] = "Hello world!"

chは、char文字列リテラルの要素によって初期化された の配列です (残りの配列は で初期化されます0)。

 char *ch2="Hello Galaxy!";

ch2文字列リテラルへのポインタです。

文字列リテラルは、C では変更可能である必要はありません。文字列リテラルの変更は、C では未定義の動作です。

于 2012-07-26T22:40:08.820 に答える
1

2 つの問題があります。1 つ目は、文字列リテラルが連結された文字列を保持するのに十分な長さではないこと"Hello world!Hello Galaxy!"です。割り当てられるスペースはわずか 13 バイトです (12 文字と文​​字列を終了する '0' バイトのスペースを加えたもの)。連結された文字列には 26 バイト (25 文字 + NULL 値の文字 1 つ) が必要です。

ただし、これは本当の問題ではありません。本当の問題は、アクセスしてはならないメモリにアクセスしていることと、オペレーティング システムによって保護されていることが多いことです。C のほとんどの実装では、次の 4 つのストレージ領域が提供されます。

  1. 関数で宣言した変数が割り当てられるスタック
  2. malloc/calloc/realloc の呼び出しがメモリを割り当てるヒープ
  3. 非 const グローバル変数 (関数の外部で宣言されたもの) が割り当てられるグローバル静的ストレージ。
  4. 宣言されたすべての文字列リテラルとその他のグローバル変数constが割り当てられるグローバル定数ストレージ。

最初の 3 つの領域は、原則として変更可能です。4 番目の領域はそうではなく、多くの場合、オペレーティング システムが読み取り専用としてマークするメモリに保存されます。文字列リテラル"Hello Galaxy!" tochar* ch2 , the variablech2` ポイントをグローバル定数ストレージに割り当てると。

より良いアイデアを提供するために、次のコードは、実行時にセグメンテーション違反を一般化します。

#include <stdio.h>

int main(int argc, char** argv)
{
  char* s = "Foo bar baz";
  s[0] = 'B';
  printf("%s\n",s);
  return 0;
}

s[0] = ...オペレーティングシステムが読み取り専用としてマークしたストレージにアクセスしているため、セグメンテーション違反が行で発生します。

于 2012-07-26T22:55:31.357 に答える
0

読み取り専用のプロセスのコードセクションにアクセスしようとしたため、エラーが発生しました。これは、コードに存在する文字列リテラルと、ポインタ変数への割り当てに使用するその文字列リテラルのアドレスです。したがって、コードにアクセスすることはできますが、これを変更することはできません。

すべての実行可能ファイルには、次のようなセクションが含まれています...

1.text(プログラムのコードとここにある文字列リテラル)

2.データが初期化されていません

3.データが初期化されました

あなたはコマンドでこれを非常にうまくいくことができます

size <executable-file-neme>

コマンドも使用

objdump -D  <executable-file-neme>
于 2012-07-27T04:32:43.933 に答える
0

それはポインタ配列のサイズについてです.オーバーフローの問題.. char *ch2="Hello Galaxy!";これを自動的に使用すると、* ch2のサイズはnull文字で14になりますが、ch[]配列をに移動*ch2するとエラーが発生します。サイズが 20 の配列をサイズが 14 の別の配列に移動することはできません...

于 2012-07-26T22:49:10.280 に答える
0

文字列リテラルは読み取り専用です。つまり、代入すると次のようになります。

char* str="Hello";

strcpy と strcat の最初の引数として str を渡すことはできません。これにより、読み取り専用メモリが上書きされる可能性があります。代わりに、次のように宣言すると:

char str2[]="Hello";

次に、str2 配列がスタックに格納され、その値を変更できます。
strcmp (wto 文字列を読み取って比較するだけ) などの関数に str を渡すことも、文字列が書き込まれないため、strcat と strcpy の 2 番目の引数として渡すこともできます。

于 2012-07-27T01:02:03.467 に答える