トップページ⇒tech
1001コメント292KB

C言語なら俺に聞け(入門篇) Part 43

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2009/01/24(土) 19:00:13
C言語の入門者向け解説スレです。

教えて欲しいのではなく宿題を丸投げしたいだけなら
↓宿題スレ↓へ行ってください。
 C/C++の宿題を片付けます 122代目
 http://pc11.2ch.net/test/read.cgi/tech/1232001038/

・C++言語はスレ違いです。
・分からない事をなるべく詳しく書いて下さい。
・ソースコードを晒すと答えやすくなるかもしれません。
  # 抜粋/整形厳禁、コンパイラに渡したソースをそのまま貼ること
  # サイズが大きい場合は宿題スレのアップローダ等を利用してください
・開発環境や動作環境も晒すと答えが早いかもしれません。
・質問者は最初にその質問をした時のレス番号を名前欄に書いて下さい。

前スレ
C言語なら俺に聞け(入門篇) Part 42
http://pc11.2ch.net/test/read.cgi/tech/1231180205/
過去スレ
  http://makimo.to:8000/cgi-bin/search/search.cgi?q=%82b%8C%BE%8C%EA%82%C8%82%E7%89%B4%82%C9%95%B7%82%AF&andor=AND&sf=0&H=&view=table&D=tech&shw=5000
0153デフォルトの名無しさん2009/01/27(火) 00:59:47
ないない。
そんな考えがあったら [ ] で配列とポインタを同じように扱えるようにしないって。
0154デフォルトの名無しさん2009/01/27(火) 01:01:08
スレ違いではあるけどC++もあることだしもうむりだろ.にするのは
0155デフォルトの名無しさん2009/01/27(火) 01:01:40
C++だとオーバーロードが絡むからな。
0156デフォルトの名無しさん2009/01/27(火) 01:01:43
>>151
えー、どこが。
それこそ、p[n]と*(p+n)を別にすべきってことじゃん。
0157デフォルトの名無しさん2009/01/27(火) 01:02:21
×別にすべき
○別にしとけばよかった
0158デフォルトの名無しさん2009/01/27(火) 01:02:56
>>156
作り辛くしてでも分かりやすくしたかったんだろう。
0159デフォルトの名無しさん2009/01/27(火) 01:03:37
. でいいんじゃね?
ということに当時の人が気付かなかった可能性も
0160デフォルトの名無しさん2009/01/27(火) 01:04:57
もう寝る
願わくばうちの会社に>>114が来ませんように
0161デフォルトの名無しさん2009/01/27(火) 01:05:01
ところで>>153は>>152じゃなくて>>151へだよね?
そうじゃないと意味が伝わらない。
0162デフォルトの名無しさん2009/01/27(火) 01:05:38
>>161 は文盲
0163デフォルトの名無しさん2009/01/27(火) 01:06:53
>>147
お前mallocしたことないの?
0164デフォルトの名無しさん2009/01/27(火) 01:07:33
>>160
大丈夫。わざわざITドカタになるってわかってるところへ就職を希望する人なんて、
この不景気でもそんなには居ないでしょ。
0165デフォルトの名無しさん2009/01/27(火) 01:08:15
素人宣言ktkr
0166デフォルトの名無しさん2009/01/27(火) 01:08:39
>>162は、皮肉という言葉を知らない、日本語の苦手な人
0167デフォルトの名無しさん2009/01/27(火) 01:10:04
>>166
理解できなかった事を今更誤摩化そうとしても遅いよ
0168デフォルトの名無しさん2009/01/27(火) 01:10:32
>>163
ポインタは p++ したり *p したりするべきものだ、
と言ってるんだろう。
たとえどんな時でも。
ばからしい話だが。
0169デフォルトの名無しさん2009/01/27(火) 01:10:44
>>163
おまえ、関数の引数にポインタ渡したことないの?
それとももしかして、1関数300行くらいにして、全部関数内で処理してるの?
0170デフォルトの名無しさん2009/01/27(火) 01:11:07
(flg ? struct : ptr).member
とかやってもいい?
0171デフォルトの名無しさん2009/01/27(火) 01:11:33
釣りが増えて来たな
0172デフォルトの名無しさん2009/01/27(火) 01:12:54
そんなことより純粋に知りたいのですが参照のコストが違うとはどういうことですか?
0173デフォルトの名無しさん2009/01/27(火) 01:13:15
>>169
>そもそも、ポインタなんだから、増減して使うのが当たり前なのに
がおかしいって、mallocっていう反例を示して指摘してるのに、なにが言いたいの?
0174デフォルトの名無しさん2009/01/27(火) 01:15:58
>>172
->は参照先アドレスが実行時に決まるのに比べて、
. はリンク時に決まるってこと。
0175デフォルトの名無しさん2009/01/27(火) 01:16:07
>>170
まずいんじゃね?
0176デフォルトの名無しさん2009/01/27(火) 01:17:52
>>174
いえそっちではなく、>>114の話です
0177デフォルトの名無しさん2009/01/27(火) 01:18:41
>>174
構造体を持つ構造体を、mallocすること考えただけでもそれはありえなくないか?
0178デフォルトの名無しさん2009/01/27(火) 01:19:34
>>176
ポインタpの指すアドレスは実行時に決まるのに比べて、
配列arrayのアドレスはリンク時に決まるってこと。
0179デフォルトの名無しさん2009/01/27(火) 01:19:59
pがレジスタに割り当てられたら差はないし、
インライン最適化されれば配列そのものが使われるかもしれない。
コストを明示したつもりでも、実際コストに差はないかもしれない。
そんなあやふやな意味の無いものを明示する暇があったら
もっと分かりやすく書け。
0180デフォルトの名無しさん2009/01/27(火) 01:20:42
いや、まじめな話、「一般的には」だけれど、

