-1

文字列を逆にするプログラムを書いた後、文字列を逆にしようとしたときにセグメンテーション違反が発生した理由を理解するのに苦労しています。私のプログラムを以下にリストしました。

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

void reverse(char *);

int main() {
  char *str = calloc(1,'\0');
  strcpy(str,"mystring0123456789");
  reverse(str);
  printf("Reverse String is: %s\n",str);
  return 0;
}

void reverse(char *string) {
  char ch, *start, *end;
  int c=0;
  int length = strlen(string);
  start = string;
  end = string;

  while (c < length-1){
    end++;
    c++;
  }
  c=0;

  while(c < length/2){
    ch = *end;
    *end = *start;
    *start = ch;
    start++;
    end--;
    c++;
  }
}

最初の質問:

charポインタstr()に1バイトのメモリしか割り当てておらずcalloc(1,'\0')、18バイトの文字列をコピーしmystring0123456789たにもかかわらず、エラーはスローされず、プログラムはSEGFAULTなしで正常に動作しました。

プログラムがエラーをスローしなかったのはなぜですか?理想的には、その大きな文字列を格納するためのメモリがないため、エラーがスローされるはずです。誰かがこれに光を当てることができますか?

プログラムは完全に実行され、出力が表示されますReverse String is: 9876543210gnirtsym

2番目の質問:

ステートメントを置き換える場合

strcpy(str,"mystring0123456789");

str="mystring0123456789\0";

str()に十分なメモリを割り当てても、プログラムでセグメンテーション違反が発生しますmalloc(100)

プログラムがセグメンテーション違反をスローするのはなぜですか?

4

5 に答える 5

5

charポインタstr(calloc(1、'\ 0'))に1バイトのメモリしか割り当てておらず、18バイトの文字列 "mystring0123456789"をコピーしましたが、エラーは発生せず、プログラムはSEGFAULTなしで正常に機能しました。

あなたのコードにはバグがありました-もちろん、それはあなたが期待することをするつもりはありません。バグを修正すれば、謎は消えます。

ステートメント
strcpy(str、 "mystring0123456789");を置き換える場合
str
= "mystring0123456789 \ 0";
str(malloc(100))に十分なメモリを割り当てても、プログラムはセグメンテーション違反を起こします。

これを終えるstrと、定数を指すからです。これにより、割り当てたメモリへのポインタである以前の値がstr破棄され、その定数へのポインタに置き換えられます。

定数を変更することはできません。それが定数になります。このstrcpy関数は定数を変数にコピーし、それを変更できます。

あなたがこれを行うことができるかどうか想像してみてください:

int * h =&2;

さて、もしあなたがそうしたら、あなたはあなたのコードでその定数*h = 1;2を変更しようとしているでしょう、もちろんあなたはそれをすることができません。

それは事実上あなたがしていることですstr="mystring0123456789\0";strもちろん、変更できないソースコードの定数を示しています。

于 2013-03-18T13:09:04.757 に答える
2
  1. セグメンテーション違反をスローする必要はありません。発生するのは、壊れたコードが未定義の動作を呼び出すことだけです。その動作に目に見える効果がない場合、それは問題ありません。ハードドライブをフォーマットして画面を青く塗る場合は、それでも問題ありません。未定義です。
  2. 割り当てられたメモリを完全に使用しない文字列リテラルのアドレスでポインタ値を上書きしています。次に、読み取り専用メモリにある文字列リテラルを逆にしようとすると、セグメンテーション違反が発生します。
于 2013-03-18T13:09:33.303 に答える
0
  1. あなたが間違ったことをしたとしても、あなたのプログラムはエラーをスローしませんでした(詳細は以下を参照)。想定外のデータを書き込んだのですが、「ラッキー」になり、これを行っても何も壊れませんでした。

  2. strcpy(str,"mystring0123456789");ポイントのある場所にデータをコピーしますstr。たまたま、その場所で、トラップを発生させることなくデータを書き込むことができます(今回)。対照的に、新しい場所を指すようにstr="mystring0123456789\0";変更します。strそれが指す場所は、"mystring0123456789\0"保管されている場所です。その場所はおそらく読み取り専用メモリであるため、ルーチンでその場所に書き込もうとするとreverse、トラップが発生します。

1についての詳細:

メモリを割り当てるときは、使用が許可callocされているスペースがあるように調整するだけです。物理的には、他のメモリが存在します。他のメモリに書き込むことはできますが、書き込むべきではありません。これはまさに現実の世界での仕組みです。ホテルの部屋を借りれば、そのホテルの部屋を使用できますが、他の部屋が開いていても使用するのは間違いです

現実の世界やプログラムで、想定外の場所に侵入すると、誰も見ることができず、逃げることがあります。時々あなたは捕まるでしょう。あなたが捕まらないという事実はそれが大丈夫だったという意味ではありません。

についてもう1つ注意してくださいcalloc:サイズがゼロの1つのものにスペースを割り当てるように依頼しました(ソースコード'\0'はゼロと評価されます)。したがって、ゼロバイトを要求しています。さまざまな標準(CやOpen Unixなど)はこれについて異なることを言っている可能性があるため、0バイトを要求すると、calloc1バイトになる可能性があります。ただし、それは確かにあなたがで書いたほど多くのバイトをあなたに与えませんstrcpy

于 2013-03-18T13:31:41.397 に答える
0

動的言語または少なくとも自動文字列処理を行う言語から来たCプログラムを書いているようです。より正式な定義がないため、Cはマシンのアーキテクチャに非常に近い言語であることがわかりました。つまり、プログラミングに関する多くの決定を行います。プログラムの問題の多くは、コードが未定義の動作を引き起こした結果です。メモリを保護された場所にコピーしたため、strcpyでセグメンテーション違反が発生しました。動作は未定義でした。一方、固定文字列 "mystring0123456789 \ 0"を割り当てることは、そのポインタをstrに割り当てることでした。

Cで実装する場合、コンパイル時または実行時にストレージ領域を定義するか、ヒープ(malloc / calloc)からストレージを割り当てるかを決定します。いずれの場合も、定義したストレージを超えないように、ハウスキーピングルーチンを作成する必要があります。

文字列をポインタに割り当てると、メモリ内の文字列のアドレスが割り当てられるだけです。文字列はコピーされず、引用符「test-string」内の固定文字列は読み取り専用であり、変更することはできません。あなたのプログラムは、それが良いCコーディングの実践とは見なされないとしても、その割り当てを行って、うまく機能したかもしれません。

この方法でストレージ割り当てを処理することには利点があります。そのため、Cが一般的な言語です。

于 2013-03-18T13:51:06.440 に答える
0

もう1つのケースは、メモリを正しく使用するとセグメンテーション違反が発生する可能性があり、ヒープが大きくなりすぎて物理メモリで管理できない場合です(stack | text | data | bss-> linkと重複しない場合)

証明:リンク、セクション考えられる原因#2

于 2014-08-29T15:39:19.707 に答える