K.Maebashi's BBS

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

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

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

[2231] Re:間違い?
投稿者:(ぱ)こと管理人
2020/04/09 00:11:08

はじめまして。 >174ページ多次元配列の欄ですが配列が[5][3]ではじまって、 >175ページでi=2,j=3としますっていうのは整合性がとれていませんし、 >それによって多次元配列の説明が意味不明です。 まず、「C言語ポインタ完全制覇」の旧版(表紙に、「新・標準プログラマーズライブラリ」 ではなく、ただ「標準プログラマーズライブラリ」とあって、表紙がロボット型の コーヒーメーカーになっているもの)の話、ということでよいでしょうか? そして、 >174ページ多次元配列の欄ですが配列が[5][3]ではじまって、 これは、p.174の下から3行目の int hoge[3][5]; のことですか? ([5][3]ではなく[3][5]ですね?) そして、 >175ページでi=2,j=3としますっていうのは整合性がとれていませんし、 これはp.174で『hoge[i][j]という形でアクセスするとします』に続けての 図(Fig.3-15)の中で、『hoge[i][j]において、i == 2、j == 3の場合を考える』と 書いてあるところのことですよね? 2次元配列全体のサイズとして、int hoge[3][5];と宣言したうえで、その中の hoge[2][3]をアクセスするのは普通のことで、整合性がとれていないってことは ないと思うのですが、どうでしょうか。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2230] Re:間違い?
投稿者:ti
2020/04/08 23:31:56

>174ページ多次元配列の欄ですが配列が[5][3]ではじまって、175ページでi=2,j=3としますっていうのは整合性がとれていませんし、それによって多次元配列の説明が意味不明です。 175ページの i==2,j==3 が配列の添字(インデックス)という点はいいですよね。 hoge[2][3] 「配列が[5][3]ではじまって」が気になりますが、 私が持っている初版第2刷では 174ページの宣言は以下のようになっています。 int hoge[3][5]; /*これなら hoge[2][3] OK */ これが、(持っていないのでわからないが)あなたの持っている版で int hoge[5][3]; となっていれば、説明としてはインデックスに問題ある(j==3の方)と思います。 ということなのでしょうか。 ちなみに175ページ最初の「intの配列(要素数5)の配列(要素数3)」の説明は、 int hoge[3][5]; とあっています。 (「3-1-2 Cの宣言を解読する」参照) わかりにくいかもですが。 前橋先生に任せるべきだったかも。私の理解が間違ってるかもしれないし。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2229] 間違い?
投稿者:ta
2020/04/07 19:16:45

174ページ多次元配列の欄ですが配列が[5][3]ではじまって、175ページでi=2,j=3としますっていうのは整合性がとれていませんし、それによって多次元配列の説明が意味不明です。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2227] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/02/05 23:13:49

>printf() の実装は実際のところ 2222 の debug_write() と全く同じことが多くて、 >よって printf() のクロック数と debug_write() のクロック数は全く同じで、 まず、「ポインタ完全制覇」での記載は、 #ifdef DEBUG printf(表示したい内容); #endif という方法を 「こんなものをソース中に大量に埋め込んだら、読みにくくてしょうがありません。」 と書いたうえで、vfprintf()を使ったdebug_write()を紹介しています。 つまりdebug_write()の比較対象は、printf()ではなく、 #ifdefを使った完全に抹殺できるデバッグライトです。 >ついでに言うと printf() の処理中、文字化に要するクロック数と関数呼び出しクロック数では >後者は無視できるほど小さいっす。 >さらに追加すると標準出力へ出力する際の実処理のクロック数のほうがもっと多い。 >ボトルネックでないところのクロック数を頑張って減らしても全体の速度は大差ない。 で、vfprintf()を使ったdebug_write()にて、フラグか何かを参照し、 デバッグモードでないときは即座にreturnするようにしたとしても、 関数呼び出しそのもののオーバーヘッドは消せない、というのが趣旨なので、 「関数呼び出しのオーバーヘッド」と、「文字化や出力のオーバーヘッド」を 比べているわけではありません。 ただまあ、そのうえで、関数呼び出しのボトルネックだって無視できるほど小さい、 というのは、まあそうだろうなとは思います。ことがデバッグライトだけに、 「本番では死ぬほどループする処理に、1行おきにデバッグライトを入れた」という 状況はもちろん考えられますが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2226] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:774RR
2020/02/04 07:08:55

