【C言語】Xiao Wangで動的メモリ管理を簡単に実現(わかりやすい)

上記のアドレス帳の作成では、動的アドレス帳の使用に動的メモリ管理が使用されています。メモリ管理機能の使用方法を知りたい学生がいる場合は、この記事を参照してください。次に、動的メモリについて一緒に学びます。関連する知識。【C言語】C言語を使って静的・動的アドレス帳を実現する(シンプルでわかりやすい) - プログラマー募集

目次

序文

1. ダイナミックメモリ機能とは何ですか?

1.1 malloc と無料

1.2 コールロック

1.3 再割り当て

1.3.1 realloc がメモリ空間を調整する場合は 2 つの状況があります。

2. 一般的な動的メモリエラー (ケース分析)

2.1 NULLポインタの逆参照操作

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

2.3 free を使用して非動的メモリを解放する

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

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

2.6 動的にスペースを空けて解放し忘れる(メモリリーク)

3. 演習

3.1 最初の

3.2 2番目

3.3 3番目

3.4 4番目

要約する


序文

私たちが習得した記憶力開発には2つの方法があります

int a = 10; //スタックスペースに 4 バイトのスペースを空けます

int a[10] = {0}; //スタック領域に 40 バイトの連続領域を空ける

これらの開発方法には、次の 2 つの共通の特徴があります。

1. 宇宙開発の規模は決まっている

2. 配列を宣言するときは、配列の長さを指定する必要があり、必要なメモリはコンパイル時に割り当てられます。

動的メモリ管理を実装する必要があるのはなぜですか?また、その役割は何ですか?

スペースに対する要求は上記 2 つに限定されるものではなく、実行後にどのくらいのスペースが必要かを知りたい場合もありますが、このとき、メモリ スペースを動的に開く必要がある、つまりダイナミック メモリ機能が誕生しました。

1. ダイナミックメモリ機能とは何ですか?

1. malloc と free

2.calloc

3.再割り当て

1.1 malloc と無料

malloc は、C 言語で提供される動的メモリ開発関数です。

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

1. 割り当てが成功した場合は、割り当てられた領域へのポインタを返します。

2. 開発に失敗した場合はNULLポインタ が返される ため、 mallocの戻り値を 確認する必要があります。
3. 戻り値の型は void*である ため、 malloc 関数は開いている領域の型を知りません。使用する場合はユーザーが自分で決定できます。
4. パラメータの サイズ 0の場合 mallocの動作は 標準では定義されておらず、コンパイラに依存します。

void*の戻り値の型、使用時は状況に応じて強制変換される

C 言語には、動的メモリの解放と再利用に特に使用される無料の関数も用意されており、関数のプロトタイプは次のとおりです。

free 関数は、動的に割り当てられたメモリを解放するために使用されます。

1.パラメータ ptr が指す空間が動的に開かれていない場合、 free関数の動作は未定義です。(エラーが報告されます)

2. パラメータptr がNULLポインタの場合、関数は何も行いません。

グラフィックプレゼンテーション:

ヘッダー ファイルに malloc.h を追加します 

 コードデモ:

int main()
{
	int num = 0;
	scanf("%d", &num);
	//int arr[num] = { 0 };   num 在 [] 中
	//VS 不支持这样,但是可以使用动态内存函数,实现动态数组
	int* ptr = (int*)malloc(sizeof(int) * num);
	if (NULL == ptr) {//进行判断是否创建成功
		perror("malloc::ptr");	
	}
	else {
		for (int i = 0; i < 10; i++) {
			*(ptr + i) = i;
		}
		for (int i = 0; i < 10; i++) {
			printf("%d ", *(ptr + i));
		}
		free(ptr);  //使用free函数释放动态申请的ptr
		ptr = NULL;  //将ptr  free之后,置为NULL,防止野指针非法访问
	}

	return 0;
}

また、malloc関数で作成した空間は初期化されず、図に示すようにランダムな値が格納されます。

1.2 コールロック

calloc 関数は動的メモリ割り当てのために C 言語でも提供されており、プロトタイプは次のとおりです。

Calloc 関数の紹介:

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

実践的なグラフィック分析:

 コードデモ:

int main()
{
	int num = 0;
	int* ptr = (int*)calloc(10, sizeof(int));//使用calloc函数
	for (int i = 0; i < 10; i++) {
			*(ptr + i) = i;
		}
		for (int i = 0; i < 10; i++) {
			printf("%d ", *(ptr + i));
		}
		free(ptr);//free 动态申请的ptr
		ptr = NULL;//置为NULL,防止野指针越界访问
	return 0;

}

calloc によって動的に要求されたスペースのすべてのバイトが 0 になりますか? 下の写真を見てみましょう

これは、calloc 関数と malloc 関数の最大の違いでもあり、自動的に初期化されるかどうか、前者には初期化があり、後者には初期化がありません。

1.3 再割り当て

realloc も C 言語で提供される動的メモリ アプリケーション関数であり、動的メモリ管理をより柔軟にします。本質は、動的に適用されるスペースを増やすことができ、より柔軟になることです。

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

 関数のプロトタイプは次のとおりで、2 つの仮パラメータ ptr と size が分析されます。

上に示すように:

1.ptr は NULL にすることができます。これは、新しいスペースを malloc することと同じです。ptr は調整されるメモリ アドレスです。

2. size が 0 の場合もあり、その場合、戻り値は特定のライブラリ実装によって異なります。null ポインターである場合もあれば、逆参照すべきではない別の場所である場合もあります。サイズは調整後のサイズです

3. 戻り値は、調整されたメモリ開始位置です。

4. この関数は、元のメモリ空間のサイズを調整することに基づいて、元のデータも新しい空間に移動します。

