web-dev-qa-db-ja.com

Cでのmalloc()の便利な例は何ですか?

Cのmalloc()について読んでいます。

ウィキペディアの記事 を提供しますが、_int array[10]_と比較して10intの配列に十分なメモリを割り当てるだけです。あまり役に立ちません。

いつメモリを処理するCでmalloc()を使用することにしましたか?

14
alex

動的データ構造(リスト、ツリーなど)は、mallocを使用してノードをヒープに割り当てます。例えば:

/* A singly-linked list node, holding data and pointer to next node */
struct slnode_t
{
    struct slnode_t* next;
    int data;
};

typedef struct slnode_t slnode;

/* Allocate a new node with the given data and next pointer */
slnode* sl_new_node(int data, slnode* next)
{
    slnode* node = malloc(sizeof *node);
    node->data = data;
    node->next = next;
    return node;
}

/* Insert the given data at the front of the list specified by a 
** pointer to the head node
*/
void sl_insert_front(slnode** head, int data)
{
    slnode* node = sl_new_node(data, *head);
    *head = node;
}

sl_insert_frontを使用して新しいデータをリストに追加する方法を検討してください。データとリスト内の次のノードへのポインタを保持するノードを作成する必要があります。どこで作成しますか?

  • たぶんスタックに! -[〜#〜] no [〜#〜]-そのスタックスペースはどこに割り当てられますか?どの機能で?関数が終了するとどうなりますか?
  • たぶん静的メモリに! --[〜#〜] no [〜#〜]-プログラムのロード時にスタティックメモリが事前に割り当てられているため、リストノードの数を事前に知る必要があります。
  • ヒープ上? [〜#〜] yes [〜#〜]-必要な柔軟性がすべて揃っているためです。

mallocはCで使用され、ヒープにデータを割り当てます。これは、実行時に動的に拡大および縮小できるメモリスペースであり、その所有権は完全にプログラマーの制御下にあります。これが役立つ例は他にもたくさんありますが、ここで示しているのは代表的な例です。最終的に、複雑なCプログラムでは、プログラムのデータのほとんどがヒープ上にあり、ポインターを介してアクセスできることがわかります。正しいプログラムは、どのポインタがデータを「所有」しているかを常に認識しており、割り当てられたメモリが不要になったときに注意深くクリーンアップします。

19
Eli Bendersky

プログラムを作成するときに配列のサイズがわからない場合はどうなりますか?例として、画像をロードしたいと想像できます。最初はそのサイズがわからないため、ファイルからサイズを読み取り、このサイズのバッファーを割り当ててから、そのバッファー内のファイルを読み取る必要があります。明らかに、静的サイズの配列を使用することはできませんでした。

編集:

もう1つのポイントは、動的割り当てを使用する場合、メモリはヒープに割り当てられ、配列はスタックに割り当てられます。スタックはヒープと比較してサイズが制限される可能性があるため、組み込みデバイスでプログラミングする場合、これは非常に重要です。

4
Antoine Pelisse

グーグルすることをお勧めします スタックとヒープ

_int* heapArray = (int*)malloc(10 * sizeof(int));
int stackArray[10];
_

どちらも、データへのアクセス方法が非常に似ています。これらは、データが舞台裏で保存される方法が大きく異なります。 heapArrayはヒープに割り当てられ、アプリケーションが停止したとき、またはfree(heapArray)が呼び出されたときにのみ割り当てが解除されます。 stackArrayはスタックに割り当てられ、スタックが巻き戻されると割り当てが解除されます。

2
tidwall

あなたが説明した例ではint array[10]スタックフレームを離れると、消えます。使用済みメモリをローカルスコープを超えて存続させたい場合は、malloc()を使用する必要があります。

2
rerun

C99の時点で可変長配列を実行できますが、より動的なデータ構造に代わる適切な方法はありません。典型的な例はリンクリストです。任意のサイズを取得するには、mallocを使用してeachノードを割り当て、可変長配列の場合のように、大量のメモリをコピーせずに挿入および削除できるようにします。

たとえば、単純なリンクリストを使用した任意のサイズのスタック:

#include <stdio.h>
#include <stdlib.h>

typedef struct sNode {
    int payLoad;
    struct sNode *next;
} tNode;

void stkPush (tNode **stk, int val) {
    tNode *newNode = malloc (sizeof (tNode));
    if (newNode == NULL) return;
    newNode->payLoad = val;
    newNode->next = *stk;
    *stk = newNode;
}

int stkPop (tNode **stk) {
    tNode *oldNode;
    int val;
    if (*stk == NULL) return 0;
    oldNode = *stk;
    *stk = oldNode->next;
    val = oldNode->payLoad;
    free (oldNode);
    return val;
}

int main (void) {
    tNode *top = NULL;
    stkPush (&top, 42);
    printf ("%d\n", stkPop (&top));
    return 0;
}

さて、可変長配列でこれを行うのは可能ですが、COBOLでオペレーティングシステムを作成するのと同様に、より良い方法があります。

1
paxdiablo

malloc()は、次の場合に使用されます。

  1. 動的なメモリ割り当てが必要です
    サイズnの配列を作成する必要がある場合(nはプログラムの実行中に計算されます)、それを実行できる唯一の方法はmalloc()を使用することです。

  2. ヒープにメモリを割り当てる必要があります
    一部の関数で定義された変数は、この関数が終了するまでしか存続しません。したがって、「コールスタックに依存しない」データが必要な場合は、関数パラメーターとして渡すか返すか(常に適切であるとは限りません)、ヒープに格納する必要があります。データをヒープに格納する唯一の方法は、malloc()を使用することです。可変サイズの配列がありますが、それらはスタックに割り当てられます。

1
Kel