ああツッコミてー printf() の実装は実際のところ 2222 の debug_write() と全く同じことが多くて、 よって printf() のクロック数と debug_write() のクロック数は全く同じで、 ついでに言うと printf() の処理中、文字化に要するクロック数と関数呼び出しクロック数では 後者は無視できるほど小さいっす。 さらに追加すると標準出力へ出力する際の実処理のクロック数のほうがもっと多い。 ボトルネックでないところのクロック数を頑張って減らしても全体の速度は大差ない。 というわけで debug_write() を真に関数として実装して増えるのはプログラムバイト数だけ debug_write() の命令語数の分、せいぜい数十バイト、実行クロック数は同一 なのでこんなところに労力使うくらいなら、別のところでもっと有意義に使いたいっす。 C/C++ ユーザーは実行時クロックを1クロックでも減らしたがるけど、悪い癖っす。 まあ組み込み系だとその数クロック数バイトが重要だったりしますが・・・
[この投稿を含むスレッドを表示] [この投稿を削除]
[2225] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/02/01 23:26:52

あれっ、何か妙なことを書いていました。 >ただその下で、 >| C99ではマクロが可変長引数を取ることができるようになったので、 >| 以下のように書けるようになりました。 > >と書いておきながら、わざわざdebug_write()を呼んでいるのはちょっといただけないですね… C99なら可変長引数のマクロが使えるので、コンパイル時に完全に抹殺できます。 よって、fprintf()を呼んでももちろん良いですが、debug_write()を呼んでも 消えてなくなるので別段「ちょっといただけない」こともないですね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2224] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:(ぱ)こと管理人
2020/01/26 23:15:21

>細かいことで恐縮ですが、Fig2-10で「"&d, %s\n"へのポインタ」とありますが、 >「"%d, %s\n"へのポインタ」の誤植と思われます。 ご指摘ありがとうございます。ミスが多くて申し訳ありません。 この部分は旧版から変えていないところなので、旧版から20年間発覚しなかった ミスかと旧版の正誤表を確認したところ、どうも旧版は ・%dであるべきところが&dになっている ・\nが抜けている というふたつのミスがあり、前者に気づいていながら後者だけ直していたようです。 http://kmaebashi.com/seiha/seigo.html#p102 何が何だか……(後ほど直します) >#define DEBUG_WRITE(...) fprintf(stderr, __VA_ARGS__) >でもokでした。 >「debug_write()関数の呼び出しのオーバーヘッドは避けられない(p127)」という >ことでしたが、fprintf()関数でも同様でしょうか。 読み返すと確かにわかりにくいのですが、 「debug_write()関数の呼び出しのオーバーヘッドは避けることができません。」 という記述は、いわゆるANSI C(C90)についての記載と思ってください。 そのすぐ下に、「マクロなら、コンパイル時に完全に抹殺できるのですが、 ANSI Cまでは、マクロには、可変長引数を渡すことができませんでした。」 とあるとおりです。 ただその下で、 | C99ではマクロが可変長引数を取ることができるようになったので、 | 以下のように書けるようになりました。 と書いておきながら、わざわざdebug_write()を呼んでいるのはちょっといただけないですね… (わずかばかりのオーバーヘッドを考えるより、出力先をまとめて切り替えたり タイムスタンプを足したりする利便性を考えて、私なら、実際にはdebug_write()を 挟みそうな気がしますし、そういう思いだったのかと思いますが) 何かしら補足を考えます。ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2223] Re:ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:Hiroyuki Naito
2020/01/26 09:40:19

お世話になります。 3番目の質問については、本文の「原理はプリプロセッサのマニュアルを調べよ」にヒントを得て調べてみたら、自己解決しました。 >#define SNAP_INT(arg) fprintf(stderr, #arg "...%d", arg) >の中の#argは引数名そのものを指しているようですが、(他のC言語の解説書では)見たことのない使い方でした。できましたら、補足説明をお願いいたします。 「#演算子は、マクロ実引数を文字列化します」ということでした。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2222] ポインタ完全制覇(第2版) Fig2-10とデバッグライト
投稿者:Hiroyuki Naito
2020/01/26 08:29:45

