プロが教えるわが家の防犯対策術!

char *str = {0x61, 0x62, 0x0, 0x64};

ができないから、

char *str = "abcd";
str[2] = 0;

として、{0x61, 0x62, 0x0, 0x64} という文字列を作ってみた。

このポインタ str は解放する必要がない。
malloc( ) で確保したなら free( ) する必用がある。
普通のポインタは、もしかしたら 0x0 までしか
確保されていないのかなと思いました。

この場合では、str[3] == 0x64 だという結果になったけど、
それは str[2] の次のデータが 0x64 だったわけで、
str[2] に 0x0 が入った時点で、str[3] 以降の領域は
str とは無関係かもしれないと思いました。

つまり、char*型は、0x0 までの部分だけを確保し、
この例のソースでは、str[3] 以降の領域は確保されていないから
後で、知らないうちに値が変わっている可能性がある。

という想像をしてみたけど、あってますか?

A 回答 (7件)

こんにちは、honiyonです。



 ハズレです。
 最初に 4byte確保したなら、str[2] = NULL; としても 4byte確保されています。
 char*型はあくまで「char型へのポインタ」であり、メモリの操作は行いません。

 0x00 も立派な「データ」ですよ。

 char* = 文字列データ という意味合いが強いですが、あくまで char型は「0~255の整数型」であり、それ以外の用途にも使用される事があります。 char* でメモリを確保し、バイナリデータを扱う事だって出来ます。

 参考になれば幸いです(..
    • good
    • 0
この回答へのお礼

ありがとうございます。
ハズレでしたか。

メモリの操作は行わないという意味が分かりませんでした。

char *str = "abcd";
で5バイト確保される。
そして str を使う。
必要なくなったら、確保した5バイトを解放したい。
解放したい場合はどうしたらいいんですか?

char *str = "abcd";
printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]);
str = "de";
printf("%x,%x,%x,%x,%x\n", str[0], str[1], str[2], str[3], str[4], str[5]);

結果は
61, 62, 63, 64, 0
64, 65, 0, 25, 23

この時、str が確保しているのはまだ5バイトですか?

char *str = "abcd";
の後に
str = "de";
としました。
どこかのサイトで、ポインタの値を書き替えてはいけない
と書いてあったのを見たような記憶があります。
この結果は企画にない結果だったんですか?

char *str;
で宣言したポインタに大きなサイズのデータを格納した場合、
プログラムが終了するまで、その大きなサイズを確保しているのは
よくないことだから解放したいと思って質問しました。

お礼日時:2002/03/21 19:35

> char *str[] = {0x61, 0x0, 0x64};


失礼しました。私のタイプミスです(笑)
ご指摘ありがとうございました。
*はいらないですね。
> char str[] = {0x61, 0x0, 0x64};

回答はみなさんの答えで的を得ています。
質問者がの処理系が違っていた場合には記述の曖昧さで悩んでしまうと可哀想かなと思ったので補足をしてみました。余計でしたら申し訳ないです。
そういう自分が上記のようなタイプミスしているくらいですから、私自身もまだまだ甘いですね。ただのタイプミスといえど挙動はかなり違いますからね。
    • good
    • 0

No.5 の方が「処理系依存」のことについて触れられていますが、それについてちょっとアドバイスを。



>signed か unsigned は処理系次第ではなかったでしたっけ。
>4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
 最適化するとレジスタを使ってしまったりする事も。

どちらも確かにその通りです。
でも A__ さんに理解して欲しいのは、
>char * 型は、文字列処理以外にも使用される、ということ
>ポインタ変数と文字列アドレスの関係について
という部分です。
(それを説明するには、どちらも十分な説明だったと思いますが。)

また、私はこの質問を、ポインタ変数を文字列で初期化した場合の、メモリとの関係について尋ねられているものだと思いました。
だとすれば、
> char *str[] = {0x61, 0x0, 0x64};
これでは文字列は生成されませんので、注意が必要です。
この記述では、それぞれのデータをアドレスとするポインタの配列ができるだけです。もちろん操作すると大変危険です。
    • good
    • 0

最近 C 言語をやっていないので懐かしいです。


char *str[] = {0x61, 0x0, 0x64};
なんていう宣言もありですね。