関数内だけで使うローカルな領域をmallocすることなんてそんなに多くないでしょ。
多くは、構造体のメンバとかに置いて、外部とのやり取りに使うためのもの。
だから、後でfreeするための元のアドレスはそのメンバが持っていて
個々の関数ではその値のコピーを使って操作することの方が多いでしょ。
いや、(コピーじゃなくて)直接使うケースが少ないとは言わないけどさ。

で、まあ、確かにローカルで使用するにしても
不定長のバッファなんかは必要ではある。
ただ、この用途は(C++で済まんが)vectorばっか使ってるから
malloc(operator new)することなんか殆ど無いし。

特に、配列として確保したもの(1個のオブジェクトではなく)は
ループを回したりするわけだから、コピーしてレジスタ割付なんかも期待したいところ。
そんな変数を増減するのは、ちっとも不思議じゃなく当たり前の話じゃないかね。
0181デフォルトの名無しさん2009/01/27(火) 01:20:50
>>177
簡略化した説明なので、そこまでは勘弁ね
0182デフォルトの名無しさん2009/01/27(火) 01:22:00
>>178
それは配列とポインタの違いであって*(p+n)とp[n]の違いじゃないと思うんだが
0183デフォルトの名無しさん2009/01/27(火) 01:25:51
>>176
配列(の先頭アドレス)は「定数」だから、コンパイル時に決まる。
それがグローバルかスタックフレームの相対アドレスか構造体内のオフセットかはともかく。

一方、ポインタは「変数」だから、(レジスタ変数にされない限り)メモリを読み出して
その値を得、それにオフセットを加えて参照先を決定する必要がある、ということ。
0184デフォルトの名無しさん2009/01/27(火) 01:26:49
>>183
C99ではそうではないとか言い出してみる
0185デフォルトの名無しさん2009/01/27(火) 01:27:13
>>178
>>182
>>183
理解できたと思いますが
要するに>>114は何か勘違いしてるってことですか?
0186デフォルトの名無しさん2009/01/27(火) 01:27:51
>>180
不思議ではないが当たり前でもないよ
0187デフォルトの名無しさん2009/01/27(火) 01:29:29
>>186
で?
0188デフォルトの名無しさん2009/01/27(火) 01:29:34
>>182
日本語力の無い俺には>>114をよく読むほど意味がわからなくなってきたw
少なくとも、*(p+n)とp[n]には見た目以外の違いは何も無いよ。
0189デフォルトの名無しさん2009/01/27(火) 01:31:27
>>174
つーか普通に関数呼び出しの時にアドレス決まるんじゃないの?
グローバル変数以外
0190デフォルトの名無しさん2009/01/27(火) 01:32:15
「ポインタなんだから、増減して使うのが当たり前」っていう極論が否定されてるだけで、
増減すること自体は誰も否定してないだろ。
01911742009/01/27(火) 01:34:09
なんか突っ込みが多いので訂正するよ!
->は. より間接参照が1回多い分コスト高だってこと。
0192デフォルトの名無しさん2009/01/27(火) 01:35:54
配列に添え字(変数)でアクセスしようが、
ポインタでアクセスしようが一緒。
0193デフォルトの名無しさん2009/01/27(火) 01:38:14
こっちでやれ