1.3.1 realloc がメモリ空間を調整する場合は 2 つの状況があります。

最初のケース: 元の領域の後のメモリ領域が十分な場合

2 番目のケース: 元の領域以降のメモリ領域が十分でない場合

写真が示すように:

 これら 2 つの状況はランダムに発生するため、どちらを使用するかを制御することはできません。そのため、1 つ注意する必要があります。動的に開かれた元の変数 ptr を使用して realloc を直接受け取るのではなく、一時変数を作成して受け取り、最初に判断する必要があります。空にしてから ptr に再割り当てします

コード図:

 自分でテストできます。

int main()
{
	int* p = (int*)malloc(sizeof(int)*10);
	if (p == NULL) {
		perror("malloc::p");
	}
	else {
		printf("%p\n", p);
	}
	int* ptr = (int*)realloc(p, sizeof(int) * 20);//创建临时变量
//如果使用 int* p = (int*)realloc(p,....这样的话如果创建失败,返回NULL,
//这样的话p的内容就没有了,所以创建临时变量ptr,然后下面判空之后可以交换
	if (NULL == ptr) {
		perror("realloc::ptr");
	}
	else {
		p = ptr;
		ptr = NULL;
		printf("%p\n", p);
	}

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

2. 一般的な動的メモリエラー (ケース分析)

2.1 NULLポインタの逆参照操作

つまり、動的メモリ機能の使い方を学びたいときは、NULL を判定する必要があります。そうしないと、NULL に問題があるかどうかは誰にもわかりません。

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	*p = 10;//这个时候谁知道p是不是NULL,如果是NULL,那么这就是非法访问,是错误
	free(p);
    return 0;
}

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

つまり、どれだけのスペースが空けられるかがスペースの量であり、このバイト数の制限を超えてスペースの外のアドレスにアクセスすることはできません。

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	if (NULL == p) {
		perror("malloc::p");
	}
	else {
		for (int i = 0; i < 100; i++) {
			*(p + i) = i + 1;//当i等于10的时候就开始越界访问
		}
		for (int i = 0; i < 11; i++) {
			printf("%d ", *(p + i));
		}
		free(p);
		p = NULL;
	}
	return 0;
}

配列と同じように、境界を越えることはなく、余分なことを考える必要はありません

2.3 free を使用して非動的メモリを解放する

free には NULL を入れることができ、エラーは報告されませんが、非動的に開発されたメモリに置くことはできないため、エラーが報告されます。

無料関数のグラフ分析:

 コードデモ:

int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	int a = 10;
	free(&a);//非动态内存开辟的,会报错
//free(NULL);  //没有什么反应,程序正常
	return 0;
}

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

つまり、メモリを動的にオープンした後で p ポインタの位置が変更された場合、free(p) は解放の一部にすぎません。

コードデモ:

//举例
int main()
{
	int* p = (int*)malloc(sizeof(int) * 10);
	p++;
	free(p);//这个的时候p向右移动一个整型字节空间,再进行释放,那么先前那个空间就没被释放
	return 0;
}

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

複数のリリースではエラーが報告されます

グラフィック:

2.6 動的にスペースを空けて解放し忘れる(メモリリーク)

したがって、メモリリークを防ぐために、使用されていないときに解放できる動的スペースを開発する必要があります。

コードデモ:

int main()
{
	//test();
	while (1) {
		malloc(1);//一直申请就是不释放
	}
}

3. 演習

3.1 最初の

void GetMemory(char *p)
{
 p = (char *)malloc(100);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str);
//改为传递地址就可以或者就是用str接收
//str= GetMemory(str);//实际上用临时变量接收更好
 strcpy(str, "hello world");
 printf(str);
//用完释放
//free(str);
//str=NULL;
}

1. 値渡し操作。p がスペースに適用された場合でも、str は変更されないため、str は NULL のままで、strcpy は使用できません。

2. メモリ リーク、GetMemory(str); p の領域が解放されない 

3.2 2番目

char *GetMemory(void)
{
//修改为:
//static char p[] = "hello world";
 char p[] = "hello world";
 return p;
}
void Test(void)
{
 char *str = NULL;
 str = GetMemory();
 printf(str);
}

典型的な戻りスタック アドレスの問題では、配列 p はローカル変数であり、確かに p のアドレスは str に返されますが、GetMemory 関数の終了後、配列 p 用のスペースがなく、p のアドレスにアクセスします (printf(str) ))は不正アクセスとなります

3.3 3番目

void GetMemory(char **p, int num)
{
 *p = (char *)malloc(num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(&str, 100);
 strcpy(str, "hello");
 printf(str);
//修改为:free(str);
//str=NULL;
}

str によって動的に開かれたスペースは解放されず、空きがない (str)、str=NULL

3.4 4番目

void Test(void)
{
 char *str = (char *) malloc(100);
 strcpy(str, "hello");
 free(str);
//修改意见:
//str=NULL;
 if(str != NULL)
 {
 strcpy(str, "world");
 printf(str);
 }
}

str によって要求されたスペースは、str が使用される前に解放され、str! = NULL、元のアドレスを保持します。str はこの時点ですでにワイルド ポインタです (対応する空間へのアクセスがないため)。その後、実際に world が出力されますが、if ステートメントはすでに間違っています。str に設定するだけです。 =NULLアップ

要約する

この記事では主に、malloc、calloc、realloc、free 関数の紹介と使い方の詳細、および動的メモリ管理に関するいくつかの関数について説明します。これらを学習すると、将来データ構造の内容にさらに便利になります。皆さんもぜひサポートしていただければと思います。 次に、次の章ではファイル管理の内容について説明します。一度覚えたら、アドレス帳を更新できます。

おすすめ

転載: blog.csdn.net/qq_63319459/article/details/128695300