displayX
@displayX (あーる)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

C言語の引数に配列を渡したいが上手くいかない

解決したいこと

C言語を始めたのですが、配列に対する処理が全然ないので困っています。

で、JavaScriptのlengthみたいなのが欲しいなと思って検索したら・・・、
sizeof(arr) / sizeof(arr[0])で配列の要素数が得られることが分かりました。

しかし、配列を関数に渡して、内部で上の処理を書くと上手くいきません。
sizeof(arr) の値が小さくなります。

発生している問題・エラー

//↓これは問題ありません
int main() {
  int arr[] = {1, 2, 3, 4, 5};
  int arrsize = sizeof(arr); // ← 20
  printf("%d", arrsize);
  return 0;
}
// arrsizeは20です。

// ↓ しかし配列を関数に渡すとarrsizeが小さくなってしまいます。
int length(int *arr) {
  int arrsize = sizeof(arr); // ← 4
  printf("%d", arrsize);
}
// 引数を経由するとarrsizeが4になってしまいます。

↓ 実際はこんな感じです。

int length(int *arr) {
  return sizeof(arr) / sizeof(arr[0]);
}
int main() {
  int arr[] = {1, 2, 3, 4, 5};
  int len1 = sizeof(arr) / sizeof(arr[0]);
  int len2 = length(arr); // ★
  printf("%d", len1); //=> 5
  printf("%d", len2); //=> 1
  return 0;
}

★のように、関数を通すと値がおかしくなるのです。
sizeof(arr)の値が変わるので。

自分で試したこと

仕方がないので、関数マクロにしました。
#define length(arr) ((sizeof(arr)) / (sizeof(arr[0])))
これで期待通りに動きましたが、釈然としません。

なぜサイズが変わりますか?
そして変えずにすむ方法があれば教えてください。

初めての質問で、おかしなことを書いていたら済みません。

0

2Answer

しかし、配列を関数に渡して、内部で上の処理を書くと上手くいきません。

仕様です。

関数の引数に配列のポインタを渡しているだけなので
渡されたポインタからsizeofで配列の要素数は取得できません。

参考URL
https://www.jpcert.or.jp/sc-rules/c-arr01-c.html

0Like

Comments

  1. @displayX

    Questioner

    なるほど。ポインタから要素数は得られないと・・・。
    C言語は難しいですね。
    ありがとうございます。
  2. C言語はどうしてもポインタが付きまとうので
    焦らず勉強していただければ幸いです。
  3. @displayX

    Questioner

    分かりました。
    ポインタの本があれば買ってみます。
    ありがとうございましたm(__)m
int length(int *arr) {
  return sizeof(arr) / sizeof(arr[0]);
}

ここでの sizeof(arr)int * 型(int のポインタ型)のバイトサイズです。大抵の環境でポインタ型は4バイトか8バイトです。 sizeof(arr[0]) はポインタが指す型(つまり int)のバイトサイズです。 int は環境によりますが一般的に4バイトです。よって配列の大きさにかかわらず length(arr) は1か2を返します。

int main() {
  int arr[] = {1, 2, 3, 4, 5};
  int len1 = sizeof(arr) / sizeof(arr[0]);
  int len2 = length(arr); 
...

ここで sizeof(arr)int[5] 型(5要素の int 配列型)の全体のバイトサイズ、つまり要素のバイトサイズかける要素数です。それを要素のバイトサイズ sizeof(arr[0]) で割ることで要素数が得られています。

ここで length(arr) が関数の場合は、最初で述べたように1か2を返します。マクロの場合はその場で ((sizeof(arr)) / (sizeof(arr[0]))) に展開されるので、直前の段落で述べたように要素数が得られます。


C 言語では配列を指すポインタから配列の長さを知る方法はありません。配列を指すポインタを受け取る関数は配列の長さも引数で受け取るようにするのが普通です。

0Like

Comments

  1. @displayX

    Questioner

    なるほど。ポインタから配列長を知る術はない・・・。
    sizeof()を毎回書いて引数で渡すなら、今回の場合は意味がないですね・・・。
    マクロでします。
    C言語はちょっと不便なところがあるんですね。
    ありがとうございます。

Your answer might help someone💌