【初心者お断り】ガチ規格準拠C専用スレ Part133
http://pc11.2ch.net/test/read.cgi/tech/1201153965/
0194デフォルトの名無しさん2009/01/27(火) 01:40:59
>>190
何言ってんだ。
後で触れているという点は除くにしても、話の流れ的に
p[n]や*(p+n)として使うくらいなら、pを増減する方が普通ということだろ。
特にわざわざそのためだけに添え字変数を用意するくらいなら。
もちろん、配列として確保したメモリ限定の話な。
0195デフォルトの名無しさん2009/01/27(火) 01:41:54
>>188
その点を否定している人は誰もいないと思われます。
0196デフォルトの名無しさん2009/01/27(火) 01:42:56
>p[n]や*(p+n)として使うくらいなら、pを増減する方が普通ということだろ。
ね え よ
0197デフォルトの名無しさん2009/01/27(火) 01:44:04
>>188
配列とポインタの違いはわかってますよね?

>>196
初心者スレですもんね。
0198デフォルトの名無しさん2009/01/27(火) 01:45:23
>>197
もちろんわかってますよ
0199デフォルトの名無しさん2009/01/27(火) 01:46:55
>>191
そりゃ (* hoge).なにか
と等価なんだから当たり前だろ・・・・・・・
0200デフォルトの名無しさん2009/01/27(火) 01:47:35
>>198
じゃあ>>191の内容はわかってますよね、当然。
0201デフォルトの名無しさん2009/01/27(火) 01:49:09
違いがあるのは配列とポインタであって[]と*(+)ではない
手に持ったゴミを焼却炉に放り込むときに「燃やす」、
ごみ箱の中身を放り込むときに「焼却する」と言い換えてるようなものだ
0202デフォルトの名無しさん2009/01/27(火) 01:49:13
>>200
わかってますよ、自分の発言ですから。
0203デフォルトの名無しさん2009/01/27(火) 01:52:38
じゃあ、ポインタ経由のインデックスアクセスと、配列からのインデックスアクセスで
コストが違うこともわかってますよね?
それと、p[n] と *(p+n) は全く同じ、ということをあわせて
敢えて違うということを明示するという意図(それに意味があるかはともかく)もわかりませんか?
0204デフォルトの名無しさん2009/01/27(火) 01:54:38
>敢えて違うということを明示するという意図(それに意味があるかはともかく)もわかりませんか?
だからそれがバカなこと以外の何物でもないとずっと言ってるんだろうが
0205デフォルトの名無しさん2009/01/27(火) 01:56:26
>>203
コーディングした人の好みの問題ですよね、わかります。
0206デフォルトの名無しさん2009/01/27(火) 01:57:41
Q. ポインタは本当に配列より高速なのか。

A. たいていは大きな配列の中をアクセスしてまわるのにポインタを使うほうが、
配列の添字を使うより高速であるが、その反対のプロセッサも存在する
(よくできたコンパイラならどちらの記法を使って書かれたコードにも
良質なコードを生成すべきである)。

  CFAQ 20.14
0207デフォルトの名無しさん2009/01/27(火) 01:58:24
>>190
単純な増減だけでしかアクセスしないんならそれでもいいかもね。
0208デフォルトの名無しさん2009/01/27(火) 02:00:59
int (*a)[1000] = malloc(sizeof(int) * 1000 * 1000);
としたとき

for (i = 0; i < 1000; ++i)
for (j = 0; j < 1000; ++j)
a[i][j] = i * j;

より

