K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[926] 質問してもよろしいでしょうか?
投稿者:たけ
2007/02/20 02:13:25

初心者で変な質問をしているかもしれませんが、 教えていただけると助かります。 以下のコードはC言語で許されますか? char buf[10]; char *cp; if (buf[10] != '1'){ printf("array[10]=%c",buf[10]); } cp = buf; if (*(cp + 10) != '1'){ printf("pointer[10]=%c",*(cp + 10)); }
[この投稿を含むスレッドを表示] [この投稿を削除]
[927] Re:質問してもよろしいでしょうか?
投稿者:774RR
2007/02/20 02:13:25

buf[10] で、無いオブジェクトの中を見に行っている時点で許されない。 *(cp+10) も同様。 ただし &buf[10] や cp+10 は許されるというあたりが微妙なところであったりする。
[この投稿を含むスレッドを表示] [この投稿を削除]
[928] 774RRさん、お返事ありがとうございます。
投稿者:たけ
2007/02/20 02:13:25

>buf[10] で、無いオブジェクトの中を見に行っている時点で許されない。 >*(cp+10) も同様。 >ただし &buf[10] や cp+10 は許されるというあたりが微妙なところであったりする。 明日試してみます。 私は去年の4月から、プログラマーとして、仕事をしています。 配列やポインタの勉強は大変ですが、C言語が面白くなってきたところです。 たまには、酒でも飲みたいのですが、みんな忙しくて、機嫌が悪いです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[929] Re:774RRさん、お返事ありがとうございます。
投稿者:(ぱ)こと管理人
2007/02/20 02:13:25

昨晩は「寒いから暖房が効くまで布団の中で本でも読んでよう」と思いつつ気が付いたら朝でした。こんなのばっか。 >>buf[10] で、無いオブジェクトの中を見に行っている時点で許されない。 >>*(cp+10) も同様。 >>ただし &buf[10] や cp+10 は許されるというあたりが微妙なところであったりする。 > >明日試してみます。 ええと、試してみたところで「動いてしまう」可能性がそれなりにあります。 Cでは、配列の範囲を超えたところをアクセスしても、普通はエラー等にはならず、ずっと離れたところでプログラムがクラッシュしたりします。 それはさておき、「たけ」さんのサンプルプログラムでは、代入もしていない「buf[10]」の中身をいきなり参照していますが、それで「'1'」が入っていることを期待しているわけではないですよね? そもそも本当は何を聞きたかったのかが疑問です。 774RRさんのご指摘どおり、char buf[10];で宣言した配列のbuf[10]は参照できませんが、 char buf[10]; char *cp; cp = buf; として、*(cp + 3)とかを参照するのは合法です。buf[3]と同じものが見えます。 ただし、「*(cp + 3)」のようなわかりにくい書き方をするよりは、cp[3]と書いたほうがよいでしょう。これもbuf[3]と同じものが見えます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[932] Re:774RRさん、お返事ありがとうございます。
投稿者:774RR
2007/02/20 02:13:25

御意。およそ何がしたいのか意図がつかめないので、あの程度のコメントとなった次第。 あえてもっと詳しくコメントしてみるテスト char buf[10]; は char が 10 個の配列、の意味。10個の内訳は buf[0] .. buf[9] の10個 // 0から開始するので ということは buf[10] は存在しないので、その中身を使ってはならない。 もちろん buf[-1] や buf[-2] や buf[11] や buf[498914] 等も全部ダメ。 char *cp=buf; は char *cp=&buf[0]; の短縮形であるため cp は buf[0] を指す。 んでそもそも buf[1] ってのは *(&buf[0]+1) のこと。 cp[1] も *(cp+1) のこと。 だからこの場合 cp[1] と buf[1] は同じところを意味する。 cp=&buf[1]; とか cp=buf+1; とかすれば cp は1つずれるわけだ。 なのでこうすると、 cp がずれてる分 cp[2] と buf[3] が同じところを意味する。 当然 cp[9] は buf[10] に相当するので前述のごとくこれも使っちゃダメ。 あと配列外をアクセスするとダメってことの解説。 多くの場合配列外に相当するメモリ/アドレス表現は存在していたりする。 存在するけど、そこは他の変数だったり、他の重要な情報だったりする。 ということで配列外をアクセスすると他の変数を壊す=遠くでクラッシュしたりする。 エラーを OS/CPU が検出してくれる場合もあるが、多くは検出なしにメモリを壊すだけ。 OS/CPU が検出をサボってよい代わりにプログラマが細心の注意を払え、ってのが C/C++ その分、正常に動いている限りにおいては他言語より高速なプログラムが書けたりする。 これとは別に 配列外のオブジェクトの中身を見てはならない (buf[10] はダメ) んだけど 配列直後に限りアドレスを計算しても良い (&buf[10] はOK) という決まりがある。 for (i=0; i<10; ++i) buf[i]=0; と書いてよいごとくに for (cp=&buf[0]; cp<&buf[10]; ++cp) *cp=0; と書いてよいということ。 直後以外はダメ。なので &buf[11] や &buf[-1] は計算しちゃダメ。 計算したらエラーになるかもしれないし、 エラーにならずにおかしな値が得られるかもしれない。 C/C++ は「やっちゃだめ」なことをしたときに「何が起こるかわからない」のだ。 これを「鼻から悪魔が飛び出してもかまわない」と表現したりする。 何が起こるかわからない=エラー発生、ならまだ良かったりする。 何が起こるかわからない=一見、プログラマの期待通りに動いたりする、こともある。 後者は怖いよー。
[この投稿を含むスレッドを表示] [この投稿を削除]
[938] Re:774RRさん、お返事ありがとうございます。
投稿者:undo
2007/02/20 02:13:25

