「2次元配列(数値型)の一般的な方法」につき一部修正しました。 関数ポインタはポインタの中でも少し変わった役割を持つポインタです。このポインタは一体何の役に立つのか?定義方法や実践的な使い方を学びましょう。 C言語では、配列そのものを引数として渡せないので、ポインタを引数として渡します。 具体的には、次のソースコード中、main関数4行目にあるnum_arr(num, numlen);のところとなります。 ソースコード

☆1 時点におけるメモリ空間の状態は図1の様になります。, まだ HOGE 関数の中に入っていませんので、変数は「main 関数の a」のひとつしか定義されていません。 C言語 malloc/calloc/reallocの使い方【ヒープメモリの確保方法】, Q:ダブルポインタの「**」があるということは、ひょっとしてトリプルポインタなんてあるの?. 引数名の前に間接演算子を書くと、ポインタを受け取ることを意味します。, 関数の呼び出し側では、関数の処理結果を受け取るための変数をまず宣言します。 変数maximumと仮引数maxも同様です。, 関数の戻り値は成功すれば0を返し、配列の要素数が0の場合は-1を返します。 ソース1との違い(3箇所)はソース内のコメントに示しています。, 実行すると最終的に 34 と表示されます。 C言語における文字列は、基本的にはchar型の配列になるので、これも文字列(配列)そのものを渡すことはできず、文字列の先頭ポインタを引数として渡すことになります。 具体的には、次のソースコード中、main関数4行目にあるnum_arr(num, numlen);のところとなります。, ここで注意を要するのは、引数として渡すのは、配列の先頭ポインタを示すnumだけではなく、配列の要素数numlenも渡していることです。

