[C Advanced]動的メモリ管理(1)

コンテンツ

1.動的メモリ割り当てが存在するのはなぜですか?

2.動的メモリ機能の概要

      2.1、mallocおよび無料

      2.2、calloc

      2.3、realloc

3.一般的な動的メモリエラー

      3.1。NULLポインターの逆参照操作

      3.2.動的開発スペースへの国境を越えたアクセス

      3.3.動的に開発されていないメモリには無料リリースを使用する

      3.4。動的に開発されたメモリの一部を解放するために無料で使用する

      3.5.同じ動的メモリを複数回解放する

      3.6.動的にメモリを開き、解放するのを忘れる(メモリリーク)


1.動的メモリ割り当てが存在するのはなぜですか?

  • 私たちが習得したメモリ開発方法は次のとおりです。
int val = 20;//在栈空间上开辟四个字节
char arr[1000] = {0};//在栈空间上开辟1000个字节的连续空间
  • ただし、上記のスペースを開く方法には、次の2つの特徴があります。
  1. 開放するスペースの大きさは固定されています。
  2. 配列を宣言するときは、配列の長さを指定する必要があり、必要なメモリはコンパイル時に割り当てられます。

ただし、スペースの必要性は上記に限定されません。必要なスペースのサイズは、プログラムの実行中にのみ知ることができ、スペースを開くために配列をコンパイルする方法が満たされない場合があります。たとえば、上記のコードでchar型によって定義された1000バイトのサイズで、実際に10バイトだけが必要な場合、残りの990バイトは無駄になります。

現時点では、動的ストレージを開くことしかできません。

  • 動的メモリによって開かれたスペース割り当てを確認します。

2.動的メモリ機能の概要

2.1、mallocおよび無料

  • malloc:

C言語は、動的メモリ開発のための機能を提供します。

void* malloc (size_t size);

この関数は、メモリ内の連続した空き領域を要求し、この領域へのポインタを返します。

  1. 開くことが成功すると、開いたスペースへのポインタが返されます。
  2. 開発が失敗した場合、NULLポインターが返されるため、mallocの戻り値を確認する必要があります。
  3. 戻り値の型はvoid*であるため、malloc関数は、開かれたスペースの型とユーザー自身を認識しません。
  4. 決定する。
  5. パラメータサイズが0の場合、mallocの動作は標準では定義されておらず、コンパイラによって異なります。
  • 注:malloc関数を使用して、ヘッダーファイル#include<stdlib.h>を参照します。
  • 例えば:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……

	//释放
	return 0;
}
  • 自由:

C言語は、動的メモリの解放と回復に特別に使用される別の関数フリーを提供します。関数プロトタイプは次のとおりです。

void free (void* ptr);
  • free関数は、動的に割り当てられたメモリを解放するために使用されます。
  1. パラメータptrが指すスペースが動的に割り当てられていない場合、free関数の動作は定義されていません。
  2. パラメータptrがNULLポインタの場合、関数は何もしません。
  • mallocとfreeの両方がstdlib.hヘッダーファイルで宣言されています。
  • たとえば、上記のコードにはリリースと使用のリンクがあり、すべてのコードは次のように完成されています。
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)malloc(40);
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

2.2、calloc

C言語は、動的メモリ割り当てにも使用されるcallocと呼ばれる関数も提供します。プロトタイプは次のとおりです。

void* calloc (size_t num, size_t size);
  • numは要素の数を表し、sizeは各要素のサイズを表します。
  1. この関数の機能は、サイズサイズのnum要素のスペースを開き、スペースの各バイトを0に初期化することです。
  2. 関数mallocとの唯一の違いは、callocがアドレスを返す前に、要求されたスペースの各バイトをすべて0に初期化することです。
  • 例えば:
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

mallo関数と比較して、malloc関数の方が効率的です。malloc関数自体には初期化関数がなく、アドレスを直接返します。