お世話になります。 細かいことで恐縮ですが、Fig2-10で「"&d, %s\n"へのポインタ」とありますが、「"%d, %s\n"へのポインタ」の誤植と思われます。 私が使っているCコンパイラはgcc 5.4.1 c99でしたので、p128で紹介されている__VA_ARGS__を以下のように使ってみました。 void debug_write(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); } #define DEBUG_WRITE(...) debug_write(__VA_ARGS__) でもちろん動作OKでしたが、 #define DEBUG_WRITE(...) fprintf(stderr, __VA_ARGS__) でもokでした。 「debug_write()関数の呼び出しのオーバーヘッドは避けられない(p127)」ということでしたが、fprintf()関数でも同様でしょうか。 〈使用例〉 int i = 300; char *p = "hoge"; DEBUG_WRITE("%s %d\n", p, i); また、 #define SNAP_INT(arg) fprintf(stderr, #arg "...%d", arg) の中の#argは引数名そのものを指しているようですが、(他のC言語の解説書では)見たことのない使い方でした。できましたら、補足説明をお願いいたします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2219] Re:C言語ポインタ完全制覇(第2版) Fig2-8
投稿者:(ぱ)こと管理人
2020/01/25 00:22:40

正誤表に追加しました。ミスが多く申し訳ありません。 >onlineGDBというWeb上のCコンパイラで、コンパイルオプションをいろいろ試して >ist2-6と同じアセンブルリストが得られたので、本文に沿ってリストを追いかけてみて >気づいた疑問点でした。 おかげで他の方が混乱するのが避けられたと思います(正誤表を見に来た方に限りますが…)。 ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2218] Re:C言語ポインタ完全制覇(第2版) Fig2-8
投稿者:Hiroyuki Naito
2020/01/24 17:39:26

ご回答ありがとうございました。 >①「ローカル変数result」と「退避したベースポインタ」を書く場所を1段間違え、 >②「ベースポインタ」の右の矢印「→」をつけ忘れる onlineGDBというWeb上のCコンパイラで、コンパイルオプションをいろいろ試してist2-6と同じアセンブルリストが得られたので、本文に沿ってリストを追いかけてみて気づいた疑問点でした。 2.5.3までのところで、目からうろこ状態になってしまったのは以下の通りですが、今後もいろいろな発見がありそうなので期待しながら読み進めていきたいと思います。 (1)宣言のときの*や[](区切り子) は、式の中に現れる演算子の*や[]とは、まったくの別物。 (2)式の中では、配列は「その先頭要素へのポインタ」に読み替えられる。 (3)関数は、式の中では「関数へのポインタ」に読み替えらえる。 (4)関数funcへのポインタを格納するポインタ変数は、以下のように宣言する。 int (*func)(double); (5)関数へのポインタを使用したサンプルプログラム:List2-3 (6)自動変数の領域は、関数を抜けたら解放される。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2217] Re:C:言語ポインタ完全制覇(第2版) Fig2-8
投稿者:(ぱ)こと管理人
2020/01/22 00:56:40

はじめまして。ご指摘ありがとうございます。 >ベースポインタ-24、-28と「仮引数a,b」の位置関係が正しいとすると、ベース >ポインタとベースポインタ-4に格納される「退避したベースポインタ」とローカル >変数:resultの位置は、-4バイトずれていないでしょうか。 > >ベースポインタ:-20とベースポインタ:-4の間に、12バイト分のスペースしかない >のも少し気になりました。 申し訳ありません。誤植です。 言い訳になりますが、私が編集さんに渡したFig2-8の原本は以下です。 http://kmaebashi.com/etc/basepointer.png これをデザイナさんが書き直した際に、 ①「ローカル変数result」と「退避したベースポインタ」を書く場所を1段間違え、 ②「ベースポインタ」の右の矢印「→」をつけ忘れる というミスをされたようです。 もちろんゲラをチェックするのは私の仕事ですので、見落として本になって しまったのは私の責任です。 元の図も、「退避したベースポインタ」が4バイトに見える、というのは ちょっと問題ですね…… 正誤表に上げさせていただきます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2216] C:言語ポインタ完全制覇(第2版) Fig2-8
投稿者:Hiroyuki Naito
2020/01/20 21:05:36

