電子書籍の厳選無料作品が豊富!

#include<cstdio>
#include<cstring>
#define _CRT_SECURE_NO_DEPRECATE 1
#define MAXBUFF 256

void s_swap(char* str_a, char* str_b)
{
char str_dummy[MAXBUFF];
strcpy_s(str_dummy,strlen(str_dummy),str_a);
★strcpy_s(str_a,strlen(str_a),str_b);
★strcpy_s(str_b,strlen(str_b),str_dummy);

}
void main(void)
{
char* str_a = "ABC";
char* str_b = "DEF";
int a;
printf("呼出前:str_a=%s, str_b=%s\n", str_a, str_b);
s_swap(str_a,str_b);
printf("呼出後:str_a=%s, str_b=%s\n", str_a, str_b);
}

str_aとstr_bの中身を入れ替える処理で、エラーや警告はでないのですが
★のところで実行失敗します。
昔から文字列の処理は苦手でどのように攻略したらよいのか
解説していただけないでしょうか。

A 回答 (8件)

>そこの部分は変えずに他を変えてできませんでしょうか?


void s_swap(char** str_a, char** str_b)
{
char *t;
t=*str_a;
*str_a=*str_b;
*str_b=t;
}
void main(void)
{
char* str_a = "ABC";
char* str_b = "DEF";
int a;
printf("呼出前:str_a=%s, str_b=%s\n", str_a, str_b);
s_swap(&str_a,&str_b);
printf("呼出後:str_a=%s, str_b=%s\n", str_a, str_b);
}
    • good
    • 0
この回答へのお礼

ありがとうございます!

お礼日時:2008/10/06 14:48

追記。



s_swap内でstr_dummyがMAXBUFFの大きさである事を期待しているので

char str_a[] = "ABC";
char str_b[] = "DEF";
じゃなく
char str_a[MAXBUFF] = "ABC";
char str_b[MAXBUFF] = "DEF";
として、str_a、str_bの大きさを「最低、MAXBUFFサイズ以上」で定義して下さい。

それに合わせ、コピールーチンは
strcpy_s(str_dummy,MAXBUFF,str_a);
strcpy_s(str_a,MAXBUFF,str_b);
strcpy_s(str_b,MAXBUFF,str_dummy);
に変えなければなりません。

じゃないと
char str_a[MAXBUFF] = "ABCDEF";
char str_b[MAXBUFF] = "GHI";
など「文字列の長さを違えて書いた時」にうまく行きません。ひっくり返した結果は「"GHI"と"ABC"」になると思われます。

それ以前に
char str_dummy[MAXBUFF];
strcpy_s(str_dummy,strlen(str_dummy),str_a);
だと、str_dummyの中身が不定なので、strlen(str_dummy)は、0を返したり、MAXBUFFよりも大きい値を返す可能性があります。つまり「何が起こるか判らないバグを含んでいる」のです。
    • good
    • 0

char* str_a = "ABC";


char* str_b = "DEF";
と書くと、str_aやstr_bは「書き換え出来ない、コンスタントなデータ領域のアドレスを指す」ことになります。

言うなれば「文字列の実体がリードオンリーにされたメモリに配置され、ポインタ変数は、その、リードオンリーになっているメモリを挿す」のです。

つまり
s_swap(str_a,str_b);

s_swap("ABC","DEF");
と書いたのと同じ意味になってしまうのです。これが「やっちゃいけない事」なのは判りますよね?

なので、
char str_a[] = "ABC";
char str_b[] = "DEF";
と書き換えて下さい。

こうすると、書き換え可能なメモリ領域に、必要なバイト数の配列が用意され、定義を行っている場所で、内部的に「書き換え不可なデータ領域にある文字列が、配列にコピー」されます。

そして、str_aやstr_bは「書き換え可能なメモリ領域に置かれた配列」なので「中身を入れかえる事」が可能です。
    • good
    • 0

ごめんなさい m(__)m


arsizeの定義を間違えました ・・・

#define arsize (sizeof(a))/(sizeof(a[0]))
でした ・・・
    • good
    • 0

セキュリティ強化版の strcpyを使う際に 第2引数はバッファのサイズですからstrlenでは NULL文字の分を考慮しないためエラー(アサーション)になると思います



typedef arsize(a) (sizeof(a))/(sizeof[a])

void swap(char* str_a, char* str_b)
{
  // str_dummyを初期化
  char str_dummy[MAXBUFF] = {0};
  // VC2005以降なら arsizeを _countofでもいいようです
  strcpy_s( str_dummy, arsize(str_dummy), str_a);
  strcpy_s(str_a, strlen( str_a ) + 1, str_b);
  strcpy_s(str_b, strlen( str_b ) + 1, str_dummy);
}
    • good
    • 0

strcpy_sという関数は、初めてみました。

(あなたが自作した関数ではないですよね)
ご使用のOSとコンパイラは何でしょうか?

この回答への補足

先日、Visual C++ 2008 Express Edition(フリー)をダウンロードして使ってます。OSはXPです。

こちらを参考にして、strcpy_sを使ってます。
http://msdn.microsoft.com/ja-jp/library/td1esda9 …

補足日時:2008/10/06 12:54
    • good
    • 0

こんにちは。



恐らくポインタと配列の認識の間違いにより発生したと思われます。
配列はあらかじめメモリ領域が確保され、ポインタは確保されません。
試しに

char* str_a = "ABC";
char* str_b = "DEF";

char str_a[10] = "ABC";
char str_b[10] = "DEF";
に変えてみてください。

ご参考までに。
    • good
    • 0
この回答へのお礼

#1様、#2様ありがとうございます。
そこの部分は変えずに他を変えてできませんでしょうか?

お礼日時:2008/10/06 12:52

> char* str_a = "ABC";


> char* str_b = "DEF";
"ABC"や"DEF"などの文字列リテラルは変更不可能な固定文字列として扱われます。
上記プログラムの場合、str_aやstr_bは変更不可能な固定文字列領域アドレスを挿すポインターなのに、s_swap内で内容を書き換えようとして実行時例外が発生していると思われます。
変更不可能なのにchar*型の変数に代入できるのはなぜかというと、確かはるか昔のCプログラムとの互換性を保つためだったはずです。

この場合、
> char str_a[] = "ABC";
> char str_b[] = "DEF";
というようにポインターではなく、配列として文字列を定義すれば、失敗せずにすむはずです(すみません、未検証です)
当然のことながら、str_a及びstr_bの配列サイズが入れ替えるのに十分な大きさがないと、やはり実行時エラーになりますが。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!