ページ 11

文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 13:29
by ゆーずぃ
ふと疑問に思ったのですが、ポインタに直接文字列を代入した場合ポインタのアドレスは一つずつ増加していくと思うのですが、もし極端に長い文字列を代入した時に途中で使用中のアドレスとぶつかったらどうなるのでしょうか?
ちょっと分かりづらいと思うのですが(;^^)
例で書くと、

(*pが確保していない状態の) *p[10000] のアドレスが別の何かで使用中だった場合、
*p = "abcdefg......" ←10000文字を超える文字列

を代入したらどうなるのかと思ったのです。上書きされるのか、メモリの再配置か何かで邪魔者をどけてくれるのか…。
的外れなことを言っているかもしれませんが、分かる方がいらっしゃいましたら是非ご回答をお願いします。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 13:58
by へろりくしょん
言いたいことが今ひとつ解りません。

基本的に自動変数は勝手にスタックに積まれます。
必要なサイズ分を順番に積んでいくので、スタック上に確保した(スタックははじめから確保されてますが)領域がかぶる事はあり得ません。 もしあったらコンパイラのバグです。

malloc() calloc() realloc() 等のメモリアロケート系の関数はすでに確保した領域とかぶらないようにします。
もし、領域がかぶってしまったらやっぱりそれもコンパイラのバグです。


通常文字列定数は定数領域にこっそりと配置されています。 *p が確保していない状態というのが解りませんが、*p が宣言されていようがいまいが、領域を確保していようがいまいが、文字列定数ははじめからこっそりと定数領域に配置されています。


スタックにしろヒープにしろ、きちんと確保した領域はその領域内で使う限り、安全に使える事が保証されています。
でないとプログラムなんてまともに走りませんよ。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 14:50
by dic
いいたいことと違ったレスかもしれないですが
ポインタがうまく使えてないかもしれないので
ポインタのサンプルを書いておきます
#include <stdio.h>

int main()
{
    char    *p;
    char    hello[100] = "hello world";

    p = hello;

    printf( "%s\n", p );

    return 0;
}

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 15:33
by ゆーずぃ
へろりさん、dicさん、早速のご回答と丁寧なレスをありがとうございます。

>ポインタがうまく使えてないかもしれないので
確かに最近理解したばかりなので危ういところはあります;


>言いたいことが今ひとつ解りません。
すみません;
何かで読んだのですが、確かポインタに代入するアドレスは変数や定数のアドレスじゃなくても自分で無理やり設定することができるんですよね?(コンパイル環境のせいかもしれませんが、自分ではそのやり方が分からなくて実験することができなかったのですが;)

そこで例えばですね、元々アドレス0x00000008に値'A'が入っていたとします。
そこでchar型のポインタ変数pをアドレス0x00000002で無理やり初期化します。
その上で p = "abcdefghijklmn..." とした場合に、aから順に
0x00000002 = a
0x00000003 = b
0x00000004 = c
0x00000005 = d
.....
となっていくと思うのですが、この時にアドレス0x00000008に入っていた値'A'は上書きされるのかどこか違うアドレスに再編されるのかと…。

イメージのソースはこんな感じです。
#include <stdio.h>

int main(void){

    char *px;
    char *py;

    px = 0x00000008;  //アドレスを無理やり設定(やり方は間違っているのでしょうが;)
    px = 'A';         //アドレス0x00000008に入っているはず?

    py = 0x00000002;  //アドレスを無理やり設定(やり方は間違っているのでしょうが;)
    py = "abcdefghijk";  //アドレス0x00000002から始まるはず?

    /* アドレス0x00000008にあった'A'はどうなる? */

    return 0;
}
なんとなく伝わるといいなと思います;

また別の言い方をすれば、あまりにも巨大すぎて連続するアドレスを確保できなかった配列変数はどうなるのか、と”似たような”感じです…。

分かりづらくてすみませんが、お願いします‥。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 15:47
by へろりくしょん
言いたいことは解りました。

結論から言うと上書きされます。

C言語において代入は常に破壊的コピーです。

>px = 0x00000008; //アドレスを無理やり設定(やり方は間違っているのでしょうが;)

間違ってはいません。 処理系によっては警告を出すでしょうが間違ってはいません。
組み込み系ではよく見る書き方ですね。
グラフィック用のメモリに直接アクセスするとかなんとか。


