Presentation is loading. Please wait.

Presentation is loading. Please wait.

11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと

Similar presentations


Presentation on theme: "11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと"— Presentation transcript:

1 11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
teachers/w483692/CPR1/

2 まとめ:ポインタを使った処理 内容 説明 呼び出し元の変数を書き換える 第 9 回 文字列を渡す・配列を渡す 第 10 回 ファイルポインタ
複数の値を返す 今回 大きな領域を確保する C プログラミング入門 基幹2 (月4)

3 複数返すには、書きこんでもらいたい変数へのポインタを渡す
複数の値を返す return は 1 つの値しか返せない 複数返すには、書きこんでもらいたい変数へのポインタを渡す 例:int 配列の最大・最小値を計算する int maximum(const int *a, int n); int minimum(const int *a, int n); void minmax(const int *a, int n, int *m, int *M); 整数の配列の先頭ポインタとその個数 返り値を使って計算 最小値を書き込むアドレス (変数などへのポインタ) 書き換えるので、 const がつかない 最大値を書き込むアドレス (変数などへのポインタ) 返り値を使わない (使ってもいい) C プログラミング入門 基幹2 (月4)

4 標準ライブラリ関数の例 整数部と小数部を求める関数 double modf(double value, double *iptr);
#include <stdio.h> #include <math.h> int main(void) { double ipart, fpart; fpart = modf(32.5, &ipart); 32 double ipart 変数 ipart のアドレスを渡すことで、関数 modf は、 ipart の中身を書き換えることができる 小数部 0.5 は戻り値として返る C プログラミング入門 基幹2 (月4)