2.3、realloc

realloc関数の出現により、動的メモリ管理がより柔軟になります。

過去に申請したスペースが小さすぎる場合や、申請したスペースが大きすぎる場合があります。
適切な時間にメモリを使用するには、メモリのサイズを柔軟に調整する必要があります。realloc関数は
、動的に割り当てられたメモリのサイズを調整できます。

関数プロトタイプは次のとおりです。

void* realloc (void* ptr, size_t size);
  • ptrは調整するメモリアドレスです
  • サイズは調整後の新しいサイズです
  • 戻り値は、調整されたメモリの開始位置です。
  • この関数は、元のメモリスペースのサイズの調整に基づいて、元のメモリ内のデータも新しいスペースに移動します。
  • reallocがメモリスペースを調整する状況は2つあります。
  1. ケース1:元のスペースの後に十分なスペースがあります 
  2. ケース2:元のスペースの後に十分なスペースがありません

  •  ケース1

ケース1の場合、メモリを拡張するには、元のメモリの直後にスペースを追加します。元のスペースのデータは変更されません。

  • ケース2

ケース2の場合、元の54スペースの後に十分なスペースがない場合、拡張方法は次のとおりです。使用するヒープスペース上で適切なサイズの別の連続スペースを見つけます。この関数は、新しいメモリアドレスを返します。

上記の2つの状況のた​​め、realloc関数の使用に注意する必要があります。例えば:

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//开辟10个整型的空间
	int* p = (int*)calloc(10, sizeof(int));
	if (NULL == p)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	// 使用……
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p[i]);
	}
	//需要增容
	int* ptr = (int*)realloc(p, 80);
	if (NULL != ptr)
	{
		p = ptr;
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

3.一般的な動的メモリエラー

3.1。NULLポインターの逆参照操作

#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}
  • この時点で、pが空かどうかを確認するためにデバッグします。

  • 正しい書き方は次のとおりです。pがnullポインタかどうかを判断する必要があります
#include<stdio.h>
#include<limits.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(INT_MAX);
	//INT_MAX:整型最大的值

    // 判断:
 	if (p == NULL)
		return 0;

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	//出问题,因为malloc开辟的空间过大,超过限制了,所以会返回一个控指针,此时p就是一个空指针
	return 0;
}

3.2.動的開発スペースへの国境を越えたアクセス

#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
int main()
{
	//申请10个字符的空间:
	char* p = (char*)malloc(10 * sizeof(char));
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}
	//使用
	int i = 0;
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = 'a' + i; // i=10的时候越界访问
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}
  • 正しいスペルは次のとおりです。
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 'a' + i;
	}

3.3.動的に開発されていないメモリには無料リリースを使用する

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;
	return 0;
}

3.4。動的に開発されたメモリの一部を解放するために無料で使用する

void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}

3.5.同じ動的メモリを複数回解放する

void test()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重复释放
}
  • スペースの一部を再度解放することはできませんが、次のようにnullポインターに割り当てることで、スペースを再度解放できます。
void test()
{
	int* p = (int*)malloc(100);
	free(p);
    p = NULL;
	free(p);//重复释放
}

3.6.動的にメモリを開き、解放するのを忘れる(メモリリーク)

#include<stdio.h>
#include<stdlib.h>
void test()
{
	int* p = (int*)malloc(100);
	if (p == NULL)
	{
		return 0;
	}
	//使用
	//……
	//忘记释放,就会出现内存泄露
}
int main()
{
	test();
	return 0;
}
  • リリースを忘れると、メモリリークが発生します
  1. voidタイプが返されない関数の場合、リリースは関数内で実行する必要があります。そうしないと、関数を終了した後に関数が見つかりません。
  2. 戻り値のある関数の場合、戻り値はメイン関数で解放できます

つまり、アプリケーションスペースが解放されます

おすすめ

転載: blog.csdn.net/bit_zyx/article/details/122737321