ただ、ポインタが返すアドレスはメモリアドレスではありません。
多くの処理系で単にメモリアドレスを返すのも事実ですが、規格上メモリアドレスではありません。
ただ、ポインタが持つ値をアドレスと呼んでいるに過ぎません。
具体的にその値がなんなのか、それはプログラマが知り得るところではありませんし、また知ろうとしてもいけません。

ポインタはただ、インスタンスの在りかを指し示すもの。 ただそれだけです。


C言語は非常に原始的な言語ですから、上書きされそうだから元あるデータをちょっとよそに避難避難。 なんて高等な事はやってくれません。
プログラマは神であり、間違いなんて無い無い。 コンパイラはそう思ってます。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 15:57
by へろりくしょん
読み逃してました。

>また別の言い方をすれば、あまりにも巨大すぎて連続するアドレスを確保できなかった配列変数はどうなるのか、と”似たような”感じです…。


メモリアローケート系の関数はNULLを返します。
スタックが足りなくなった場合はプログラムは落ちます。SIGSEGVあたりが投げられるでしょう。


>py = 0x00000002; //アドレスを無理やり設定(やり方は間違っているのでしょうが;)
>py = "abcdefghijk"; //アドレス0x00000002から始まるはず?

ちなみに、この時の py には、"abcdefghijk" が格納されている定数領域のポインタが代入されています。
0x02へのアクセスは行われていません。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 17:29
by ゆーずぃ
へろりさん、続けてのご回答ありがとうございます!

>ただ、ポインタが返すアドレスはメモリアドレスではありません。
多くの処理系で単にメモリアドレスを返すのも事実ですが、規格上メモリアドレスではありません。
ただ、ポインタが持つ値をアドレスと呼んでいるに過ぎません。
具体的にその値がなんなのか、それはプログラマが知り得るところではありませんし、また知ろうとしてもいけません。

ポインタはただ、インスタンスの在りかを指し示すもの。 ただそれだけです。



なるほど!私の疑問と冒頭のスタックの説明が理解できました!本当にありがとうございます。

迷惑ついでにもう一つご質問すると、

>ちなみに、この時の py には、"abcdefghijk" が格納されている定数領域のポインタが代入されています。
0x02へのアクセスは行われていません。

というご指摘の中の、定数領域というのはどういったものなのでしょうか?少し調べましたところ、他にもテキスト領域やヒープ領域というものも出てきたのですが、わかりやすく説明してあるHPが見つかりませんで;スタック領域やヒープ領域は分かるのですが、出来れば定数領域(とテキスト領域)の説明もして頂けませんでしょうか?;

すみませんが、宜しくお願いいたします。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 17:40
by toyo
char *px;

px = (char*)0x00000008; // ポインタならちゃんとキャストしましょう
*px = 'A';
こういうのは環境によってはまったく問題ありません
ポインタがIOに割り当てられたりとか普通にあります
メモリマップがわかっていて自分で管理する環境もあります

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月06日(火) 18:18
by たかぎ
> (*pが確保していない状態の) *p[10000] のアドレスが別の何かで使用中だった場合、
> *p = "abcdefg......" ←10000文字を超える文字列
>
> を代入したらどうなるのかと思ったのです。上書きされるのか、メモリの再配置か何かで邪魔者をどけてくれるのか…。

使用中というのが、どういう状況なのかによります。
シングルプロセッサの環境で、別のタスク(あるいはスレッド)や割り込みハンドラで同時更新が起きた場合は、上書きといえば上書きになります。
ただし、型によっては代入がアトミックオペレーションになりませんので、中途半端に上書きされる可能性があります。

マルチタスク環境では、上記に加え、バスの調停方法がどうなっているのかに依存します。

Re:文字列操作時のメモリの使われ方について

Posted: 2010年7月11日(日) 19:48
by ゆーずぃ
toyoさん、たかぎさん、ご回答ありがとうございます!私用でパソコンの使えない環境へと出掛けていたため、お礼が遅くなって申し訳ありませんでした;
これからも宜しくお願いいたします。

>toyoさん
>px = (char*)0x00000008; // ポインタならちゃんとキャストしましょう

最初見たときは何をしているのか、何故キャストをするのかが分からなかったのですが、何度も読み返すうちになんとなく分かりました。初めてそういった方法を見たので、とても勉強になりました!ありがとうございます。


>たかぎさん

たかぎさんの深い知識、いつも大変尊敬しております。耳慣れない言葉もありますが、そういったお話をして頂けると調べることも出来て大変勉強になります。ありがとうございました!

皆さんありがとうございました!これをもって解決とさせて頂きます!