コピーなので、アドレス値を書き換えても呼び出し元には影響しませんが、アドレスが指し示す値は関数内からも呼び出し元からも同じ場所を参照しています。 この例では、menseki関数に実引数として底辺5と高さ10を渡しています。この5と10の値は、それぞれ、x、yに代入され、menseki関数の処理を実行します。ここで大切なのは、x、yに代入された値を、仮に変更したとしても変数teihenやtakasaの値は変わらないと言う事です。関数内では仮引数とローカル変数の値しか変更できないと言うのが普通です。, 上の例では、menseki関数に実引数として底辺5と高さ10とansのアドレスを渡しています。面積を求めたら、ansのアドレスを使ってansに値を入れています。関数内では仮引数とローカル変数の値しか変更できないと言うのが、普通なんですが、値渡しの時と違い、ポインタ機能を使って関数外の変数ansの値を変更する事ができるのです。, 上の例では、構造体を使い、それぞれ値渡しとポインタ渡しを行っています。show1関数の値渡しでは、構造体のメンバageとbloodをshow1関数の仮引数pに代入し、関数内の処理が行われます。この場合、int型のageとchar型3つで7バイト分の値渡しが行われる事になります。そして、show2関数のアドレス渡しでは、tanaka構造体のポインタをshow2関数の仮引数pに代入し、関数内の処理が行われます。この場合、ポインタ型なので、4バイト分のアドレス渡しが行われた事になります。構造体のメンバがどれだけ増えてもアドレス渡しを行えば、一律4バイトです。このように、構造体を使う場合は、値渡しよりもアドレス渡しの方が処理が軽くなるのです。構造体のポインタ渡しは、構造体のメンバが多くなればなる程、絶大な威力を発揮します。関数へ構造体を渡す場合は、極力、アドレス渡しを使うようにしましょう。, 値渡しのみの引数で構成された関数は、その関数内の変数しか変更しませんので(グローバル変数は除く)、他の関数に影響を及ぼす事がなく、安心、安全で管理しやすい関数となります。, 一方、アドレス渡しを使うと、渡されたアドレスを使って関数外の変数も変更可能です。便利ではありますが、他の関数にも影響を与えるので、注意しながら使わなければなりません。. C言語の理解できない機能としてランキング上位に位置するであろう、「ポインタのポインタ」に関して解説していきます。, 「ポインタのポインタ」ってC言語の中でちょくちょく出てくるんです。ですので、やっぱり理解しておきたい機能の1つなんですね。, ポインタはわかったけど、「ポインタのポインタ」ってどういうこと?「ポインタのポインタ」って言葉としておかしくない?意味わかんないんだけど‼, と多くの人が戸惑います。しかし、ポインタを正しく理解していれば、実は簡単なんです。, 理解するために必要なのは「ポインタのポインタ」を理解するためのイメージと、定義の意味を正しく知ることです。, ポインタの全貌を学びたい方は『C言語 ポインタを使いこなせ【身に付けるための9の極意】』の記事から順に読むことをお勧めします。, はい、はい、はーーーい。僕の出番がやってまいりましたっ!なるほど「ポインタのポインタ」、2つ繰り返してますね。つまり、反復王子の僕の出番ってことですねっ!, うん、違うよ。「ポインタ」って言葉が2つ繋がってるだけで反復処理とはあんまり関係ないね。でも、繰り返しているという状況としては遠くないね。, じゃあ、「ポインタのポインタ」を理解するために、まずは「ポインタ」のおさらいをしようね。, 「ポインタ」を理解するにはイメージが大切です。「ポインタのポインタ」もイメージとして理解することです。, 「変数」に対して遠距離アクセスしたい場合は、「ポインタ変数」を使用しました。関係性は次のようになります。, 「変数」を的、「ポインタ変数」を弓矢とし、遠距離アクセスを可能にしました。これが変数とポインタ変数の関係性ですね。, 「ポインタのポインタ」を理解するには、ポインタのイメージが基本となります。これが理解できていれば「ポインタのポインタ」もイメージできます。, 「ポインタ変数」という変数も、変数の一種なわけです。であれば、「ポインタ変数に対して遠距離アクセスしたい!」というニーズがあってもよさそうです。, ここで皆さんに質問です!「ポインタ変数を的」として見た場合、弓矢はいったい何になるのでしょうか?, そうです!ここで登場するのが「ポインタのポインタ(ダブルポインタ変数)」なんです。, このように「ポインタ変数を的」としたときに、弓矢に相当するのが「ダブルポインタ変数」になります。, 「ポインタのポインタ」とは、「ポインタ変数を参照しているポインタ変数」ということです。, 「的」と「弓矢」の関係性とは、着目している2つの変数によって変化することがわかります。, ほいほ、ほーーい。「ポインタのポインタ」が「ポインタ変数」を見て、「ポインタ変数」が「変数」を見る。誰かが誰かを見守ってるんですね…, じゃあ、次は「ポインタのポインタ」の変数定義の解釈を理解しようね。複雑に見えるけど、ちゃんと理解すれば理にかなってるんだよ。, 「ポインタのポインタ」変数の定義はルールは簡単ですが、正しい解釈を知らない方って結構多いと思います。, 使い方を知っている方でさえ「じゃあ、どうしてこんな風に書くと思う?」 って聞いても、なかなか答えられません。, 「ポインタのポインタ」は通称「ダブルポインタ」とも呼ばれます。なぜそう呼ばれるかは定義をみると一目瞭然ですね。, 変数名の頭に「pp」と付けているのは「ダブルポインタ」を示しているという意味です。名前の付け方は自由ですので、もちろん付けなくても大丈夫です。, ポインタ変数とダブルポインタ変数の定義方法の違いは「*」がもう一つ付くかどうかです。作り方は覚えてしまえば簡単ですね。, ポインタで必ず出てくる「*」、これが2つ連なることで多くの人が戸惑います。考えることを放棄して、とりあえず「*」を付ければよいと思っている方もいます。, しかし、「**」には意味とルールが存在します。「**」の意味をしっかりと理解しましょう。, この変数定義の解釈ですが、各部品を分離して差を比べてみましょう。下図左のように捉えるのは間違いであり、右側の見方が正しいです。, ダブルポインタという名称から「**」をくっつけるイメージを抱きますが、分離して解釈するのが正しいです。, 部品②部品①に対してのデータ型を示す。データ型をポインタにしたい場合は「*」を指定することにより、「ポインタ型」であることを示すことができる。, 「ダブルポインタ変数」において、部品③の参照先のデータ型が「ポインタ型」として定義されるということなんです。, つまり、「ポインタ変数」と「ダブルポインタ変数」の違いは、参照先メモリのデータ型が異なることしか違いがありません。, で、で、で、で、これを使う場面が知りたいんでーす。それ知らないといざって時に使えないじゃないですかっ!, そうだね、いいこと言うね。実践的に使用するケースを知らなければ活用できないよね。まずは、こんな時に利用するよっていうのを紹介しようね。, ダブルポインタ変数は、実際のプログラムの中ではそれほど多用されるわけではありません。, しかし、「これをしたい時は、ダブルポインタ変数がいるよね!」といった特定のシーンにおいてやはり出てくるので、しっかりと知識としては身に付けておく必要があります。, 仕事を依頼する側が保有している変数の設定を、別の関数へ依頼する場合に「ポインタ変数」が引数で登場します。, 「ポインタ変数」の番地の設定を、別の関数へ依頼する場合に「ダブルポインタ変数」が引数として登場します。, ここまで解説したシーンとは「こんな場面で使われるよ」というものであり、実践的に使われるシーンをまだ解説してません。, このシーンはあるにはあるのですが、現時点ではまだ紹介していない機能でよく使うんです。知りたい方は次の記事を参照してください。, C言語入門カリキュラムを進めている方は、気にせず続けてください。もう少し先の記事で実戦的に使用する場面を具体的に紹介します。, はい、はい、はい。「ポインタ」には「ダブルポインタ」がありますね。ま、ま、まさか、ポインタに「トリプルポインタ」なんてものはないですよね?, 僕は反復王子と配列王子の2冠を持っているんですよ、3つ目の冠を狙ってるんです。絶対にポインタには負けません!3冠王に僕はなるっ!, あるよ。使うかどうかは置いておいて、トリプルポインタは存在するんだよ!残念ながら、君は現時点でポインタに負けてるんだよ!, C言語の文法的にはトリプルポインタの作成も、さらに先のクアドラプルポインタすら作成可能です。, 年間200人以上のプログラミング初心者・未経験者を直接指導で教育している現役エンジニアです。, 本サイトでは開発経験20年のノウハウ・学習ポイント・カリキュラムを全力でわかりやすく解説します!, ハンドルはC言語で疑似的なオブジェクト指向プログラミングをするための仕組みです。ファイルハンドルからハンドルの概念と扱い方を学びます。, 関数ポインタはポインタの中でも少し変わった役割を持つポインタです。このポインタは一体何の役に立つのか?定義方法や実践的な使い方を学びましょう。, C言語において最も難関となるポインタを解説します。ポインタは多くのルールの上で成立している機能であり、そのルールを知ることだけでも苦労します。そのルールがなぜあるのかまで踏み込むことで理解を深めます。, 独学でプログラミングを始めようとしている方へのC言語入門学習カリキュラムです。C言語を学ぶために必要な知識を順序立てて解説します。順に進められる構成となっており、課題が用意されているため理解を確認しながら進めることができます。. この様に「main 関数の a 」の値は元の 12 のままです。, 以上の説明から、関数の引数の渡し方として「値渡し」を使うと、関数の中から元の変数の値を変えることが出来ないことが理解できたと思います。, 次は「ポインタ渡し」のメリットである「どうして関数の中で呼び出し元の変数の値を変更出来るのか」についてもメモリ空間を使って説明して行きます。, まずは以下のソース2を実行して下さい。

