このページをはてなブックマークに追加このページを含むはてなブックマーク このページをlivedoor クリップに追加このページを含むlivedoor クリップ

  • 追加された行はこの色です。
  • 削除された行はこの色です。
*目次 [#z02f2a88]

#contents


*realloc [#v0b7d232]

*プリプロセッサ [#y4df5fa5]

 void *realloc(void *mem, size_t newsize);

**引数 [#uf41b23d]

-第1引数
--拡張する領域を指定するためのポインタ。
---このポインタはmalloc,calloc,reallocのいずれかが返したアドレスでなければならない。
--例外としてNULLが与えられた場合は、reallocはmallocと同じ動作をする。
-第2引数
--拡張したい大きさ。

**戻り値 [#bf08a352]

-拡張に失敗するとNULLが返される。

*reallocの特徴 [#kdf310ae]

-calloc,malloc,reallocにより作成されたメモリ領域pを保持しながら、再度sizeバイトの大きさに拡張する。
--最初はこれくらいで全部のデータが収まると予想してmallocしたとする。しかし、その後確保したメモリ領域では足りなくなることもある。このときの対処法は2つ考えられる。
---まず1つ目の方法は、十分なメモリをmallocにより新しく確保して、そこにコピーしてしまう方法である。
---次に2つ目の方法は、reallocでメモリ領域を拡張する方法である。
-失敗するとNULLが返される。
-拡張されてできたメモリ領域は初期化されない。
-メモリが配列A,B,未使用という順番で並んでいたとする。
--このとき、Bをreallocで拡張するときは、Bのアドレスは変化せずにサイズだけが拡張される。
--一方、Aをreallocで拡張するときは、Bが邪魔なのでそのままAを拡張することはできない。そこで、Bの後ろにAをコピーし、そのAの後ろにサイズを拡張していく。つまり、元のAのアドレスとは異なるアドレスが返されることになる。


*テクニック [#gb12e15f]

**reallocを用いた動的なメモリ確保例 [#ta07e089]

#code(c){{
#include <stdio.h>
#include <stdlib.h>

int main(void){
	int c;			/* 入力文字 */
	int size = 0;		/* 文字数 */
	char *buf_p = NULL;

	while (1) {
		/*-----------------------------------------------
		  標準入力から1文字ずつ拡張されたメモリ領域に格納
		  する
		-----------------------------------------------*/
		buf_p = realloc(buf_p, size + 1);
		if (buf_p == NULL) {
			fprintf(stderr, "メモリ領域の確保に失敗しました。\n");
			free(buf_p);
			exit(EXIT_FAILURE);
		}
		c = fgetc(stdin);
		if (c != EOF) {
			buf_p[size++] = c;
		} else {
			buf_p[size] = '\0';
			break;
		}
	}
	/*-----------------------------------------------
	  文字列を表示し、メモリ領域を開放する
	-----------------------------------------------*/
	if (buf_p) {
		puts(buf_p);
		free(buf_p);
	}
	return 0;
}
}}


**reallocで拡張する領域の大小について [#a80acec1]

 1文字ずつreallocをしていては効率が悪くなってしまうし、フラグメンテーションも発生しやすいという問題がある。もしreallocをするときは、1度にある程度まとまった量を拡張した方がよいと言える。


**割り当て済み領域を初期化する [#i3da36a5]

 realloc関数を使って領域を拡大しても、既存のすべてのデータが保持されている。簡単に初期化したければ、memset関数を用いればよい。具体的に言えば、古いデータの存在する次の位置から新しい領域の末尾までを次のように初期化すればよい。

 pmem = pmemnew + BUFF_SIZE;	/* pmemポインタを未初期化部分の先頭位置に設定する */
 memset(pmem, 0, BUFF_SIZE);	/* memset関数を使って初期化する */

 サンプルプログラムは次の通りである。

#code(c){{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFF_SIZE	256		/* バッファのサイズ */
#define NEW_BUFF_SIZE	(BUFF_SIZE * 2)	/* 拡張されたバッファのサイズ */

int main(void){
	int i;			/* for文用のカウンタ */
	unsigned char *buf_p = NULL;
	unsigned char *tmp_buf_p = NULL;
	unsigned char *new_buf_p = NULL;

	/*-------------------------------------------------------
	  malloc関数を用いてメモリを割り当て、数値を格納し、表示する
	-------------------------------------------------------*/
	tmp_buf_p = (buf_p = (unsigned char *)malloc(BUFF_SIZE));
	if (buf_p == NULL) {
		printf("メモリ領域の確保に失敗しました。\n");
		free(buf_p);
		exit(EXIT_FAILURE);
	}
	for (i = 0; i < BUFF_SIZE; i++) {
		*buf_p++ = (char)i;
	}
	buf_p = tmp_buf_p;	/* buf_pポインタのリセット */
	printf("メモリの拡大前の状態\n");
	for (i = 0; i < BUFF_SIZE; i++) {
		printf("%u ", *buf_p++);
	}
	printf("\n\n");

	/*-------------------------------------------------------
	  realloc関数を用いてメモリの領域を拡大する
	-------------------------------------------------------*/
	new_buf_p = realloc(tmp_buf_p, NEW_BUFF_SIZE);
	if (new_buf_p != NULL) {
		/*-----------------------------------------------
		  初期化
		-----------------------------------------------*/
		buf_p = new_buf_p + BUFF_SIZE;
		memset(buf_p, 0, BUFF_SIZE);
		buf_p = new_buf_p;	/* 新しい先頭位置のセット */
		/*-----------------------------------------------
		  拡大後のメモリ内容を表示する
		-----------------------------------------------*/
		printf("メモリの拡大後の状態\n");
		for (i = 0; i < NEW_BUFF_SIZE; i++) {
			printf("%u ", *buf_p++);
		}
		printf("\n");
		/*-----------------------------------------------
		  メモリを解放し、NULLを代入する
		-----------------------------------------------*/
		free(new_buf_p);
		new_buf_p = NULL;
	/*-------------------------------------------------------
	  メモリの拡大に失敗したとときの処理
	-------------------------------------------------------*/
	} else {
		free(new_buf_p);
		new_buf_p = NULL;
		fprintf(stderr, "メモリの拡大に失敗しました。\n");
		exit(EXIT_FAILURE);
	}
	return 0;
}
}}

*参考文献 [#y3213da4]

-『C言語ポインタが理解できない理由』
-『美しいCプログラミング見本帖 〜ポインタ手習い指南〜』