お世話になります。 だいぶ前にpdf版を購入してからしばらくコンピュータの中で眠らせてしまって いましたが、一念発起して読み始めております。 さて、Fig2-8では、アセンブラが割り振るベースポインタとそこに格納される変数の 関係が示されています。 ベースポインタ-24、-28と「仮引数a,b」の位置関係が正しいとすると、ベース ポインタとベースポインタ-4に格納される「退避したベースポインタ」とローカル 変数:resultの位置は、-4バイトずれていないでしょうか。 ベースポインタ:-20とベースポインタ:-4の間に、12バイト分のスペースしかない のも少し気になりました。 以上、お手数ですがご回答をお願いいたします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2215] Re:c言語ポインタ完全制覇 realloc
投稿者:774RR
2020/01/14 14:23:20

>結局、巨大配列から動的に切り出す仕組みを作りかけたのを思い出しました。 それなんてオレオレ malloc ? 数バイト単位の alloc/free が高頻度で必要 L1 キャッシュヒット率を落とさないよう free 直後領域の再利用を優先するべし みたいな案件でオレオレ malloc/free 相当の関数は組んだことが過去にありました。 でも苦労した割にはそこがボトルネックではなかったでした。 それ以後は実測せずに思い込みの最適化をするなと口酸っぱく言ってます。 まあとりあえず p=realloc(p, sz); は一応注意喚起対象ってことで。 書籍の著者の掲示板まで読んでいる人には周知の事実かもしれませんが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2214] Re:c言語ポインタ完全制覇 realloc
投稿者:(ぱ)こと管理人
2020/01/12 17:02:50

>p=realloc(p, sz); のコードに対して静的解析ツールが警告出したりするので >QAC 絶対主義みたいな頭の固い上司がこのコードにウンと言わない場合が >あったりするとかなかったりするとか。 まあそれはそれで必然性がないわけでもないので、よろしいのではないでしょうか。 >組み込み系では RAM 8KiB をコード実装に入る前の設計段階で静的に割り振って >動的確保なんぞありえないってケースが大半なので、そういう点でオイラは楽できてます。 新人時代、ワークステーションなのに上司がmalloc()禁止と言い出して、 結局、巨大配列から動的に切り出す仕組みを作りかけたのを思い出しました。 (最終的には説得に成功した)
[この投稿を含むスレッドを表示] [この投稿を削除]
[2213] Re:c言語ポインタ完全制覇 realloc
投稿者:774RR
2020/01/08 06:54:29

お久しぶりです。1月に1回くらいは掲示板チェックしてましたよ。 > 「戻り値のチェックは省略しています」という言い訳を付けています。 それなら問題ないっす。この手の解説書き始めると数ページを要してしまうし、 紙面に制約がある状況で本筋からずれた詳細を記載してもねー、と思うわけっす。 # ページに余裕があるなら数行の「コラム」にするのはアリかもしれない。 p=realloc(p, sz); のコードに対して静的解析ツールが警告出したりするので QAC 絶対主義みたいな頭の固い上司がこのコードにウンと言わない場合が あったりするとかなかったりするとか。 組み込み系では RAM 8KiB をコード実装に入る前の設計段階で静的に割り振って 動的確保なんぞありえないってケースが大半なので、そういう点でオイラは楽できてます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2212] Re:c言語ポインタ完全制覇 realloc
投稿者:(ぱ)こと管理人
2020/01/08 02:18:07

