解決済みの質問
質問:No.6378473
暇なときに回答ください
お気に入り投稿に追加する (0人が追加しました)
回答数5
閲覧数197
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
質問者が選んだベストアンサー
回答:No.5
> 文字列のコピーを作りたかったので、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
この回答を支持する
(現在1人が支持しています)
お礼
度々の回答ありがとうございます。

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


char dst[256];
strcpy(dst, src);
とすると正常に目的の結果が得られました。  
ポインタはこういうものだと理解しておきます。
投稿日時 - 2010-12-14 01:42:54
この質問は役に立ちましたか?
0人が「このQ&Aが役に立った」と投票しています
ベストアンサー以外の回答
回答:No.4
他にもまずいところがあって,
 char* s="abcd";
と宣言した場合,s の内容を書き換えてはいけません。
 char s[] = "abcd";
なら OK。


# 文字列の先頭と末尾から,文字単位で入れ替えていけば,
# 文字列のコピーを作らなくても大丈夫ですよ。
投稿日時 - 2010-12-12 13:22:49
この回答を支持する
(現在1人が支持しています)
お礼
ありがとうございます。

文字列のコピーを作りたかったので、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
回答:No.3
tmpが参照するべき実体がありません。

実体がないので

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

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

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

> *(tmp+len)=NULL;

「ヌルポインタ(NULL)」と「ヌル文字('\0')」は(C++の範疇では)同じ値を示しますが、概念としては別モノです。
文字列終端のヌル文字の代用にNULLを使うのは避けた方がいいでしょう。
投稿日時 - 2010-12-12 11:56:03
この回答を支持する
(現在1人が支持しています)
お礼
ありがとうございます。

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

まだポインタの概念を良く理解してない為、参考にさせていただきます。
投稿日時 - 2010-12-13 12:42:37
回答:No.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
この回答を支持する
(現在1人が支持しています)
お礼
ありがとうございます。
勉強中なのでrevrese()は知りませんでしたが、うまく行きました。
revrese()無しでもやってみます。
投稿日時 - 2010-12-13 12:38:27
回答:No.1
tmpが領域確保されてないのに、未初期化のままデレファレンスしてるからでは。

詳しいことは、他の人が回答してくれるかと。
投稿日時 - 2010-12-12 00:03:54
この回答を支持する
(現在1人が支持しています)
お礼
ありがとうございます。他の人の回答も参考にさせていただきます。
投稿日時 - 2010-12-13 12:36:02
もっと聞いてみる
関連するQ&Aはこちら
柴田望洋氏著「新版 明解C++ 入門編」をテキストにして、BCBでコンソールアプリを作成しながら勉強しています。 「List8C-1」での質問ですが、テキストでは、下記に示す「プログラム」を実行して入...
新版 明解C++ 入門編  について 私は、柴田望洋さんの『新版 明解 C++ 入門編』という本を購入して、勉強し始めました。 根本的な質問なんですが、ソースプログラムをメモ帳に書き込んだ後、どうし...
「望羊」 地名などではなく、単独でどういう意味の言葉でしょうか。 「望洋」なら辞書にあるのですが・・・。 ...
この他の関連するQ&Aをキーワードで探す
プログラミングのサブカテゴリ
[PR] おすすめの注目情報
カテゴリ:C・C++
RSS
-PR-
PR
-PR-