for (i = 0; i < 1000; ++i)
for (j = 0; j < 1000; ++j)
a[j][i] = i * j;

のほうが遅いらしいんですがなんでですか?

0209デフォルトの名無しさん2009/01/27(火) 02:01:41
だからね、俺も(バグってるかどうか知らん)
char *strcpy(char *dst, const char *src) {
 char *top;
 while (*dst++ = *src++);
 return top;
}
なんてのが「普通」「読みやすい」なんて全然思わない。けど、
char *strcpy(char *dst, const char *src) {
 char *top = dst;
 while (*src) {
  *dst = *src;
  ++src, ++dst;
 }
 *dst = '\0';
 return top;
}
のような使い方のほうが
char *strcpy(char *dst, const char *src) {
 int i;
 for (i = 0; src[i]; ++i) {
  dst[i] = src[i];
 }
 dst[i] = '\0';
 return dst;
}
よりも「普通」だと言いたいわけよ。
もちろん、この場合に速くなるなんて思わないけど(レジスタ変数が2つまででなければ)。
0210デフォルトの名無しさん2009/01/27(火) 02:01:58
ぶっちゃけ処理速度を要求されてるわけでもない場面で雀の涙ほどの高速化を計るより
統一的で読みやすいコードを書いてほしい
0211デフォルトの名無しさん2009/01/27(火) 02:03:25
>よりも「普通」だと言いたいわけよ。
条件の後出し乙
0212デフォルトの名無しさん2009/01/27(火) 02:03:30
>>208
右側の[ ]の添え字を1ずつ動かしたものは、メモリ上連続しているので、
キャッシュメモリの効果が出やすい。
左側の[ ]を動かすと、メモリのあっちこっちに飛んでアクセスすることになるのだ。
0213デフォルトの名無しさん2009/01/27(火) 02:04:07
配列を順番に舐める程度の使い方しかできないのはわかった。
0214デフォルトの名無しさん2009/01/27(火) 02:04:19
>>209
さすがにそのレベルだとどれでも読みやすさに大差ないだろ

ポインタ演算にしたせいで糞読みづらくなるのはもっとさぁ
0215デフォルトの名無しさん2009/01/27(火) 02:05:23
>>209
i 消滅させてくれたはずなんだよなぁ、コンパイラさまの力で
ソース出せといわれても困るけど
0216デフォルトの名無しさん2009/01/27(火) 02:07:05
>>212
ありがとうございます
説明にくわえ、キャッシュメモリという単語をもとにおおむね分かりました
どうもありがとうございます
0217デフォルトの名無しさん2009/01/27(火) 02:08:09
>>209
どう見ても特殊な状況だけを取り出して「普通」ってw
配列の使い方がそんな単純なものだけなわけねーだろ。
0218デフォルトの名無しさん2009/01/27(火) 02:10:47
>>204
あれ、>>114の言っていることがわからないって言ってた(>>188)んじゃなかったの?
じゃあ「>>114の意味がわからない」なんて書かないでよ。
せめて「>>114は無意味としか思えない」とかにしてよ。
すげー時間無駄にしたよ。

本当に日本語苦手なんだろうけど
「日本語が苦手なんですけど」と書き出されても
「初心者ですけど」と言って質問する人と同じように応対すべきとは思わないじゃん。
0219デフォルトの名無しさん2009/01/27(火) 02:12:26
>じゃあ「>>114の意味がわからない」なんて書かないでよ。
俺はそんなこと一言も言ってない
ID出ない板で勝手に特定の発言を同一人物だと思わないこと
0220デフォルトの名無しさん2009/01/27(火) 02:14:16
>>114が無意味なことしてるとは思わなくて、*(p+n)とp[n]に何か違いがあるのかも、
って思っちゃったんじゃね?
0221デフォルトの名無しさん2009/01/27(火) 02:15:06
そんな無意味なことをやる人間がプログラマ名乗ってるとは信じがたかったとかそういういわゆる一つのアレだろ
0222デフォルトの名無しさん2009/01/27(火) 02:15:46
>>219
>>188は別人なの?
>>188は
>>>114をよく読むほど意味がわからなくなってきたw
と書いてあるけど。
0223デフォルトの名無しさん2009/01/27(火) 02:19:50
>>218
いや、>>114はポインタと配列のコストの違いと言っているのか、
*(p+n)とp[n]のコストの違いと言っているのか、どっちなのかわからなかったのだ。
あと、>>204は俺じゃないよ。
いずれにせよ、ごめんね。
スレも無駄に消費してごめんなさい。
0224デフォルトの名無しさん2009/01/27(火) 02:23:32
これが単なるスタイルの問題ならここまで紛糾しなかっただろう
しかし常に*(p+n)と書くというのはあまりにも迷惑すぎる
0225デフォルトの名無しさん2009/01/27(火) 02:23:49
つまり>>204=>>219が流れも空気も読めずにゴミを混ぜたと