おや、ごぶさたしております。 >オイラは買っていませんが [2206] で >> variable_array = realloc(variable_array, sizeof(int) * size); >と引用されていますね。典型的やってはダメと巷で解説されている例でしょう。 この箇所、書籍では、地の分で | List4-4では,ユーザーがint型の値を入力するたびに,realloc()を使って | variable_arrayを拡張しています(ここでも,戻り値のチェックは省略しています). と書いておりまして、「戻り値のチェックは省略しています」という言い訳を付けています。 realloc()の挙動を知るためのサンプルプログラムとしてはありではないでしょうか? ではサンプルではない場合にどうするかといえば、 malloc()だろうとrealloc()だろうと直接呼ぶのはそれ自体NGで、 なんらかのラップをかぶせ、「死ぬしかないにしても、(Segmentation faultではなく) メモリ不足で死んだことがわかるようにする」というのが最低限の対策だと 思っています。 >でもまあ realloc() に失敗するような状況だとほかの処理も一切できなくて >終了するしかない、ってのが実情で、 20年近く前に http://kmaebashi.com/programmer/c_yota/malloc.html の「戻り値チェック」のところにいろいろ書いてて、書籍の方にも似たことを 書いています。 JavaでOutOfMemoryErrorをcatchもしないくせに、Cでmalloc()の戻り値だけ 気にしたってしょうがない。それを言うならRubyなんてかつてはmalloc()が NULLを返しただけで(適切なエラーメッセージも出さず)Segmentation faultで 落ちまくってたぞ、と言いたいですねえ。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2211] c言語ポインタ完全制覇 realloc
投稿者:774RR
2020/01/06 19:18:48

オイラは買っていませんが [2206] で > variable_array = realloc(variable_array, sizeof(int) * size); と引用されていますね。典型的やってはダメと巷で解説されている例でしょう。 realloc() に失敗したとき nullptr が返され、旧 variable_array の領域を指すポインタがなくなってしまうので free() できなくなり、リークする というのがよくある解説なわけです。 でもまあ realloc() に失敗するような状況だとほかの処理も一切できなくて終了するしかない、ってのが実情で、 どうせ終了するんだったら現コードでもまいっかと思うわけですが Maebashi さんはどう思います?
[この投稿を含むスレッドを表示] [この投稿を削除]
[2210] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:Hello World
2020/01/05 12:09:19

回答ありがとうございます。 すぐに読ませていただきます。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2209] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:(ぱ)こと管理人
2020/01/03 21:13:33

>もう一つ質問があります。 >ポインタ完全制覇を読んでみて、処理系がどのようにプログラマーの書いたコードを >解釈しているのかが理解できれば、より理解が深まるなと考えています。 >そこで処理系に関するおすすめの書籍などがあれば教えていただけると非常に嬉しいです。 処理系に関する本、というと私が答えるなら当然これになるわけですが プログラミング言語を作る https://amzn.to/2szojNN 10年前の本なので新刊入手は難しいでしょうし、「機械語を生成するCコンパイラ」を 作っているわけではないのでHello Worldさんの目的にはちょっと合わないかもしれません。 Web版なら無料なのでよろしければどうぞ。crowbarはともかくDiksamの方は、 バイトコードコンパイル型の言語なのでCにも通じるところはあるかと思います。 http://kmaebashi.com/programmer/devlang/index.html 機械語を生成するCコンパイラの本であれば、私が大昔に読んだのはこれですが、 yaccによるCコンパイラプログラミング https://amzn.to/2SP8bT1 こちらも入手困難かもしれません(昔はマーケットプレイスでとんでもない高値が ついていました……)。 今なら、Rui Ueyamaさんの、こちらのページとかどうでしょうか(完結していませんが)。 https://www.sigbus.info/compilerbook
[この投稿を含むスレッドを表示] [この投稿を削除]
[2208] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:Hello World
2020/01/02 15:39:55