みなさんの回答でちょっと気になった点を。

(あくまで char型は「0~255の整数型」)
signed か unsigned は処理系次第ではなかったでしたっけ。

(関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。)
4バイトというのと、スタックに確保されるというのも、処理系次第ですよね。
最適化するとレジスタを使ってしまったりする事も。

なんんだかややこしい話ですね・・・
    • good
    • 0

おもしろい発想です。


C言語勉強し始めの頃は、こんな疑問に大いにぶつかってください。
今回は、皆様の言うとおり、はずれですが。

おまけ情報です。
char*はCスタイルの文字列と呼ばれますが、これは\0(0x00)までを文字範囲とする、という規定の基に、様々な操作がなされます。
確保した領域の中に\0が見つからなければ、文字列操作関数は、確保してある領域を超え、一般保護違反というエラーが発生する危険性を秘めます。

VBやJAVA、Perlの文字列は、\0で終わるという保証はなく、わざわざこの文字列は何文字あるという情報と一緒に、変数を管理します。
でも、これによって\0を途中に含む文字列が作れますし、確保した範囲を超えてアクセスする危険性も低くなります。

ポインタマニアの、はぽるんでした。
    • good
    • 0
この回答へのお礼

ありがとうございます。

お礼日時:2002/07/14 09:17

# 何か、メモリとポインタ変数との間に、変な誤解を持たれているようですが・・・



「文字列」というのは、確保されるものではありません。例えば、
  char *str = "abcd";
とすると、コンパイルした時点で、プログラム内部のどこかに 0x61, 0x62, 0x63, 0x64, 0x00(全部で5バイト)が用意されます。(文字列の最後には、'\0'が付加されることをお忘れなく!)
この「用意」というのは、「プログラム実行時にメモリを確保してデータが配置される」のではなく、「コンパイルされたプログラムに、その一部として既に存在している」ということです。
ソース名が hoge.c だとすれば、hoge.exe の中には、"abcd" が含まれているのです。

(つまり)文字列はプログラムの一部なので、プログラムがメモリ上にロードされた時点でアドレスが決定されます。"文字列" は、そのアドレスを持っています。

関数内で宣言された char * 型の str は、スタックメモリ上に確保されます。無論、確保されるサイズは4バイトです。
str = "abcd" となっているので、str の確保されている4バイトの領域に、"abcd" が存在するメモリのアドレスが代入されます。
プログラム実行時に行われるのは、たったこれだけです。
つまり、ポインタ変数 str と、"abcd" が存在するメモリの間には、そのアドレスを知っていること以外、何の関係もないのです。

alloc系関数を用いた動的メモリ確保の場合も同じです。
malloc は必要サイズのメモリを確保し、その先頭アドレスを返します。
→これをポインタ変数で受け取るのは、メモリにアクセスするのに必要だからであって、このポインタにメモリを割り当てるわけではありません。
次にこのメモリ領域を解放する場合、malloc が返したアドレスを使って、free が解放処理を行います。
→無論アドレスを受け取ったポインタ変数を解放するわけではありません。ポインタ変数を介して、確保したメモリのアドレスを free に知らせるだけです。
(ですので「ポインタを解放する」という表現は、明らかに正しくありません。)

話を質問に戻しますが、文字列 "abcd" が存在していた5バイトの領域が、勝手に使用されてしまうことはありません。
意図的に str[2] = 0 ('\0'であるべき) としても、その5バイトの領域の内容が 0x61, 0x62, 0x00, 0x63, 0x00 になるだけであって、解放とかそういう次元の話は、全く関係ありません。
表示した時に「ab」しか表示されないだけであって、
  str[2] = 'Z';
とすれば、「abZd」が、いつでも必ず表示されます。
    • good
    • 0

> このポインタ str は解放する必要がない。


むしろ、解放したらまずいです。

たぶん。判断されたのは
printfで表示しても
abしか出なかったからだと思いますが、これは\0(0x00)がCに置ける文字列の終わりを示すコードになっているからです。

もし、確保されていなければ、str[3]のアクセス時に不正終了しかねません。「確保されていないメモリ」にアクセスするわけですから。
    • good
    • 0

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