C言語による動的メモリ管理。C 言語には、メモリの割り当てと管理のためのいくつかの関数が用意されています。これらの関数は、 <stdlib.h>ヘッダー ファイルにあります。
C 言語では、メモリはポインタ変数によって管理されます。ポインタは、整数、浮動小数点数、文字、配列などの任意のデータ型の変数を指すことができるメモリ アドレスを格納する変数です。C 言語には、プログラマが割り当て、解放、移動、コピーなどのメモリ操作を可能にするいくつかの関数と演算子が用意されています。
注: void * 型は、型なしのポインターを表します。C および C++ では、型変換を通じて void * 型を他の任意の型のポインターに変換できると規定しています。
動的にメモリを割り当てる
プログラミングするとき、配列のサイズが事前にわかっていると、配列を定義するのが簡単になります。たとえば、人の名前を格納する配列は最大 100 文字を保持できるため、次のように配列を定義できます。
char name[100];
ただし、保存する必要があるテキストの長さが事前にわからない場合 (たとえば、トピックに関する詳細な説明を保存したい場合)。ここでは、以下に示すように、必要なメモリ サイズが定義されていない文字を指すポインタを定義し、需要に応じてメモリを割り当てる必要があります。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char name[100];
char *description;
strcpy(name, "Zara Ali");
/* 动态分配内存 */
description = (char *)malloc( 200 * sizeof(char) );
if( description == NULL )
{
fprintf(stderr, "Error - unable to allocate required memory\n");
}
else
{
strcpy( description, "Zara ali a DPS student in class 10th");
}
printf("Name = %s\n", name );
printf("Description: %s\n", description );
}
上記のコードをコンパイルして実行すると、次の結果が生成されます。
Name = Zara Ali
Description: Zara ali a DPS student in class 10th
上記のプログラムは、以下に示すように、calloc()を使用して作成することもできます。 malloc を calloc に置き換えるだけです。
calloc(200, sizeof(char));
メモリを動的に割り当てる場合は、完全に制御でき、任意のサイズの値を渡すことができます。また、サイズが事前に定義されている配列は、一度定義するとサイズを変更できません。
サイズを変更してメモリを解放する
プログラムが終了すると、オペレーティング システムはプログラムに割り当てられたすべてのメモリを自動的に解放しますが、メモリが必要ない場合は関数free()を呼び出してメモリを解放することをお勧めします。
あるいは、関数realloc()を呼び出して、割り当てられたメモリ ブロックのサイズを増減することもできます。realloc() 関数と free() 関数を使用して上記の例をもう一度見てみましょう。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char name[100];
char *description;
strcpy(name, "Zara Ali");
/* 动态分配内存 */
description = (char *)malloc( 30 * sizeof(char) );
if( description == NULL )
{
fprintf(stderr, "Error - unable to allocate required memory\n");
}
else
{
strcpy( description, "Zara ali a DPS student.");
}
/* 假设您想要存储更大的描述信息 */
description = (char *) realloc( description, 100 * sizeof(char) );
if( description == NULL )
{
fprintf(stderr, "Error - unable to allocate required memory\n");
}
else
{
strcat( description, "She is in class 10th");
}
printf("Name = %s\n", name );
printf("Description: %s\n", description );
/* 使用 free() 函数释放内存 */
free(description);
}
上記のコードをコンパイルして実行すると、次の結果が生成されます。
Name = Zara Ali
Description: Zara ali a DPS student.She is in class 10th
追加のメモリを再割り当てせずに試すことができます。説明を保存するのに十分なメモリがないため、strcat() 関数はエラーを生成します。
C 言語でよく使用されるメモリ管理関数と演算子
-
malloc() 関数: メモリを動的に割り当てるために使用されます。これは、割り当てられるメモリのサイズ (バイト単位) を 1 つのパラメータとして受け取り、割り当てられたメモリへのポインタを返します。
-
free() 関数: 以前に割り当てられたメモリを解放するために使用されます。引数として解放されるメモリへのポインタを受け取り、そのメモリを未使用としてマークします。
-
calloc() 関数: メモリを動的に割り当て、ゼロに初期化するために使用されます。これは、割り当てるメモリ ブロックの数と各メモリ ブロックのサイズ (バイト単位) の 2 つのパラメータを受け取り、割り当てられたメモリへのポインタを返します。
-
realloc() 関数: メモリの再割り当てに使用されます。これは、以前に割り当てられたポインターと新しいメモリ サイズの 2 つの引数を受け取り、以前に割り当てられたメモリ ブロックのサイズを変更しようとします。調整が成功した場合は再割り当てされたメモリへのポインタを返し、それ以外の場合は null ポインタを返します。
-
sizeof 演算子: データ型または変数のサイズ (バイト単位) を取得するために使用されます。
-
ポインタ演算子: ポインタが指すメモリ アドレスまたは変数の値を取得するために使用されます。
-
& 演算子: 変数のメモリ アドレスを取得するために使用されます。
-
* 演算子: ポインタが指す変数の値を取得するために使用されます。
-
-> 演算子: 構造体メンバーへのポインター アクセスに使用されます。構文は pointer->member で、(*pointer).member と同等です。
-
memcpy() 関数: ソース メモリ領域からターゲット メモリ領域にデータをコピーするために使用されます。コピー先のメモリ領域へのポインタ、コピー元のメモリ領域へのポインタ、およびコピーされるデータのサイズ (バイト単位) の 3 つのパラメータを取ります。
-
memmove() 関数: memcpy() 関数に似ていますが、重複するメモリ領域を処理できます。コピー先のメモリ領域へのポインタ、コピー元のメモリ領域へのポインタ、およびコピーされるデータのサイズ (バイト単位) の 3 つのパラメータを取ります。
malloc と calloc に本質的な違いはなく、malloc 後の未初期化メモリは memset で初期化できます。
主な違いは、malloc は割り当てられたメモリを初期化しないのに対し、calloc は割り当てられたメモリをゼロに初期化することです。
小さな違いは、calloc は配列を返すのに対し、malloc はオブジェクトを返すことです。
Calloc は malloc に等しいため、次に memset に等しいため、malloc は calloc より効率的です。
メモリ空間を割り当てるための関数 malloc の呼び出し形式: (型指定子 *) malloc (サイズ)。
メモリ空間の割り当て関数 calloc calloc は、メモリ空間の割り当てにも使用されます。
なぜ malloc を多く使用し、calloc をほとんど使用しないのでしょうか?
calloc がメモリを初期化しているため (すべて 0 に初期化されています)、
calloc は次と同等です
p = malloc();
memset(p, 0,size);
malloc と比較すると、メモリにゼロを書き込む操作が多く、ゼロを書き込む必要がある場合もありますが、ほとんどの場合は書きません。