回答ありがとうございます。と共に返信遅くなり、申し訳ありません。 >はい。realloc()は引数で渡されたポインタとは異なるポインタを返すこともあります。 >2-6-6(p.147)にも書いたとおりです。 2-6-6 読み直しました。4章(List 4-4 realloc.c)で色々試したことにより深く理解することができました。 ありがとうございます。 >どこに疑問を持たれているのかいまひとつわかりませんが、 >確かにrealloc()は異なるアドレスを返すことがあります。 >たとえばrealloc()が6回目までは同じアドレスAを返し、7回目の呼び出しで >アドレスBを返したとして、Bを返すとき、realloc()は >A[0]~A[5]をB[0]~B[5]にコピーしてから返します。 >よって、このサンプルでは、17行目からのforループで値を表示することは >問題なくできます。 > >これで回答になっていますでしょうか? はい、的確な回答ありがとうございます。 17行目の部分も理解することができました。ありがとうございます。 >実験できる環境があるのでしたら、realloc()の下で実際にポインタの値を >表示してみると挙動がわかるかもしれません。 >具体的には13行目と14行目の間に以下の2行を挿入します。 > >printf("variable_array..%p\n", variable_array); >malloc(10); > >明らかに無駄に見える2行目のmalloc(10);は、realloc()で確保した領域の >続きを埋めることでrealloc()が別の領域を返すことを促すためのものです >(コンパイラが最適化で消してしまうかもしれませんが、私の環境(Linux上のgcc)では >最適化オプションを付けなければ大丈夫でした)。これを付けないと、 >何度呼んでもrealloc()は同じアドレスを返しました。後ろが空いているからでしょう >(p.147参照)。 > >上記2行を足すことで、私の環境では、realloc()は7回目で異なるアドレスを >返してきました。 アドレスを表示することは何度もやっていましたが、mallocにより別の領域を返すことを促す発想はありませんでした。 ちなみにわたしの環境では、realloc()は6回目で異なるアドレスを返してきました。 もう一つ質問があります。 ポインタ完全制覇を読んでみて、処理系がどのようにプログラマーの書いたコードを解釈しているのかが理解できれば、より理解が深まるなと考えています。そこで処理系に関する おすすめの書籍などがあれば教えていただけると非常に嬉しいです。 回答ありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2207] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:(ぱ)こと管理人
2019/12/29 14:42:22

はじめまして。 >realloc関数について man command で調べたところ(準拠 C89 C99)、返り値の項で >>「realloc関数は新たに割り当てられたメモリーへのポインタを返す。これはあらゆる >>組み込み型に対応できるようにアラインメントされており、ptrとは異なることも >ある。」と説明されています。 はい。realloc()は引数で渡されたポインタとは異なるポインタを返すこともあります。 2-6-6(p.147)にも書いたとおりです。 >List 4-4 realloc.cの17~19行目のfor文のブロックでsscanf関数によって >ヒープ領域にストアした値をprintf関数により、variable_array[i]という形で >参照しています。これは実際には *(variable_array + i) という形に >読み替えられていると思います。 ただ、上記のmanコマンドの返り値の項で >記述されている「ptrとは異なることもある」が実際に起こった場合、 >List 4-4 におけるptrつまりvariable_arrayが指し示すメモリアドレスが >一定ではなくなると思うので、そのメモリアドレスを起点にしてアクセスする >*(variable_array + i)は上手く目的の値をとってくることが、 >できないのではないでしょうか。 どこに疑問を持たれているのかいまひとつわかりませんが、 確かにrealloc()は異なるアドレスを返すことがあります。 たとえばrealloc()が6回目までは同じアドレスAを返し、7回目の呼び出しで アドレスBを返したとして、Bを返すとき、realloc()は A[0]~A[5]をB[0]~B[5]にコピーしてから返します。 よって、このサンプルでは、17行目からのforループで値を表示することは 問題なくできます。 これで回答になっていますでしょうか? >今まだ4章の途中ですが、本当にたくさんのことも学ぶことができています。 >自身の環境で実験をしながら試行錯誤ができ、とてもおもしろいです。 >本を書いてくださりありがとうございました。 ありがとうございます。 実験できる環境があるのでしたら、realloc()の下で実際にポインタの値を 表示してみると挙動がわかるかもしれません。 具体的には13行目と14行目の間に以下の2行を挿入します。 printf("variable_array..%p\n", variable_array); malloc(10); 明らかに無駄に見える2行目のmalloc(10);は、realloc()で確保した領域の 続きを埋めることでrealloc()が別の領域を返すことを促すためのものです (コンパイラが最適化で消してしまうかもしれませんが、私の環境(Linux上のgcc)では 最適化オプションを付けなければ大丈夫でした)。これを付けないと、 何度呼んでもrealloc()は同じアドレスを返しました。後ろが空いているからでしょう (p.147参照)。 上記2行を足すことで、私の環境では、realloc()は7回目で異なるアドレスを 返してきました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2206] c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:Hello World
2019/12/27 19:06:55

