C言語について質問です。main関数以外の関数であるtimesを、main関数内から呼び出すとします。times関数は、int型の配列を引数として受け取り、配列の各要素を2倍するものとします。ポインタを引数として渡すことや、配列を引数として渡す方法がよくわからなかった私は、これを実装する際、chatgptに聞いてみたのですが、呼び出し時はこうなり、times(samp);関数の定義はこうなるそうです。void times(int samp[]);呼び出し時に引数として、配列名だけを渡していること・配列の定義時に配列の長さを定義していないこと・int *となっていないことが気持ち悪くて仕方なかったので理由を聞いてみたところ、「配列の各要素は、メモリにおいて連続していて、intであるなら例えば\u0026amp;samp[0]が0x1000なら、\u0026amp;samp[1]は0x1004となります。そして配列名自体は、\u0026amp;samp[0]と同義であり、times(samp);はtimes(\u0026amp;samp[0])と同じです。そして、times関数内でtimes[1]=times[1]*2;を実行することは、実は\u0026amp;times[0]の4バイト次のメモリの中身を二倍にすることなのです。」と言われ、「じゃあint x;と定義して、\u0026amp;xが0x1000なら、x[1]とやったら0x1004を参照できるのか?」と聞いたらまたゴニャゴニャ言い始めました。本当に言っていることが正しいのかも分かりませんでしたし、最後の返答で余計わからなくなりましたし、なぜ関数の定義時にint samp[]とやったのかも解決しませんでした。誰か教えてほしいです。お願いします!

1件の回答

回答を書く

1214624

2026-01-13 06:20

+ フォロー

結局何がわかれば満足かが今ひとつ...その辺全部すっきりさせなきゃいけないのかな。ちょっと大変。



まずひとつ根本的な話。

C言語ってのは、すご~く原始的な言語で、1970年代のコンピュータの能力を骨の髄まで絞り出すために「コンピュータの中身」をさらけ出していて、いろいろなことをプログラマが面倒みてやらなきゃいけません。基本的に人間の都合ではなく、コンピュータの都合が原則で、優先。これを忘れないで下さい。「なんでそうなってるの?」と思ったら、それは「コンピュータにとってそれが都合がいい(よかった)から」が答えです。



で。そんなC言語は、「配列」というものをその構成要素がメモリ上に密に並んだもの、と定義しました。配列を変数として定義すると、その要素数のメモリエリアを変数の領域として確保したコードを出力します。ここで注意が必要なのは、C言語がやってくれるのは「領域を確保する」だけ。要素数の管理は全てプログラマの責任です。なんでそうなっているのか...もちろん「コンピュータで要素数の管理をすると言語の処理が面倒になるから」。



なので、「配列」としてC言語が管理するのは最初の要素の位置(アドレス)すなわちポインタだけ。2番目以降の要素は、(要素が密に並んでいるというのが配列の定義ですから)最初の要素の位置に要素のサイズを足していけば在処がわかるのでアクセスできる、ということになります。

で、配列で管理するのがポインタだけなら、つまりそれはポインタと一緒だよね、ということで、

・配列として宣言した変数名は最初の要素へのポインタとして扱われる

・関数の引数の型として配列を指定することと、ポインタを指定することは等価

ということにしました。そう決めたのだから文句を言わないで従って下さい。

これらにより

\u0026gt; 引数として、配列名だけを渡していること

\u0026gt; int *となっていないこと

の理由付けがされます。配列名は即ちポインタ型で、int*とint[]型は等価なのですから。



さて。

配列を受け渡しするときに配列の長さを指定していないこと

は、一般的にはよろしくないことですが、場合によってはあり、です。

それでいい場合というのは、

・プログラム上で配列のサイズがハードコーディングされている。呼び出し側と関数側とがそれぞれ配列のサイズを「知っている」=ソースコード上にかかれている

・配列の内容自身に、たとえば「負のデータが出てきたら配列終わり」などの規則が設けられていて結果として配列のサイズがわかる(呼び出し側と関数側どちらもがその規則を守っている)

といったところでしょう。

これは、もとの課題設定がどのようなものかまで遡って考えないと、この質問からだけでは正否は判断できません。



また、

\u0026gt; int x;と定義して、\u0026amp;xが0x1000なら、x[1]とやったら0x1004を参照できるのか?

C言語の範囲では、少なくとも参照しようとはします。それが許される動作となるかどうかはまた別の議論で、C言語の範囲外で決まること。そして参照した結果起こることは「プログラマの責任」とされています。





ところで、いくつか本題とは関係ないコメント。

・C言語においては、「宣言」と「定義」という言葉は意味が異なります。混同しないようにしましょう。

\u0026gt; 関数の定義はこうなるそうです。

\u0026gt; void times(int samp[]);

これは「こういう関数があるよ」という「宣言」であって、「その関数はこう動くよ」という「定義」ではありません。

また、

\u0026gt; 配列の定義時に配列の長さを定義していない

例えば

int array[];

として配列を「定義」しようとするとエラーになります。配列の定義時には配列のサイズは指定されているはずです。

なお、関数の(仮)引数は、これも「こういう変数があるよ」という「宣言」であって、定義ではありません。「これは配列だからね」という情報(=宣言)だけあれば、先に述べたようにCではサイズは管理しないので無意味です(一応数字を書くことは許されていますが無視されます)。



もう一つ、int型のサイズは必ずしも4byteではありません。現在メジャーな処理系では4byteかも知れませんが、それは今どきのCPUがそれが都合が良い、という理由によるものです。C言語としてはint型は16bit以上の値の範囲を表せればよい、ということになっています。sizeof(int)は4と思い込みませんように。

うったえる有益だ(0シェアするブックマークする

関連質問

Copyright © 2026 AQ188.com All Rights Reserved.

博識 著作権所有