当たり前ですが、配列dとd2は別物ですので、アドレスも異なります。, 関数の先で配列の中身を変えられたくない場合は、後半の解決方法のほうがシンプルでわかりやすいですが、 「配列渡し」は「ポインタ渡し」の一種でポインタ変数を引数として使うことは同じですが、呼び出し元の実引数が変数ではなくて配列であるという違いがあります。では定義と例を見てみましょう。 繰り返しますが「配列渡し」は「ポインタ渡し」の一種ですのでメリット・デメリットも「ポインタ渡し」とほぼ同じです。つまり、 というメリットがあります。

アドレスを渡している 前項では、配列型の引数の持つ奇妙な性質を説明しました。 あのような現象は、配列が値渡しされていれば、絶対にあり得ないことです。 つまり、逆に言えば、配列自体は値渡しされていないのです。 値渡しを行う目的は「呼び出し先の関数で値を変えられないようにする」ことがあります。 このことから配列を渡して処理できていることが分かります。 この方法一見特に問題ないようにも見えますがあまり使われません。 いちいち配列の要素数を書くのも面倒ですよね。 通常の書き方では、その配列の 先頭ポインタを渡して処理します。

funcYのようにするということですね。 すると ☆1 時点におけるメモリ空間の状態は図1の様になります。, まだ HOGE 関数の中に入っていませんので、「main 関数の配列 a」だけが定義され、各配列要素にはそれぞれ 100、101、102 が入っています。, HOGE 関数の引数としてポインタ変数「char *pa」が指定されており、 更に main 関数から HOGE 関数を呼び出す時に a の先頭アドレスが渡されていますので、「ポインタ渡し」の時と同様に, HOGE 関数に入る直前に char 型のポインタ変数 pa が作られ、「main 関数の配列 a」の先頭アドレスが「 HOGE 関数のポインタ変数 pa 」に代入されます。, ☆3 の直前の 3 行を使って *(pa+i)記法 と pa[i] 記法を使って値が代入されていますが、, pa[0] は「main 関数の a[0] 」を参照している(矢印で指し示している)ので「main 関数の a[0] 」に 12 が入ります。, *(pa+1) は「main 関数の a[1] 」を参照している(矢印で指し示している)ので「main 関数の a[1] 」に 34 が入ります。, pa[2] は「main 関数の a[2] 」を参照している(矢印で指し示している)ので「main 関数の a[2] 」に 56 が入ります。, HOGE 関数を抜けた瞬間に「HOGE 関数のポインタ変数 pa 」は消えて無くなりますので、よって ☆4 時点におけるメモリ空間の状態は図 4 の様になります。, 以上の説明から、「配列渡し」を使うと、関数の中から元の配列の値も変えることが出来ることが理解できたと思います。. 久しぶりにC言語のお話になりますが、関数の引数に配列を指定したい場合は、配列の先頭アドレスを渡すのが一般的です。 つまり、参照渡しを行うわけです。 配列を参照渡しする場合 例を出すと、 #include void funcB(char *b){ printf("### funcB ###\n"); … 関数の引数に配列を指定したい場合は、配列の先頭アドレスを渡すのが一般的です。 配列の先頭ポインタを渡しているので参照渡しになっていますが、