・realloc関数についての質問(p238 List 4-4 realloc.c)  realloc関数の呼び出しは13行目 variable_array = realloc(variable_array, sizeof(int) * size); realloc関数について man command で調べたところ(準拠 C89 C99)、返り値の項で 「realloc関数は新たに割り当てられたメモリーへのポインタを返す。これはあらゆる組み込み型に対応できるようにアラインメントされており、ptrとは異なることもある。」と説明されています。 man command のrealloc関数の書式は以下の通り。 void *realloc(void *ptr, size_t size); List 4-4 realloc.cの17~19行目のfor文のブロックでsscanf関数によってヒープ領域にストアした値をprintf関数により、variable_array[i]という形で参照しています。これは実際には *(variable_array + i) という形に読み替えられていると思います。 ただ、上記のmanコマンドの返り値の項で記述されている「ptrとは異なることもある」が実際に起こった場合、List 4-4 におけるptrつまりvariable_arrayが指し示すメモリアドレスが一定ではなくなると思うので、そのメモリアドレスを起点にしてアクセスする *(variable_array + i)は上手く目的の値をとってくることが、できないのではないでしょうか。 拙い文ではありますが、何卒よろしくお願いします。 今まだ4章の途中ですが、本当にたくさんのことも学ぶことができています。 自身の環境で実験をしながら試行錯誤ができ、とてもおもしろいです。 本を書いてくださりありがとうございました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2205] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:nana
2019/12/21 19:03:55

回答ありがとうございます。 なんとなく分かった気がします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2204] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:(ぱ)こと管理人
2019/12/21 18:06:45

すみません、不明点がいまいちよくわかりません。 >37行目 : read_slogan(stdin, slogan); のように なぜslogan のみで良いのか >理解できずにいます。 … >例えば、 char slogan[7]; を渡す場合は、 >配列は渡せないため、 slogan として配列の先頭要素へのポインタを渡すということは >一応理解できています。 おなじことです。 char slogan[7]; においてsloganの型は「charの配列」です。これを関数に渡すなら、 (配列は渡せないため)sloganとして配列の先頭要素へのポインタを渡します。 式の中では配列はポインタに読み替えられるので、sloganの型は 「charへのポインタ」となります。 char *slogan[7]; においてsloganの型は「charへのポインタの配列」です。これを関数に渡すなら、 (配列は渡せないため)sloganとして配列の先頭要素へのポインタを渡します。 式の中では配列はポインタに読み替えられるので、sloganの型は 「charへのポインタのポインタ」となります。 これで回答になっていますでしょうか?
[この投稿を含むスレッドを表示] [この投稿を削除]
[2203] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:nana
2019/12/20 16:27:08

回答ありがとうございます。 そのページも読んでいたはずなのですが、理解できていなかったようです。 追加で、もう一つ質問があります。 p.241 のList4-5に関してなのですが、 char *slogan[7]; を渡す際に、 37行目 : read_slogan(stdin, slogan); のように なぜslogan のみで良いのか理解できずにいます。 p.242 では read_slogan()関数には「charへのポインタの配列」を引数で渡していると 書いてありますが、なぜ slogan のみでcharへのポインタの配列を渡すことになるのかが 分かりません。 例えば、 char slogan[7]; を渡す場合は、 配列は渡せないため、 slogan として配列の先頭要素へのポインタを渡すということは 一応理解できています。 回答お願いいたします。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2202] Re:c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:(ぱ)こと管理人
2019/12/20 00:24:07

