空文字列の記述方法として、NULLポインタを指定できると思うのですが、
以下のコードを実行するとAccess Violationになります。
#include <string.h>
void main()
{
char c[256];
strcpy(c, NULL);
}
NULLポインタが空文字を表すという、私の解釈は間違ってますか?
WinMe VC++6.0SP5
NULLは文字列が'ない'のであって、'長さ0の文字列'とは違います。
strcpyっていう関数は、引数がNULLだとダメじゃないですかね。
単純に、c[256]を初期化してはどうですか?
memset(c,0,sizeof(c));
そうでしょうか?
私の持っているC++の本(C++ Primer 改訂3版 ISBN4-7561-4006-8)の
131ページには以下のような記述があります。
-----------------------------------------
C形式の文字列の長さを0(空の文字列として扱われる)にすることができる。
その方法は2種類ある。まず文字ポインタを0にして、
いかなるオブジェクトも指していないようにする方法。
もう1つは、ポインタを正しく設定して、その参照している配列に
NULL文字だけを設定しておく方法である。
------------------------------------------
また、同書の134ページには文字列が空であるかの判定方法として
------------------------------------------
char *str = 0;
//...
if (!str || !*str)
return;
------------------------------------------
とあります。
・・・なので
char c[256];
strcpy(c, NULL);
で、c[0] == '\0'となることを期待したのですが・・・
NULLが入っている のと、 NULLを参照する のはぜんぜん違います。
> strcpy(c, NULL);
この記述は
『NULL(という場所)にある文字列をc(という場所)にコピーする』
という意味であって、c がNULLになるわけではありません。
NULLというのは
『どこも指していない』
という場所なので、そこをアクセスすれば当然未定義の動きになります。
ポインタと、それが指してる先はぜんぜん別物です。
> c[0] == '\0'となることを期待したのですが・・・
ならば c[0] = '\0' でOKです。頭脳パンさんの言うように
>memset(c,0,sizeof(c));
とすれば、c[0] から c[255] まで全部 0 になってくれます。
デバッグで、メモリウィンドウを見ながら動作させると
よくわかりますよ。(VCを使っていらっしゃると仮定します)
例えば、今回の場合は、
char c[256]; cの中身は、CCCCCCCC...CC (256個)
memset(c,0,sizeof(c)); cの中身は、00000000...00 (256個)
となって、意図した動きになっていると思いますよ。
strcpy(c, NULL)は、動作させると死んじゃうので、cの中身は見れませんが
アセンブル コードで見れば
strcpyの中の以下の箇所で、ecxが、0なんで死んでますね。
mov eax,dword ptr [ecx] ; read 4 bytes
まぁ、引数にNULL指定はできないと理解してください。
char c[256]; cの中身は、CCCCCCCC...CC (256個)
strcpy(c, NULL);
↑がもし動作したとしたら、
cの中身は、00000000...00 (256個) もしくは
cの中身は、00CCCCCC...CC (256個)
となることを期待したのではないでしょうか?
別にきよさんは
「char c[256]を初期化したいのだがどうすればよいか」
ということが知りたいわけじゃないような。
> 私の持っているC++の本(C++ Primer 改訂3版 ISBN4-7561-4006-8)の
> 131ページには以下のような記述があります。
> -----------------------------------------
> C形式の文字列の長さを0(空の文字列として扱われる)にすることができる。
> その方法は2種類ある。まず文字ポインタを0にして、
> いかなるオブジェクトも指していないようにする方法。
> もう1つは、ポインタを正しく設定して、その参照している配列に
> NULL文字だけを設定しておく方法である。
> ------------------------------------------
私はその本を持っておらず前後の文脈がわからないので推測ですが、
その文章の言いたいことは、
「あなたの書くコードにおいて、『文字ポインタがNULLである』ことを
『文字列が空である』ことと扱うようにすることもできる」
ということではないかしら。
#ちと意訳しすぎかな(^^;
strcpyは『文字ポインタがNULLである』ことを『文字列が空である』とはみなさず、
素直にNULLポインタの参照先にアクセスしようとするため
当然アクセス違反が起きます。
strcpyのみならず単純な文字列操作ライブラリでは、高速化のため
NULLチェックなどやってくれません。
>「char c[256]を初期化したいのだがどうすればよいか」
>ということが知りたいわけじゃないような。
はい。その通りです。
当然、皆さんのおっしゃてる空文字列とNULLポインタの違いは
理解していますし、いままでstrcpy(c, NULL);なんてコードを
書いたことは当然ありません。
ただ、
> C形式の文字列の長さを0(空の文字列として扱われる)にすることができる。
> その方法は2種類ある。まず文字ポインタを0にして、
> いかなるオブジェクトも指していないようにする方法。
という記述があったので、言語仕様でも変わったのかと思い、
質問させていただいた次第です。
>その文章の言いたいことは、
>「あなたの書くコードにおいて、『文字ポインタがNULLである』ことを
>『文字列が空である』ことと扱うようにすることもできる」
>ということではないかしら。
たしかにそういう解釈正しいのかもしれません・・・
いや~、ちょっとはやとちり。
char c[256]を初期化する方法になってましたね(^^
でも、じっさいにポインタや配列にどの値が入っているかということを
考えるのが一番、簡単に理解できると思ったもので。
日本語で書くと、いろいろな解釈をしそうになって余計に混乱するかなと。
131ページの引用は、普通に読み飛ばせる文章だと思いますよ。
もちろん、言語仕様は変わっていませんし。
ところで、解決されたのでしょうか?
>まず文字ポインタを0にして、
>いかなるオブジェクトも指していないようにする方法。
char *str;
str=0;//私なら「str=NULL;」と記述するが、、、
>もう1つは、ポインタを正しく設定して、その参照している配列に
>NULL文字だけを設定しておく方法である。
char *str,buf[256];
str=buf;
memset(buf,NULL,sizeof(buf));//*str=NULL;でも可。
//私ならNULLじゃなくて文字コードとして0x00を使うな。
>if (!str || !*str)
> return;
「!str」は「まず文字ポインタを0にして、いかなるオブジェクトも指していないようにする
方法。」を判断する為のもの。
「!*str」は「もう1つは、ポインタを正しく設定して、その参照している配列にNULL文字だ
けを設定しておく方法である。」を判断する為のもの。
どちらかに該当すれば「文字列の長さを0」として「return」します。