What is going on with this article?

ここからはポインタ変数の活用方法についていくつか例を挙げたいと思います。 (adsbygoogle = window.adsbygoogle || []).push({}); © 超初心者向けプログラミング入門, 超初心者向けプログラミング入門, ファイル名変更、移動、削除、存在確認, ディレクトリ作成、削除、存在確認. c言語を学習する上では、どうしても手が止まってしまう部分です。 しかし、ポインタを使ってやっていることはアドレスかアドレス先の値を操作するかどちらかに限られます。 ... 4 関数でのポインタの使い方. Copyright © 2019 モノづくりC言語塾 All Rights Reserved. c言語の理解できない機能ランキングで上位に位置するポインタのポインタを解説します。ポインタを理解したのに「ポインタのポインタ」が登場し、悩んでいる方は是非この記事を読んで学んでみてくださ … C言語では、配列そのものを引数として渡せないので、ポインタを引数として渡します。 ダブルポインタが示すアドレス10は、シングルポインタの先頭アドレスとなります。

修正前は、void num_arr2(int num[][5], int numline, int numlen)という形で、列数も引数として渡していましたが、numlen = 5であることは自明であるため列数は引数として渡さない形に修正しました。.

そして、このシングルポインタが示すアドレス100は、目的となるデータが格納されているアドレスとなります。 これは、「C言語の引数に多次元配列を渡す」という記事を元とさせていただきました。, C99に準拠している環境であれば、これを使えば便利だと思います(私の環境では、gccでは動きますが、Visual Studioでは動きませんでした)。 ポインタの項では、ポインタの概要を説明しましたが、この説明だけではポインタの有効な使い方はあまりイメージできないでしょう。, 実際のところ、ポインタは「高速化」「効率化」のために使われることが多く、これらを無視すればポインタを使わなくてもそれなりにプログラムは作れます。 c More than 3 years have passed since last update. C言語の関数で、配列を引数として渡す方法については、数多のサイトで紹介されています。 これをするには、配列の構造を、次のイメージ図のように変えてあげる必要があります。 引数の書き換えについて. [c言語]関数の引数に配列を指定する3つの書き方(サンプルコードあり) 公開日 : 2018年8月23日 / 更新日 : 2018年11月23日 2次元配列num[][]のデータは、次のような形で、格納されています。, ● イメージ // get_ftext関数を用いて、strの用意したメモリにファイルの文字列データを格納, // get_ftext関数(二次元配列を使ってファイル内の文字列データを行ごとに格納する関数), // 改行があるたびに行をカウント(なお、fgetsの場合'\n'を改行として認識する), // get_ftext_len関数(ポインタ[len]にファイルの行ごとのバイト長を格納する), Microsoft Ignite 2020の振り返りも「Azure Rock Star Community Day」, you can read useful information later efficiently. そしてその a には 12 が入っています。, HOGE 関数に入る直前に short 型の a がもうひとつ別に作られ、「main 関数の a 」の値が新しく作られた「 HOGE 関数の a 」に代入コピーされます。, これが「値渡し」の動作で、その結果 ☆2 時点におけるメモリ空間の状態は図2の様になります。, そのまま ☆3 まで進みます。

