7

だから私はいくつかのCコードを持っています:

#include <stdio.h>
#include <string.h>

/* putting one of the "char*"s here causes a segfault */
void main() {
  char* path = "/temp";
  char* temp;
  strcpy(temp, path);
}

これは、見た目どおりにコンパイル、実行、および動作します。ただし、文字ポインターの一方または両方がグローバル変数として宣言されている場合、strcpy はセグメンテーション違反になります。なぜこれが起こるのですか?明らかに、スコープの理解に誤りがあります。

4

8 に答える 8

16

他のポスターが述べたように、問題の根本は、tempが初期化されていないことです。スタック上で自動変数として宣言されると、そのメモリ位置にたまたま存在するガベージがすべて含まれます。どうやらあなたが実行しているコンパイラ+CPU+ OSにとって、その場所のゴミは有効なポインタです。strcpyは、セグメンテーション違反を起こさないという点で「成功」しますが、実際には、文字列をメモリ内の任意の場所にコピーしました。この種のメモリ破損の問題は、デバッグが非常に難しいため、あらゆる場所のCプログラマーの心に恐怖をもたらします。

一時変数宣言をグローバルスコープに移動すると、BSSセクションに配置され、自動的にゼロになります。* tempを逆参照しようとすると、セグメンテーション違反が発生します。

* pathをグローバルスコープに移動すると、*tempはスタック上の1つの場所に移動します。その場所のガベージは明らかに有効なポインタではないため、*tempを逆参照するとセグメンテーション違反が発生します。

于 2008-09-23T18:43:36.600 に答える
9

temp 変数はストレージ (メモリ) を指しておらず、初期化されていません。

temp が次のように宣言されているchar temp[32];場合、コードはどこで宣言されていても機能します。ただし、そのような固定サイズで temp を宣言することには別の問題がありますが、それはまた別の質問です。

さて、ローカルではなくグローバルに宣言するとクラッシュするのはなぜですか。幸運...

ローカルで宣言された場合、temp の値は、その時点でスタック上にある可能性のある値から取得されます。クラッシュを引き起こさないアドレスを指しているのは幸運です。ただし、他の誰かが使用したメモリを破棄しています。

グローバルに宣言すると、ほとんどのプロセッサでこれらの変数は、デマンド ゼロ ページを使用するデータ セグメントに格納されます。したがってchar *temp、宣言されているかのように見えますchar *temp=0

于 2008-09-23T18:39:46.143 に答える
8

temp の割り当てと初期化を忘れました:

temp = (char *)malloc(TEMP_SIZE);

TEMP_SIZE が十分に大きいことを確認してください。実行時にこれを計算して、サイズが十分であることを確認することもできます (少なくとも strlen(path) である必要があります)。

于 2008-09-23T18:36:27.150 に答える
3

上で述べたように、あなたは臨時雇用者のためにスペースを割り当てるのを忘れました。私はstrdupしたいmalloc+strcpy。それはあなたがやりたいことをします。

于 2008-09-23T18:43:09.613 に答える
2

いいえ-これは変数に関係なく機能しません-運が良かったために機能したように見えます。変数を初期化しないままにするのではなく、文字列の内容を格納するためのスペースを割り当てる必要があります。

スタック上の初期化されていない変数は、メモリのほぼランダムな場所を指します。これらのアドレスがたまたま有効である場合、コードはそこにあるものすべてを踏みにじりますが、エラーは発生しません(ただし、コードの他の場所で厄介なメモリ破損関連のバグが発生する可能性があります)。

グローバルは通常、マップされていないメモリを指す特定のパターンに設定されるため、常に失敗します。これらを逆参照しようとすると、すぐにセグメンテーション違反が発生します(これは、後でバグを追跡するのが非常に困難になるため、より良い方法です)。

于 2008-09-23T18:43:29.143 に答える
2

最初の Adam のフラグメントを次のように書き換えたいと思います。

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';

そうすれば:

1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.

2 番目のポイントは、ソース文字列の長さが 256 文字以上の場合、ソース文字列の最後の文字が失われることです。

于 2008-09-23T18:57:04.337 に答える
1

注意すべき重要な部分:
宛先文字列 dest は、コピーを受け取るのに十分な大きさでなければなりません。
あなたの状況では、tempにはコピー先のメモリが割り当てられていません。

strcpy の man ページからコピー:

DESCRIPTION
   The  strcpy()  function  copies the string pointed to by src (including
   the terminating '\0' character) to the array pointed to by  dest.   The
   strings  may not overlap, and the destination string dest must be large
   enough to receive the copy.
于 2008-09-23T18:39:09.747 に答える
1

temp変数を初期化していないため、未定義の動作を呼び出しています。メモリ内のランダムな場所を指しているため、プログラム機能する可能性がありますが、セグメンテーション違反が発生する可能性が高くなります。宛先文字列を配列にするか、動的メモリを指すようにする必要があります。

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);

// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);

また、バッファー オーバーランを回避するためstrncpy()に代わりに使用します。strcpy()

于 2008-09-23T18:39:53.647 に答える