こんにちは。 >スタックというのは、データ構造なのか、そういった領域があるのか、 >いまいちわかっていません。 >スタックに積むという表現がp.111あたりにありますが、自動変数の場合は >CPUに組み込みで備わっているスタックという機能(データ構造)を使ってくれる >ということなんでしょうか? スタックという言葉自体は広くはデータ構造を指すので、配列や連結リストで スタックを作ることもありますが、Cにおける自動変数の領域の確保は、 通常はCPUに組み込みで備わっているスタックの機能を使います。 p.114 List 2-6のアセンブリ言語を見ると、%rsp(スタックポインタ)という レジスタが登場しています。これにsp(stack pointer)という名前が付いている ことから、このスタックがCPU組み込みの機能であることがわかるでしょう。 もし、CPUに組み込みのスタック機能がないとしたら、別のレジスタやメモリを スタックポインタに使って同等の機能を実現することはできるでしょうが、 その場合、pushq(List2-6の4行目)やpopq(16行目)のように、1命令でスタックに 値を積んだり取り出したりはできなくなります。スタックは有用な機能なので、 昔から、たいていのCPUには組み込みのスタック機能が付いています。 スタックの領域は、p.100のFig.2-3にあるとおり、仮想アドレスのどこかに OSにより割り当てられています。 >ヒープというのはもともとそういった領域が用意されているのでしょうか? これもp.100のFig.2-3にあるとおり、仮想アドレスのどこかにOSにより 割り当てられています。 >また、 >p.141には「malloc()の要求に対して十分な大きさの空きブロックがない場合、 >OSにお願いして領域を拡張してもらいます」 >と書いてあります。 >これは、もともとあるヒープ領域を拡張するという意味なのでしょうか? そうです。Fig.2-3の「malloc()により確保された領域」が下に伸びるイメージです。 >また、くだらないことかもしれませんが、 >p.285のList 5-5 >1行目 include <stdio.h>で # が抜けているように思います。 本当ですね。ご指摘ありがとうございます。正誤表に載せます。 (プログラムリストは、ソースから自動処理で編集さんに渡すテキストに 組み込んでいたので、元原稿にはコンパイルが通らないようなソースは ないのですが…… 編集段階で#が抜けてしまったようです。著者としては ゲラのチェックの段階で気付かなければいけなかったのですが…… もうしわけありません)
[この投稿を含むスレッドを表示] [この投稿を削除]
[2201] c言語ポインタ完全制覇(改訂版)に関する質問
投稿者:nana
2019/12/16 11:08:26

・スタックに関する質問 スタックというのは、データ構造なのか、そういった領域があるのか、いまいちわかっていません。 スタックに積むという表現がp.111あたりにありますが、自動変数の場合はCPUに組み込みで備わっているスタックという機能(データ構造)を使ってくれるということなんでしょうか? ・ヒープに関する質問 p.135にmalloc()は、...「ヒープからメモリを取ってくる関数」ということになります。 と書いてありますが、 ヒープというのはもともとそういった領域が用意されているのでしょうか? また、 p.141には「malloc()の要求に対して十分な大きさの空きブロックがない場合、OSにお願いして領域を拡張してもらいます」 と書いてあります。 これは、もともとあるヒープ領域を拡張するという意味なのでしょうか? 初歩的な質問かと思いますが、お答えいただけると嬉しいです。 また、くだらないことかもしれませんが、 p.285のList 5-5 1行目 include <stdio.h>で # が抜けているように思います。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2200] X-Drawのページの画像について
投稿者:(ぱ)こと管理人
2019/12/05 23:30:02

ポインタ完全制覇新版のX-Drawのページについて、 http://kmaebashi.com/seiha2/xdraw/index.html 画像がすべて表示できない状態になっていました。 画像ファイルがサーバになくて、404状態でした。 原因はわかりませんし、いつからこの状態だったのかもわかりません (もしかして最初から?)。 ひとまず再アップロードしておきました。 ご迷惑をおかけしまして申し訳ありません。
[この投稿を含むスレッドを表示] [この投稿を削除]
[2199] Re:ポインタ完全制覇 - read_slogan.c
投稿者:(ぱ)こと管理人
2019/11/16 02:04:54

はじめまして。ご指摘ありがとうございます。 >buf[slogan_len - 1] = '\0'; > >したあと、 > >slogan[i] = malloc(sizeof(char) * (slogan_len + 1)); > >していますが、bufの大きさは、slogan_len byteで十分なので、 通常、文字数がlenのとき、'\0'の分を含めてlen+1だけmalloc()するのが 定石ですが、このケースではslogan_lenは改行文字を含んでいて、 その改行文字を'\0'に置き換えるので、malloc()するのはslogan_lenの 分だけでよいですね。 改定前のものからのミスだと思います。正直、まだポカが残っているとは 思いませんでした…… 正誤表に入れさせていただきます。
[この投稿を含むスレッドを表示] [この投稿を削除]