ブログを報告する, 最近Unityを使っていますが、UnityでDeep Learningを使ってみま…, Javascript(Node.js)でROSのTopicをpublish, subscribeしてみま…, rosbridgeとroslibjsを使ってJavascriptでROSのTopicを操作してみる, Visual Studio Code でJavascriptのフォーマッターを設定する. Copyright © 2019 モノづくりC言語塾 All Rights Reserved. よって、値を変更したい場合はmemcpy等でコピーを作成してから行う必要があります。 配列aと配列b、配列cのアドレスが変わっていないので、参照渡しになっていますね。 構造体zとyのアドレスが異なっていますし、yの配列に値を書き込んでもzには反映されません。, これについては値渡しではないですが、こちらを使用することのほうが多いと思います。 何かの諸事情で本当に「値渡し」をしたい場合は構造体とするという方法があります。, naonaorangeさんは、はてなブログを使っています。あなたもはてなブログをはじめてみませんか?, Powered by Hatena Blog つまり、参照渡しを行うわけです。, 出力結果は下になります。 特に関数の引数でポインタを使って参照渡しを行うと、複数の変数を1つの関数で処理変更できる。 ひとつのポインタ変数で、配列のすべての要素の値を取得したり、変更することができる。 したがって、配列の要素を一つずつ扱う手間が省ける。 まずは以下のソース1を実行して下さい。, ソース 1 の main 関数から始まって ☆1 まで進んだとします。 「ポインタ」と「配列」は異なる機能ではありますが、使い方が似ている部分があります。この扱いを知ることで配列をポインタから自由に操ることができるようになります。ポインタを使った配列の扱い方を学びましょう。 ただしc言語よりも新しいプログラミング言語では参照渡しがデフォルト動作となっている事が多いので、後で必ず自学自習しておいて下さい。 さて (1) の値渡しはみなさんが今まで学んできた普通の引数の渡し方で、次のように定義します。 しかし、C言語の中ではポインタと配列の扱い方が、酷似している部分があります。何が同じで何が違うのかを学んでいきます。, ポインタの全貌を学びたい方は『C言語 ポインタを使いこなせ【身に付けるための9の極意】』の記事から順に読むことをお勧めします。, ポインタと配列はね、違うようで似てるんだよ。配列王子を名乗るのであれば、この関係性は知っておくべきなんだよ。, この時に注意しなければならないのは、引数へ渡された配列はポインタとなって受け渡しされるということです。, main関数側のmoji配列を、subfunc関数の引数として渡しています。subfunc関数側の引数定義は、ポインタ変数として定義されているのがわかるでしょう。, このように、配列を受け取りたい関数の引数は、ポインタ変数として受けなければなりません。, この際に注意することは、subfunc関数側のポインタ変数pmojiを利用して参照先の値を書き換えると、moji配列の中身のデータが変わってしまうことです。, つまり、上記プログラムではprintf関数によるnum[0]の表示は「C」という文字が表示されることになります。, 先ほどの例にて「配列」を「ポインタ変数」に受け渡しました。簡易的に書くと次になります。, ポインタ変数へ番地を設定するときは、変数名にアドレス演算子「&」を付けて番地を取り出していましたよね。しかし、このプログラムには「&」がそもそも出てきていません。, 「変数」と「配列変数」では番地の取り出し方が変わるんです。これはすごく大事なルールなんです。このことが「配列」と「ポインタ」の関係性を近くすることになるんです。, ほほほーい。「ポインタ」と「配列」が親戚と聞いて、俄然やる気が湧いてきましたよー。ポインタを使って配列を使いこなす。この配列王子が必ずマスターしてみせますっ!ででで、どうやって使うんですか?, ポインタに配列のように[]を付ければ使えるんだよ。配列と一緒でしょ。これが配列とポインタの類似性だよ。, 配列を使ったプログラムでは、次のように[]を使って各配列要素にアクセスしていました。, 皆さんは、[]とは配列に使用するものではないのかと思っているかもしれませんが、こんなことができるのです。これには理由があります。, 配列とポインタ変数に対して添字演算子を使うことは最終的に同一の解釈に落ち着きます。, 「配列名は番地である」ということが、ここで活きてきます。これこそが配列にもポインタ変数にも、添字演算子が使用できる理由です。, はい、はーい。配列を関数で受け取るときにはポインタ変数で定義する必要があるんですねー。もし、引数を配列として定義したらビルドエラーが出るんですか?, お、これはいい質問だね。実際に書いてみるとわかるけど、ビルドエラーは出ないんだよ。でもね、配列のように書くことに対して注意が必要だよ。, このポインタの定義方法ですが、いくつかの記述方法が存在します。このバリエーションは配列とポインタの関係性が近いことにより認められている特殊な記法です。, この時に定義するfunc関数の定義の引数は、次のいずれかの書き方が認められています。, しかし、この②③は配列ではありません。②③は見た目は配列のようですが、正体は①のポインタ変数と全く同じものです。, 関数に対して配列を丸ごと受け渡すことはできません。すべてポインタに変えられてしまいます。, ですが、「配列を受け取ります」という意味を強調できるよう、関数の引数に限りこれらの特殊な記法が認められています。, 一般的に配列を受け取るときでも①の記法を好む方が多いですが、配列を強調するため②の記法を使用する方もいます。③の書き方は使われません。, 開発者は他の人が作成したプログラムを読むことも日常ですので、この特殊な記法のルールは知っておく必要があります。, このルールは関数の引数だけに適用されるルールです。すごく特殊なルールということになります。, ほーーい。配列とポインタは仲良しなんですね。では、僕もポインタと仲良しになろうと思います。ポインタと仲良くなれる方法を教えてください!, じゃあ、ポインタから配列にアクセスするための方法を教えるよ。いくつかの方法があるから、好きな方法を選んで仲良くなってね。, 配列を参照しているポインタを扱う際に、メモリへのアクセス方法にはいくつかの書き方が存在します。, 次のプログラムにおいて、subfunc関数は配列へのポインタを引数で管理しています。このポインタを使った配列へのアクセス方法として、パターン①~③が存在します。, パターン①ポインタを配列的に参照するパターン。あたかも配列のように参照できるため、直感的で使いやすい。, パターン②ポインタの番地にインデックスを加え、ポインタの参照位置をずらすパターン。パターン①と同様の意味であるが、①の方がわかりやすいため、あまり使われない。, パターン③ポインタの参照位置を直接ずらしながら順番に参照していくパターン。配列先頭の番地がわからなくなるため、使う時には注意が必要。, 補足になりますが、配列を関数の引数に渡す際には配列要素数も一緒に渡すのがセオリーです。, これは配列を渡された側の関数にとって配列はポインタ変数としてしか認識できず、配列要素数を知ることができないためです。, 関数には「配列へのポインタ」と「配列要素数」を一緒に渡すというのは、よくある実践的なパターンですね。覚えておくとよいですよ。, くくく、悔しいですっ!配列はなぜ関数にそのまま渡すことができないのですか?配列王子としての尊厳に関わる問題ですよ、これは。配列協議委員会に物申しますよ!, そんな委員会あるの?初めて知ったよ。配列を関数の引数でマルっと受け渡す方法はあるにはあるんだよ。だから物申さないでね。, このようにfunc関数で構造体内の配列を書き換えても呼び出し元の配列には影響がありません。これは構造体のデータは値渡しが可能だからです。, もしも、プログラムが上手く動かなくて困ったときは、答えを見るのではなく「デバッガ」の使い方を学びましょう。, 次のプログラムに上記関数を追加し、ケース①~③を切り替えて出力期待結果が表示されることを確認せよ。, 前章のNULLチェックも入れてますね。このように関数の引数でNULLチェックはよく使われます。, 次のプログラムに上記関数を定義し呼び出せ。出力期待結果が表示されることを入力ケース①と②の場合で確認せよ。, データを昇順や降順で並べ替えることを「ソート」と呼びます。このプログラムは「バブルソート」と呼ばれる方法を利用しています。, 年間200人以上のプログラミング初心者・未経験者を直接指導で教育している現役エンジニアです。, 本サイトでは開発経験20年のノウハウ・学習ポイント・カリキュラムを全力でわかりやすく解説します!, Visual Studioのデバッガにはメモリを参照することができる「メモリ画面」機能が搭載されています。C言語ではポインタを使う機会が多く、メモリのデータをいかに把握するかが問題解決の糸口になります。, 構造体のポインタ変数を利用して構造体メンバへアクセスするためにはアロー演算子と呼ばれる特殊な演算子が必要となります。ドット演算子と使い分け方を覚えましょう。, C言語において最も難関となるポインタを解説します。ポインタは多くのルールの上で成立している機能であり、そのルールを知ることだけでも苦労します。そのルールがなぜあるのかまで踏み込むことで理解を深めます。, 独学でプログラミングを始めようとしている方へのC言語入門学習カリキュラムです。C言語を学ぶために必要な知識を順序立てて解説します。順に進められる構成となっており、課題が用意されているため理解を確認しながら進めることができます。. funcCのような書き方をすると値渡しになるのですが、配列の場合はどちらも参照渡しです。, 配列を持つ構造体array_tを定義し、その構造体を渡すことによって値渡しができるようになります。 その証拠に、funcB, funcCで配列の中身の値を変更すると、配列aの値も変わっています。, 配列ではなく、通常の変数(char, intなど)の場合はfuncBのような書き方をすると参照渡し、

「配列渡し」は「ポインタ渡し」の一種でポインタ変数を引数として使うことは同じですが、呼び出し元の実引数が変数ではなくて配列であるという違いがあります。では定義と例を見てみましょう。, 繰り返しますが「配列渡し」は「ポインタ渡し」の一種ですのでメリット・デメリットも「ポインタ渡し」とほぼ同じです。つまり、, 上で説明したポインタ変数を引数とする配列渡しの方法以外にも次のような記法があります。, 呼び出し元の配列が 1 次元配列ならどの記法を使っても同じ結果になりますので(※)基本的に好みの記法を使って結構です。, ※ 呼び出し元の配列が 2 次元配列などの多次元配列になると結果が変わってくるので注意が必要です。, では「配列渡し」の動作についてメモリ空間を使って説明して行きます。

constがついているので変更することはできません。 よって、値渡しを行わなくてもconstをつけることによって実現できます。, funcDの仮引数がconst char d[3]となっています。 配列を参照渡しする場合、仮引数は配列の要素数まで指定する必要があります。 この関数で使用できるのは「要素数が5のint型配列」に限定され、要素数が異なる配列を実引数に指定するとエラーになります。 |