第 9 章: C 言語による高度な動的メモリ管理

動的メモリ管理

ダイナミックメモリ機能

マロック

void* malloc (size_t サイズ)

この関数は、メモリ内の連続した利用可能な領域に適用され、この領域へのポインタを返します。

int main() {
    
    
	int arr[10] = {
    
     0 };
	//动态内存管理
	int* p = (int*)malloc(40);
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++) {
    
    
		printf("%d ", *(p + i));
	}
	return 0;
}

割り当てが成功すると、割り当てられた領域へのポインタが返されます。
オープンに失敗した場合は NULL ポインタが返されるため、malloc の戻り値を確認する必要があります。
戻り値の型は void* なので、malloc 関数は開いている空間の型を知りません。使用する場合はユーザーが自分で決めることができます

パラメータのサイズが 0 の場合、malloc の動作は標準では定義されておらず、コンパイラに依存します。

無料

ボイドフリー (void* ptr);

C 言語には、動的メモリの解放とリサイクルに特に使用される別の関数が無料で提供されています。

int main() {
    
    
	int arr[10] = {
    
     0 };
	//动态内存管理
	int* p = (int*)malloc(40);
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++) {
    
    
		printf("%d ", *(p + i));
	}
	//没有free
	//并不是说内存空间就不会收了
	//当程序退出的时候,系统会自动回收内存空间
	free(p);
	p = NULL;
	return 0;
}

パラメータ ptr が指す空間が動的に開かれていない場合、free 関数の動作は未定義です。
パラメータ ptr が NULL ポインタの場合、関数は何も行いません。

コールク

void* calloc (size_t num, size_t size);

calloc 関数は動的メモリ割り当てにも使用されます。

//开辟10个整型的空间

int main(){
    
    
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//打印
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		printf("%d", *(p + i));
	}
	//释放
	free(p);
	p = NULL;

	return 0;
}

この関数の機能は、サイズが size である num 個の要素用のスペースを開き、スペースの各バイトを 0 に初期化することです。
関数 malloc との違いは、calloc はアドレスを返す前に、要求された空間の各バイトをすべて 0 に初期化することです。

再ロック

void realloc (void ptr, size_t サイズ);**

realloc 関数の登場により、動的メモリ管理がより柔軟になります。
過去に申請したスペースが小さすぎると感じることもあれば、申請したスペースが大きすぎると感じることもありますが、適正なメモリにするためには、メモリのサイズを柔軟に調整する必要があります。次に、realloc 関数を使用して、動的に割り当てられたメモリのサイズを調整できます

int main()
{
    
    
	int* p = (int*)malloc(40);
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	//1,2,3,4,5,6,7,8,9,10
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		*(p + i) = i + 1;
	}
	//扩容

	//p = realloc(p, 80);
	//可能扩容失败
	int* ptr = realloc(p, 80);
	if (ptr != NULL) {
    
    
		p = ptr;
	}
	//使用
	for (i = 0; i < 10; i++) {
    
    
		printf("%d", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}
int main()
{
    
    
	int* p = (int*)malloc(40);
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	//1,2,3,4,5,6,7,8,9,10
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		*(p + i) = i + 1;
	}
	//扩容

	//p = realloc(p, 80);
	//可能扩容失败
	int* ptr = realloc(p, 8000);
	if (ptr != NULL) {
    
    
		p = ptr;
	}
	//使用
	for (i = 0; i < 10; i++) {
    
    
		printf("%d", *(p + i));
	}
	free(p);
	p = NULL;
	return 0;
}

ptr は調整対象のメモリアドレス
サイズ、調整後の新しいサイズ、
戻り値は調整後のメモリの開始位置です。
この関数は、元のメモリ空間のサイズを調整することに基づいて、元のメモリ内のデータも新しい空間に移動します。
realloc がメモリ空間を調整する場合は 2 つの状況があります。
ケース 1: 元の空間の後に十分な空間がある
ケース 2: 元の空間の後に十分な空間がない

よくある動的メモリの間違い

NULL ポインタの逆参照操作

int main()
{
    
    
	int* p = (int*)malloc(40);
	if (p == NULL) {
    
    
		return 1;
	}
	*p = 20;
	free(p);
	p = NULL;

	return 0;
}

動的に割り当てられたスペースへの境界外アクセス

int main()
{
    
    
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}

	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		p[i] = i;
		printf("%d ", p[i]);
	}

	free(p);
	p = NULL;
	return 0;

}

非動的に割り当てられたメモリには free 関数を使用する

int main() {
    
    
	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;

	return 0;

}

free を使用して、動的に割り当てられたメモリの一部を解放します。

int main() {
    
    

	int* p = (int*)malloc(40);
	if (p == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	
	int i = 0;
	for (i = 0; i < 10; i++) {
    
    
		*p = i;
		p++;
	}
	
	free(p);
	p = NULL;
	return 0;
}

同じ動的メモリの複数のリリース

int main() {
    
    
	int* p = (int*)malloc(40);

	free(p);
	p = NULL;

	free(p);
}

メモリを動的に開いて解放し忘れる (メモリ リーク)

メモリを開いて解放しないでください

void test() {
    
    
	int* p = (int*)malloc(40);

	int flag = 0;
	scanf("%d", &flag);
	if (flag == 5)
		return 0;
	free(p);
	p = NULL;
}
int main() {
    
    

	test();
	return 0;
}

スタック空間のアドレスを返す問題

int* test() {
    
    
	int a = 10;
	int* p = &a;
	return p;
}

int main() {
    
    
	int* p = test();
	printf("hehe\n");
	printf("%d", *p);
}

C/C++プログラムのメモリ割り当て

ここに画像の説明を挿入

柔軟なアレイ

C99 では、構造体の最後の要素は、「フレキシブル配列」メンバーと呼ばれる、サイズが不明な配列にすることが許可されています。

typedef struct st_type
{
    
    
int i;
int a[0];//柔性数组成员
}type_a;

特徴

  1. 構造体のフレキシブル配列メンバーの前には、少なくとも 1 つの他のメンバーがなければなりません。
  2. sizeof によって返されるこのような構造体のサイズには、フレキシブル配列のメモリは含まれません。

  3. フレキシブル配列メンバーを含む構造体は、メモリの動的な割り当てに malloc() 関数を使用します。割り当てられるメモリは、フレキシブル配列の予想されるサイズに対応できるように、構造体のサイズより大きくする必要があります。
struct s {
    
    
	int a;
	int arr[];
};

int main() {
    
    
	printf("%d", sizeof(struct s));
	return 0;
}
struct s {
    
    
	int a;
	int arr[];
};

int main() {
    
    
	
	//柔性数组的使用
	struct s* ps = (struct s*)malloc(sizeof(struct s) + 40);
	return 0;
}

おすすめ

転載: blog.csdn.net/yanyongfu523/article/details/128791346