こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

EAccessViolationクラス例外

WindowsXPでBCB5を使用しています。
柴田望洋氏著、新版明解C++入門編の演習8-14ですが
「文字列sの文字の並びを反転する関数str_rvsを作成せよ。
char* str_rvs(char* s);
たとえば、文字列sが"abc"であれば、その文字列を"cba"に更新する。受け取ったsの値をそのまま返却すること。」
と言う問題で、下記の様に作成したんですが、
char* s="a"、または"ab"、または"abc"とすると正常に終了しますが
"abcd"とすると、

文字列[abcd]を反転します。
dcba
文字列[dcba]を反転します。
abcd

が繰り返された後、「EAccessViolationクラスの例外を生成しました。~」が表示されて停止します。
s="abcde"とすると

文字列[abcde]を反転します。
edcba

と1回表示されて、同様のエラーが発生しますが、何が悪いのかわかりません。ご教授願います。

//---------------------
#include <iostream>
#include <cstring>
using namespace std;

char* str_rvs(char* s){
int len=strlen(s);
char* tmp;

for(int i=0;i<len;i++)
*(tmp+i)=*(s+len-1-i);
*(tmp+len)=NULL;

for(int i=0;i<len;i++)
*(s+i)=*(tmp+i);

return s;
}

int main(){
char* s="abcd";

cout << "文字列[" << s << "]を反転します。\n";
cout << str_rvs(s) << '\n';

//getchar();
}

投稿日時 - 2010-12-11 23:45:39

QNo.6378473

暇なときに回答ください

質問者が選んだベストアンサー

> 文字列のコピーを作りたかったので、char* tmp="";等と初期化してやってみてどうしてもうまく行きませんでした

ANo.4 でも書きましたが,この場合 tmp (が指している先)を書き換えてはいけません。
(const char* tmp=""; とすべき)

コピー元の文字列(終端のナル文字含む)を格納するのに十分なサイズのコピー先を自分で用意してやる必要があります。

const char *src = "abcd"; // コピー元
char dst[256];         // コピー先

strcpy(dst, src);  // src (が指している先にある文字列)を dst にコピー

投稿日時 - 2010-12-13 21:58:24

お礼

度々の回答ありがとうございます。

>ANo.4 でも書きましたが,この場合 tmp (が指している先)を書き換えてはいけません。
>(const char* tmp=""; とすべき)


char dst[256];
strcpy(dst, src);
とすると正常に目的の結果が得られました。  
ポインタはこういうものだと理解しておきます。

投稿日時 - 2010-12-14 01:42:54

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(5)

他にもまずいところがあって,
 char* s="abcd";
と宣言した場合,s の内容を書き換えてはいけません。
 char s[] = "abcd";
なら OK。


# 文字列の先頭と末尾から,文字単位で入れ替えていけば,
# 文字列のコピーを作らなくても大丈夫ですよ。

投稿日時 - 2010-12-12 13:22:49

お礼

ありがとうございます。

文字列のコピーを作りたかったので、char* tmp="";等と初期化してやってみてどうしてもうまく行きませんでしたが、おっしゃられる通り
char tmp;
for(int i=0;i<=(len/2-1);i++){
tmp=*(s+i);
*(s+i)=*(s+len-1-i);
*(s+len-1-i)=tmp;
}
として、文字単位で入れ替えてみると正常に終了しました。

投稿日時 - 2010-12-13 12:48:48

ANo.3

tmpが参照するべき実体がありません。

実体がないので

> *(tmp+i)=*(s+len-1-i);

は「どことも知れないメモリ」にアクセスしようとします。結果としてOS側で不正なメモリアクセスを検知して例外を送出します。

あと、どうでもいい部類には入りますが、

> *(tmp+len)=NULL;

「ヌルポインタ(NULL)」と「ヌル文字('\0')」は(C++の範疇では)同じ値を示しますが、概念としては別モノです。
文字列終端のヌル文字の代用にNULLを使うのは避けた方がいいでしょう。

投稿日時 - 2010-12-12 11:56:03

お礼

ありがとうございます。

>>「ヌルポインタ(NULL)」と「ヌル文字('\0')」は(C++の範疇では)同じ値を示しますが、
>>概念としては別モノです。
>>文字列終端のヌル文字の代用にNULLを使うのは避けた方がいいでしょう。

まだポインタの概念を良く理解してない為、参考にさせていただきます。

投稿日時 - 2010-12-13 12:42:37

ANo.2

# ご参考: C++なんだからそんなものわざわざ自作せんでも...

#include <iostream>
#include <cstring>
#include <algorithm> // 追加

using namespace std;

char* str_rvs(char* s){
 std::reverse(s, s+strlen(s)); // これでオシマイ
 return s;
}

int main(){
 char s[] = "abcd";
 cout << "文字列[" << s << "]を反転します。\n";
 cout << str_rvs(s) << '\n';
}

投稿日時 - 2010-12-12 08:05:32

お礼

ありがとうございます。
勉強中なのでrevrese()は知りませんでしたが、うまく行きました。
revrese()無しでもやってみます。

投稿日時 - 2010-12-13 12:38:27

ANo.1

tmpが領域確保されてないのに、未初期化のままデレファレンスしてるからでは。

詳しいことは、他の人が回答してくれるかと。

投稿日時 - 2010-12-12 00:03:54

お礼

ありがとうございます。他の人の回答も参考にさせていただきます。

投稿日時 - 2010-12-13 12:36:02