>Cでは、配列の範囲を超えたところをアクセスしても、普通はエラー等にはならず、ずっと離れたところでプログラムがクラッシュしたりします。 この記述の「アクセス」というのは書き換えを意図しているんだと思います。 コンパイラ、ランタイム、参照アドレスによっても違うでしょうが、 無関係なところを参照してアドレスエラーや境界チェックエラーなどになれば、その場でクラッシュするでしょう。 その場でエラーにならなければ参照しているだけですから、通常その後にはクラッシュしません。 buf[10]を参照することに意味があるとは思いませんが(^^;
[この投稿を含むスレッドを表示] [この投稿を削除]
[939] Re:774RRさん、お返事ありがとうございます。
投稿者:yuya
2007/02/20 02:13:25

> その場でエラーにならなければ参照しているだけですから、通常その後にはクラッシュしません。 例えばbufが関数へのポインタの配列だったりすると、 誤って取得しちゃったbuf[10]の値に従って関数を呼び出すかもしれないわけですよね。 こういう場合、 「参照だけして、ずっと先でクラッシュしてしまう(or してくれる)」という事態は、 そんなに珍しいことではないように思うのですが。 そういう話をしているのではない!?ならゴメンナサイ。 たけさんが初めに出した例(要素の値を表示するだけ)であれば きっとクラッシュしないでしょうけど。
[この投稿を含むスレッドを表示] [この投稿を削除]
[940] Re:774RRさん、お返事ありがとうございます。
投稿者:(ぱ)こと管理人
2007/02/20 02:13:25

ああ、確かにちょっと不正確な書き方でしたね。 >>Cでは、配列の範囲を超えたところをアクセスしても、普通はエラー等にはならず、ずっと離れたところでプログラムがクラッシュしたりします。 Cでは、配列の範囲をちょっと越えたところに書き込んでも、普通はエラー等にはならず、ずっと離れたところでプログラムがクラッシュしたりします。 と訂正します。 >無関係なところを参照してアドレスエラーや境界チェックエラーなどになれば、その場でクラッシュするでしょう。 >その場でエラーにならなければ参照しているだけですから、通常その後にはクラッシュしません。 わかって書いておられるとは思いますが、「その場でエラーにならなければ参照しているだけ」とは限りませんよね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[942] Re:774RRさん、お返事ありがとうございます。
投稿者:(ぱ)こと管理人
2007/02/20 02:13:25

>例えばbufが関数へのポインタの配列だったりすると、 >誤って取得しちゃったbuf[10]の値に従って関数を呼び出すかもしれないわけですよね。 他にもポインタの配列だったり、intの配列でもそれが別の配列の添字になっていたりとか。 >たけさんが初めに出した例(要素の値を表示するだけ)であれば たけさんの最初の例だと、ひとつだけ超えたところですからたぶん書き込んでも死なないんですよね。 この辺の「不定」さがCの難しさではありますが、たとえばJavaでもマルチスレッドなら結果が予測できないことはいくらでもあるので、「ダメなコードは何をしでかすかわからない」ことは結局理解しなければいけないことだよなあ、と思ったり。
[この投稿を含むスレッドを表示] [この投稿を削除]
[943] Re:774RRさん、お返事ありがとうございます。
投稿者:undo
2007/02/20 02:13:25

>> その場でエラーにならなければ参照しているだけですから、通常その後にはクラッシュしません。 > >例えばbufが関数へのポインタの配列だったりすると、 >誤って取得しちゃったbuf[10]の値に従って関数を呼び出すかもしれないわけですよね。 そうですね。 初期化していないデータをポインタとして参照したら、不正なアドレスですから、いつクラッシュしてもおかしくないですね(^_^) # 無謀なキャストも同様ですね。 書き方が少し変でした。 「(参照しているだけですから)その場でエラーにならなければ、通常その後にはクラッシュしません。」 というつもりでした(_ _)
[この投稿を含むスレッドを表示] [この投稿を削除]