ただし、2次元配列については方法が複数あり、うまく使い分けることが必要となりますので、そのあたりの考察を含めて書いておきます。, わかりやすいように図表をつけて、1次元配列から2次元配列まで順を追って書いていきます。

しかし、この形式の場合はint num[][5]という形で列数は固定されているため、列数を引数として渡す必要はありません。, 一般的な方法で配列を渡すと、あらかじめ要素数が固定されてしまい汎用性に乏しくなります。 変数minimumのアドレスと、仮引数minとして受け取ったアドレス値は同一ですから、ポインタを通して値を書きかえると呼び出し元の変数の値も書き換えられます。 関数の処理結果をふたつ以上受け取りたい場合は、変数のポインタを実引数で渡し、関数内で書き換えるという方法があります。 これは、文字列(char型配列)の末尾には、NULL文字'\0'があるため、受け取り側(str_arr関数)でも配列数(要素数)が簡単にわかるからです。, ソースコード中のstr_arr関数側では、配列の先頭アドレスの情報(str = 3300)だけを受け取れば、そこから末端NULL文字までを文字型配列として認識すればよいことになります。, 次に、数値型(int型)の2次元配列についてです。 ただしC言語よりも新しいプログラミング言語では参照渡しがデフォルト動作となっている事が多いので、後で必ず自学自習しておいて下さい。, さて (1) の値渡しはみなさんが今まで学んできた普通の引数の渡し方で、次のように定義します。, 「値渡しの」デメリット: 関数の中で呼び出し元の変数(実引数)の値を変更出来ない(取得は出来る), 「ポインタ渡し」のメリット: 関数の中で呼び出し元の変数(実引数)の値を取得したり変更したり出来る, はじめに「値渡し」のデメリットである「どうして関数の中で呼び出し元の変数の値を変更出来ないのか」についてメモリ空間を使って説明して行きます。, 実行すると HOGE 関数の中で a に 34 を代入しているはずなのに、最終的には 12 と表示されます。 具体的には、次のソースコード中、main関数3行目にあるstr_arr(str);のところとなります。, 数値型と異なり、引数として渡すのは、配列の先頭ポインタを示すstrのみで足ります。 そのため、ポインタを通して値を書き換えると呼び出し元の変数の値も書き換わるのです。. 一般的には、次のようにすれば、引数に渡すことができます。, ソースコード中、引数の受け取り側であるnum_arr2関数では、次のように第1引数で、int num[][5]という形式で、受け取る配列を指定しています。, これは、各行ごとの要素数(列数)を指定しないと、プログラム上、2次元配列として認識されないためです。 上記のように、各行のデータが全て繋がっており、データ上は2次元配列でも構造的には1次元配列と同じ形になっています。 tanaka構造体のポインタをshow2関数の仮引数pに代入し、 関数内の処理が行われます。 この場合、ポインタ型なので、 4バイト分のアドレス渡し が行われた事になります。 構造体のメンバがどれだけ増えても アドレス渡しを行えば、一律4バイト です。