5 ☠ ポインタ変数の初期値の注意 通常の変数同様、ポインタ変数も初期化されない しかし、どこかは指している
初期化しないポインタ変数でアクセスすると危険 { int *p; *p = 100; 暗黙の初期化はされないので、どこを指すアドレスが入っているかは不明。 p C プログラミング入門 基幹2 (月4)

6 null ポインタに対してデリファレンス演算子 * を使うと例外 (null pointer exception) が発生する
どのアドレスでもないことを示す特別な値 空ポインタともいう null ポインタに対してデリファレンス演算子 * を使うと例外 (null pointer exception) が発生する null ポインタ定数マクロ NULL を使って判定する 数値リテラル 0 は、 null ポインタに変換される <stddef.h> で定義されているが、 <stdio.h> などで自動的にインクルードされる C プログラミング入門 基幹2 (月4)

7 ☠ NULL ポインタによる安全策 以下の場合、 NULL ポインタを入れるとよい 初期化時にアドレスを決定しないもの
今まで使っていたアドレスがもう使われない場合 { int *p = NULL; *p = 100; ポインタ変数の値(アドレス)が NULL ポインタの場合、斜線を引いて、どこも指示していないことを表現することがおおい。 NULL ポインタが指す領域にアクセスすると、システムが検知して、例外を発生する p C プログラミング入門 基幹2 (月4)

8 関数内で定義された配列変数は、通常の変数と同様に関数の実行が終了する際に消滅する
配列を返す…? 関数内で定義された配列変数は、通常の変数と同様に関数の実行が終了する際に消滅する ... unsigned char *createNewImage(void) { unsigned char img[512*512] = { 0 }; return img; } int main(void) unsigned char *pImage; pImage = createNewImage(); // この後ポインタ pImage を使って // アクセスしてはいけない 配列の型を戻り値とする関数は作れない その代わり、ポインタを返す この領域は関数の実行後、 消滅してしまう createNewImage の領域 img pImage 返されたポインタ(アドレス)は、すでに意味のある情報を持っていない C プログラミング入門 基幹2 (月4)

9 動的メモリ確保 (dynamic memory allocation)
自動的に消滅しないメモリ領域を作る 動的メモリ確保 (dynamic memory allocation) 変数のような言語機能ではなく、標準ライブラリ関数を使って、直接 OS にメモリ領域を要求する 確保された領域は自由に使える 変数名はつかないので、ポインタでアクセスする 自動的には消去されないので、自分で解放する C プログラミング入門 基幹2 (月4)

10 malloc() 関数によって指定したバイト数のメモリ領域を確保する
動的メモリの確保 malloc() 関数によって指定したバイト数のメモリ領域を確保する 確保された領域が置かれているところをヒープ (heap) という メモリ領域は初期化されない メモリ不足などで確保が失敗した場合、 NULL ポインタが返る malloc() のプロトタイプ #include <stdlib.h> void *malloc(size_t size); 次のスライドで説明 C プログラミング入門 基幹2 (月4)

11 確保されたメモリ領域の値 malloc は void * 型を返す 特定の型を表さない 任意のポインタ型に自動変換できる ヒープ領域 {
C++では自動変換されないため、 static_cast が必要 ヒープ領域 { int *pInt; double *pDouble; pInt = malloc(16); pInt[0] = 100; // double の場合 // pDouble = malloc(16); // pDouble[0] = 3.14; 100 ? 3.14 指し示すアドレスは同じだが、扱われ方が型によって異なる int *pInt double *pDouble ? ? sizeof(int) == 4, sizeof(double) == 8 の場合 main のスタック領域 C プログラミング入門 基幹2 (月4)

12 例:画素値を unsigned char 型として、 w × h のサイズのメモリ領域を確保
サイズの指定 例: int 型の100個の領域を確保 int *mem = malloc(sizeof(int) * 100); mem[0] ~ mem[99] としてアクセス 例:画素値を unsigned char 型として、 w × h のサイズのメモリ領域を確保 unsigned char *image = malloc(sizeof(unsigned char) * w * h); 座標 x, y に対して、 image[x+w*h] としてアクセス 0 ≤ x < w, 0 ≤ y < h sizeof(unsigned char) は必ず 1 なので、書かなくてもよい C プログラミング入門 基幹2 (月4)

13 calloc(), realloc() のプロトタイプ
動的メモリの確保 (その他) calloc(): malloc() と同じだが、さらにゼロで初期化を行う size × num バイトの領域を確保する メモリの全てのビットが 0 となるからと言って、 double などの型の値として 0 となるとは限らない realloc(): 確保された領域のサイズを変更 calloc(), realloc() のプロトタイプ #include <stdlib.h> void *calloc(size_t num, size_t size); void *realloc(void *ptr, size_t new_size); C プログラミング入門 基幹2 (月4)

14 確保したメモリへのポインタを指定して、その領域を解放する 解放した領域は使用してはならない
動的メモリの解放 確保したメモリへのポインタを指定して、その領域を解放する 解放した領域は使用してはならない NULL を入れておくと安全。 既に解放済みのポインタに対して実行してはいけない(2重解放エラー) NULL ポインタを与えた場合は何もしない free() のプロトタイプ #include <stdlib.h> void free(void* ptr); どんな型のポインタも void * に自動的に変換される C プログラミング入門 基幹2 (月4)

15 画像のためのメモリを自動的に確保する関数
例題:PGM 画像 画像のためのメモリを自動的に確保する関数 ... // 画素値 0 で初期化された画像を動的に作成する unsigned char *createImage(int width, int height) { int i; unsigned char *img = malloc(width * height); if(img == NULL) return NULL; } for(i = 0; i < width*height; ++i) img[i] = 0; return img; sizeof(unsigned char) == 1 なので、掛けるのを省略 メモリ不足の場合は NULL を返す すべてゼロで初期化する C プログラミング入門 基幹2 (月4)

16 例題:PGM 画像 使い終わったら自分で free() する ... int main(void) {
unsigned char *Image = NULL; Image = createImage(640, 480); free(Image), Image = NULL; ポインタは無効になるので、 NULL ポインタを代入しておくとよい メモリ領域を解放する C プログラミング入門 基幹2 (月4)

17 用語:メモリリーク (memory leak)
malloc() で動的確保した領域を free() で解放し忘れて、メモリが圧迫されること 単純なプログラムではこの手のバグは見つけやすいが、秋期「Cプログラミング」で扱う複雑なデータ構造では発生しやすく、見つけづらいバグとなる。 C プログラミング入門 基幹2 (月4)

18 メモリに領域を確保して値を読み書きする方法には4つある
変数とポインタと動的メモリ確保の整理 メモリに領域を確保して値を読み書きする方法には4つある 分類 生存期間 スコープ メモリ領域 初期化 自動変数 (ローカル変数) 定義位置からブロック終端まで スタック 初期化が指定されている場合のみ、ブロックに入るたびに初期化される 大域変数 (グローバル変数) プログラムの実行開始から終了まで 定義位置からプログラム終了まで 静的領域 プログラム開始時に1度だけ。初期化が指定されない場合、0 で初期化される 静的変数 (static 変数) 同上 動的メモリ 確保から解放まで ヒープ malloc() はされない calloc() は 0 を書きこむ 変数名で参照しない C プログラミング入門 基幹2 (月4)

19 配列変数と動的メモリ確保の比較 機能 配列 動的メモリ確保 サイズ 自動変数の場合は、あまり大きなサイズは確保できない。 ほとんど制限がない
多次元 可能。ただし、関数などに次元やサイズを伝えられない 単なるポインタなので不可能 コピー 不可能。標準ライブラリ関数を利用 解放 自動変数の場合、ブロックを抜けると自動的に消滅する free() によって自分で解放する アクセス 変数名が先頭へのポインタになる malloc() によって得られるアドレスをポインタ変数に入れて扱う C プログラミング入門 基幹2 (月4)


Download ppt "11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと"

Similar presentations


Ads by Google