ポインタ演算子のイメージ
+0 +1 +2 +3 +4 +5 +6 +7 +8
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
char型 [] [] [] [] [] [] [] [] []
+0 +1 +2
↓ ↓ ↓
long型 [] [] [] [] [] [] [] []|[]
|← [0] →|← [1] →|←
ポインタ演算の秘密
・同じ1加算でもデータ型によって加算される量は異なる
・ポインタにおける1加算は実際にはデータ型で使用するバイト数だけ加算される
・配列変数の添え字([]演算子)も同様である
ポインタ演算の秘密の補足
・ただしプログラムを組む人は『実際の加算量』について意識する必要はない
・1加算すれば次のデータに到達できると考えてよい
・意識させないための仕組みがポインタである
ポインタ変数と配列変数の違い
ポインタ変数 配列変数
----------------------------------------------------
宣言 int *piPointer; int piArray[10];
代入 できる できない
領域確保 1つ 指定個数
格納する値 ポインタ 各要素に通常の値
(アドレス)
<ポインタ変数>
piPointer = &iValue;
<配列変数>
piArray = &iValue; 代入はできない。
C言語研修(基礎編)
〜関数〜
関数とは
・ブラックボックスのことである
A→[?]→B
・数学における関数と意味的には一緒
・英語ではfunction(機能・作用)という
C言語における関数とは
・基本的な関数(標準関数)は用意されている
−C言語の構文だけでは何もできない
・自分で新しく関数を作ることもできる
−関数を作成する場合は自分で定義する
・C言語にはサブルーチン(Sub Routine)という呼称はない
−全ての関数という呼称で統一されている
C言語における関数とは
・関数は関数から呼ばれていて初めて実行される
−呼び出しされない関数は何もしない
・main関数のみプログラム実行時に自動的によばれる
関数作成する目的
・1つの関数を小さくする
−制御文などが深くならない様に
・共通部分を1つにまとめる
−同じような処理を行っている部分を関数に
−プログラムが小さくなる
−修正量が減る
関数の宣言
戻り値の型 関数名 (引数リスト){
関数の動作を実現する文
}
機能名
A → [ ? ] → B
関数名について
・関数が実現している機能を表す名称
・半角の英数字と一部の記号が使用できる
−全角文字や半角カタカナは使用できない
−C言語全体を通したルールである
・関数名のネーミングルールはプロジェクト毎に異なる
引数リストについて
・引数は複数渡せる
−それぞれの引数をカンマ(,)で区切って記述する
・引数にはそれぞれデータ型がある
−引数名の前にデータ型名をつける
−引数毎にデータ型が異なっても良い
・引数のない関数も定義できる
−引数リストにvoidと記述する
引数の名称
仮引数 関数を定義する時に使用する引数
実引数 関数を呼び出し時に指定する引数
※仮引数に何も入れない時は定義するときはvoidを入れる
実引数にはなにも入れない
#include
int power(int iBase);
:
void main(void){
:
a=power(i) ← iが実引数
}
int power(int iBase){ ←int iBaseが仮引数
:
}
戻り値について
・戻り値は1つだけしか返さない
−複数の戻り値を返すことはできない
・戻り値にはデータ型がある
−関数名にはデータ型がある
−関数名の前にデータ型名をつける
−『戻り値の型』=『関数の型』と考えてよい
・戻り値のない関数も定義できる
−関数名の前にvoidと記述する
戻り値について
・戻り値がreturn文で返す
−戻り値は自動的には返らない
−return文は関数定義の本文中で使用する
・return文が使われると関数の途中でも関数から抜ける
−return文はbreak文の関数版だと思ってよい
−必要なら一つの関数にいくつ書いても良い
が、変わりづらくなるので濫用はしない
関数定義の本文について
・他の関数で使用している変数名も変数宣言で使用できる
−その場合は別の変数として扱われる
・return文により処理を途中で止められる
−戻り値のある関数の場合は戻り値も指定する
−わかりづらくなるので濫用はしない
関数プロトタイプの存在意義
・以下の目的を実現するために関数プロトタイプは存在する
−関数が存在することをコンパイラに伝える
−引数の有無とデータ型をコンパイラに伝える
−戻り値の有無とデータ型をコンパイラに伝える
#include
int power(int iBase); ← プロトタイプ宣言
:
void main(void){
:
a=power(i) ← iが実引数
}
int power(int iBase){ ←int iBaseが仮引数
:
}
関数プロトタイプの宣言
・引数リストの)の後ろに";"を記述するだけ
引数の名前(iBase,iExp)は省略可能
int power(int iBase, int iExp);
~~~~~ ~~~~ ~
・関数を使用するより前にプロトタイプ宣言を行う
−通常はプロトタイプソースの先頭付近(もしくはヘッダ
ファイル内)にまとめて記述する
引数の渡し方
値渡し 引数として値そのものを渡す
(Call by Value) 関数側で仮引数の値を操作しても
呼び出し側の実引数には影響しない
参照渡し 引数として変数のアドレス(ポインタ)を渡す
(Call by Reference) 関数側で引数に対して行った操作が
呼び出し側の実引数にも反映される
値渡しのイメージ
・関数側に新しく用意した変数に値をコピーするイメージ
呼び出し側 | 関数側
⇒
[ ○ ] | [ ○ ]
値渡しのメモリイメージ
値渡しのメモリイメージ
呼び出し側 [ 10 ]-----------
: |
: |関数側に新しく用意した
: |変数に値をコピーする
関数側 [ 10 ]←---------
値渡しの関数
宣言 引数のデータ型を通常のデータ型にする
int power(int iBase, int iExp);
使用 値を関数に渡す
power(2, i);
備考 定数も実引数として指定できる
関数の独立性が保たれる
参照渡しのイメージ
・呼び出し側の変数を共有するイメージ
呼び出し側 | 関数側
⇒[ ○ ]
|
参照渡しのメモリイメージ
呼び出し側 [ 10 ]1000番地---
: |
: |変数のアドレス(=1000番地)
: |を関数側に渡す
関数側 [ 10 ]←---------
参照渡しの関数
宣言 引数のデータ型をポインタ型にする
void swap(int *iVal1, int *iVal2);
使用 変数のアドレスを関数に渡す
swap(&iValue1, &iValue2);
備考 定数は実引数として指定できない
−定数にはアドレスがないため
引数の参照渡しの注意点
・関数の独立性を保つため、特定の場合を除いて使用しない
・原則として以下の場合に使用する
−関数の処理結果(戻り値)を複数戻したい場合
−ポインタを引数として渡す場合
−配列変数を引数として渡す場合
文字列を関数に渡す
・文字列は文字(char)型の配列変数である
・配列変数はポインタ変数とほぼ同じ
・ポインタを引数に渡すには参照渡しを使用
−ポインタで受け取る
−配列として受け取る
文字列を受け取る関数
宣言 引数をポインタ型もしくは配列にする
void PutString(char *pszSrc);
void PutString(char pszSrc[]);
使用 文字列の先頭アドレスへのポインタを渡す
putString(pszBuffer);
備考 文字列定数も指定できる
−コンパイル時にワーニングが出る場合あり
文字列を受け取る関数の補足
・参照渡しで値が関数に渡すということは関数内で配列変数の値が
書き換えられてしまう可能性があるということである。
・関数内で配列変数の値を書き換えないと言うことを明示するには
const指定を引数指定に追加する
void PutString(const char *pszSrc)