まあ張り付き方見てればわかるけど
0226デフォルトの名無しさん2009/01/27(火) 02:24:23
>>224
さすがにそんな奴居ないだろ。
0227デフォルトの名無しさん2009/01/27(火) 02:27:03
>>226
>>114
0228デフォルトの名無しさん2009/01/27(火) 02:28:43
どこに「常に」と書いてある?
0229デフォルトの名無しさん2009/01/27(火) 02:30:04
「常に」とは書いてないが、ポインタなら常に*(p+n)って書くんじゃね?
0230デフォルトの名無しさん2009/01/27(火) 02:31:30
>>228
常にでないならその無意味な意図とやらすら成立しないだろう
0231デフォルトの名無しさん2009/01/27(火) 02:32:28
>>114の知り合いがそう言ってるのを聞いたの?
0232デフォルトの名無しさん2009/01/27(火) 02:32:56
>>228
ポインタと配列が違うことを示すために変えて書いてます!
ってやつが常にそうしないなら逆に大笑いだ
0233デフォルトの名無しさん2009/01/27(火) 02:33:43
文脈が読めず「常に」と書いてなければ常にじゃないってw
0234デフォルトの名無しさん2009/01/27(火) 02:35:32
ポインタなら別のどこかでインクリメントとかする事があるんで。
0235デフォルトの名無しさん2009/01/27(火) 02:38:45
>>234
前後のつながりのわかる文章を書け
0236デフォルトの名無しさん2009/01/27(火) 02:43:52
別にわからなくてもいいよ。
0237デフォルトの名無しさん2009/01/27(火) 02:44:21
そんなにポインタと配列を混同しやすくて困るってんなら
プレフィクスでもなんでもつけたほうがまだマシってものだ
0238デフォルトの名無しさん2009/01/27(火) 02:55:10
しょうがねえな。
別の話題に持っていってやろう。

配列として宣言された変数には[]を使い、
ポインタとして宣言された変数には*()を使う、という人はいるはず。
もちろん、それは関数の仮引数に[]を使うというような方法で区別する。

という話題はどうだろう。
http://www.kouno.jp/home/c_faq/c6.html#4
に近い話があるが。
0239デフォルトの名無しさん2009/01/27(火) 03:02:26
劣勢だから話題をそらしたいんですね
0240デフォルトの名無しさん2009/01/27(火) 03:03:11
デバッグ作業にかかる時間を短くするために心がけることってどんなこと?
時間かかりすぎる
0241デフォルトの名無しさん2009/01/27(火) 03:08:06
>>238
迷惑すぎる。
*()を使って(2文字増やして)得られるものが何一つない。

ちなみに[]と*()は実は記述上完全な同等ではない。
演算子の優先順位が[]のほうが高いからだ。
ポインタと配列を区別したいなどという理由で*()を押し通していると、
(*())とさらに一つ余計な括弧をつけなければならない場面が出てくる。
0242デフォルトの名無しさん2009/01/27(火) 03:43:42
ふまえると、関数に配列を渡す場合にポインタを渡すか、配列そのものを渡すかで
関数内の処理速度に影響があるということ?
配列を渡すと、渡す際のコストは大きくなるけど、関数内の処理は速くなる?
0243デフォルトの名無しさん2009/01/27(火) 03:47:41
>>242
それは議論の余地無く完全に間違ってる
0244デフォルトの名無しさん2009/01/27(火) 04:01:51
p[3]や*(p+3)は オK
だが
int *p,q p[q]は問題無いが、*(p+q)は迷惑。p[q]じゃないと殴りたくなる
というか、後世に継承してもらうのは無理と思って欲しい。

ちなみにC++では
Class *p( operator[](int)が定義澄み)
p[2] はコンパイルエラー
(*p)[2] この書き方じゃないとNG
p->[2]なんて書けない。

void *p
p=(void*)(p+3);はコンパイル可能だし警告もおそらく出ない。
p=&(p[3]);は警告が出る筈。
(処理系によってはコンパイルが通らない場合がある。)
こういった微妙な相違はあるな。
0245デフォルトの名無しさん2009/01/27(火) 04:09:02
>>241
たとえば、
struct foo { bar_t bar; };
struct foo foo_array[4];
struct foo *foo_ptr_of_array[] = {foo_array, foo_array+1, foo_array+2, foo_array+3};
struct foo *(*ptr_to_foo_ptr_of_array)[] = &foo_ptr_of_array;
struct foo *(*ptr_to_ptr_to_foo) = foo_ptr_of_array;

foo_ptr_of_array[0]->bar = barFoo;
(*ptr_to_foo_ptr_of_array)[0]->bar = barBar;
(*(ptr_to_ptr_to_foo + 0))->bar = barBaz;

さすがに最後はないだろうとは思うけど。

 私は、配列なら添え字演算子を使い、ポインタなら間接参照を使うので、
この場合は、2番目を選ぶと思う。明らかに、最後のは、配列をポインタに成り下げているから、嫌だ。
配列は配列。ポインタはポインタです。混同するのはよくない。
ポインタに間接参照を使う理由は、関数の引数やローカル変数が、間接参照をされている場合、
ポインタなので(+1)、それなりの注意をして読んだり書き直したりできる。
 たとえば、NULLポインタチェック、アロケートとフリーの対応、リテイン(他のポインタが、同じアロケート先をさしていないか)チェックなど。

(+1 配列もポインタに成り下がれるけどe.g. sizeof(array)/sizeof(*array)当然私は、sizeof(array)/sizeof([0])のほうを使うけど)
0246デフォルトの名無しさん2009/01/27(火) 04:10:01
>>244
C++の例なんかむちゃくちゃ言ってるぞwwwwww
0247デフォルトの名無しさん2009/01/27(火) 04:39:52
base pointerとindexの両方を1つのコンテクストの中で動かす
極めてアルゴリズム的ななコードはそれが公共的なものである
場合、修正加筆し損なって、破損した場合の影響度を考えると最早書け
ないと思ったほうがいいかもな。
0248デフォルトの名無しさん2009/01/27(火) 07:23:03
>>245
混同したくないなら名前を変えりゃいいだけだろ。
そんな汚い表記で迷惑かけるのはやめてくれ。
0249デフォルトの名無しさん2009/01/27(火) 07:34:43
読み辛さに起因するバグと相殺しそうだ。
0250デフォルトの名無しさん2009/01/27(火) 10:32:46
>>248
 「混同したくない」ではなく「混同するな」といっているんだが。
たとえそれが糖衣構文とはいってもポインタをあたかも配列のように扱うのはプログラマの意図すべきことではない。
間違ったコードが間違って見えるように、ポインタを配列のように表記せずにはじめから間接参照を使うほうが、
プログラマの意図を反映したコードになる。

 配列は、固定長のデータやデータ長が既知であるとき、動的メモリ確保に制限があるとき(マシンの構造上、動的にメモリを確保できない)、
そのほか小手先技の実現のためなどに使えばよい。だからこそ、ポインタと配列は、別の表記をしたほうがよい。
 配列は、線形的なデータ構造を作るための安価な複合型
 ポインタは、柔軟なデータ構造を作るための安価な複合型


>>汚い表記
 どこが汚いのかまったく理解できない。
0251デフォルトの名無しさん2009/01/27(火) 11:08:54
自分にしか読めないようなのは他人から見ると汚いんだよ
0252デフォルトの名無しさん2009/01/27(火) 11:12:04
>>250
言いたいことはまぁ判ったから、もう少し判り易い例を提示してくれ。
>245だと何が言いたいのか全く判らん。
■ このスレッドは過去ログ倉庫に格納されています