13

配列に動的メモリ割り当てを使用するにはどうすればよいですか?

たとえば、次の配列では、.txt ファイルから個々の単語を読み取り、単語ごとに配列に保存しています。

コード:

char words[1000][15];

ここで、1000 は配列が保存できる単語数を定義し、各単語は 15 文字以下で構成できます。

ここで、そのプログラムがカウントする単語数に対してメモリを動的に割り当てる必要があることを望みます。たとえば、.txt ファイルには 1000 を超える単語が含まれている場合があります。ここで、プログラムで単語数をカウントし、それに応じてメモリを割り当てる必要があります。

[1000] の代わりに変数を使用することはできないため、ロジックを実装する方法については完全に空白です。この点で私を助けてください。

4

8 に答える 8

25

ポインターを使用します。

具体的には、アドレスへのポインターを使用し、標準の C ライブラリ関数呼び出しを使用して、必要なものを格納できるようにヒープを拡張するようオペレーティング システムに要求します。

今、それはあなたが処理する必要があることを拒否するかもしれません.

次の質問は、2D 配列をどのように求めるかということです。さて、ポインタの配列を要求してから、各ポインタを展開します。

例として、これを考えてみましょう:

int i = 0;
char** words;
words = malloc((num_words)*sizeof(char*));

if ( words == NULL )
{
    /* we have a problem */
    printf("Error: out of memory.\n");
    return;
}

for ( i=0; i<num_words; i++ )
{
    words[i] = malloc((word_size+1)*sizeof(char));
    if ( words[i] == NULL )
    {
        /* problem */
        break;
    }
}

if ( i != num_words )
{
    /* it didn't allocate */
}

これにより、2 次元配列が得られます。各要素words[i]は、単語数と同様に、実行時に決定可能な異なるサイズを持つことができます。

free()配列を使い終わったら、配列をループして結果のメモリをすべて取得する必要があります。

for ( i = 0; i < num_words; i++ )
{
    free(words[i]);
}

free(words);

そうしないと、メモリ リークが発生します。

を使用することもできますcalloc。違いは、呼び出し規則と効果にあります-callocすべてのメモリを初期化しますが、そうでは0ありmallocません。

実行時にサイズを変更する必要がある場合は、realloc.


また、重要なのは、私が使用した word_size+1 に注意してください。C の文字列は 0 で終了するため、考慮する必要がある余分な文字が必要です。これを確実に覚えておくために、私は通常、変数word_sizeのサイズを単語のサイズ (期待どおりの文字列の長さ) に設定し、0 の malloc に +1 を明示的に残します。次に、割り当てられたバッファーが文字列を取ることができることを知っていますword_size。これをしなくても問題ありません - 私は明らかな方法でゼロを明示的に説明したいので、そうしています。

このアプローチにはマイナス面もあります。これは、最近出荷されたバグであることがはっきりとわかりました。私が書いたことに注意して(word_size+1)*sizeof(type)ください - しかし、私が書いたことを想像してみてくださいword_size*sizeof(type)+1sizeof(type)=1これらは同じものですが、Windows はwchar_t非常に頻繁に使用します。この場合、最後の 0 に対して 2 バイトではなく 1 バイトを予約します。これらは、単一の 0 バイトではなく、型の 0 で終了する要素ですtype。これは、読み取りと書き込みでオーバーランすることを意味します。  

補遺: 好きな方法で実行してください。バッファーに依存するものにバッファーを渡す場合は、ゼロターミネーターに注意してください。

于 2011-01-09T20:18:57.977 に答える
7

ナインフィンガーズはポインターの配列を使用して回答を提供しましたが、内部配列のサイズが定数式である限り、配列の配列を使用することもできます。このコードはより単純です。

char (*words)[15]; // 'words' is pointer to char[15]
words = malloc (num_words * sizeof(char[15]);

// to access character i of word w
words[w][i];

free(words);
于 2011-01-09T20:26:03.873 に答える
1

C++ を使用する場合、STL は何かの動的割り当てに非常に役立ち、非常に簡単です。std::vector .. を使用できます。

于 2011-01-09T20:13:39.960 に答える
1

C で作業している場合:

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

#define WORD_LEN 15

int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent)
{
  int result = 1;
  char (*tmp)[WORD_LEN] = realloc(*wordList, 
                                 (*currentSize + extent) * sizeof **wordList);
  if (tmp)
  {
    *currentSize += extent;
    *wordList = tmp;
  }
  else
    result = 0;

  return result;
}

int main(void)
{
  char *data[] = {"This", "is", "a", "test", 
                  "of", "the", "Emergency", 
                  "Broadcast", "System", NULL};
  size_t i = 0, j;
  char (*words)[WORD_LEN] = NULL;
  size_t currentSize = 0;

  for (i = 0; data[i] != NULL; i++)
  {
    if (currentSize <= i)
    {
      if (!resizeArray(&words, &currentSize, 5))
      {
        fprintf(stderr, "Could not resize words\n");
        break;
      }
    }
    strcpy(words[i], data[i]);
  }

  printf("current array size: %lu\n", (unsigned long) currentSize);
  printf("copied %lu words\n", (unsigned long) i);

  for (j = 0; j < i; j++)
  {
    printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]);
  }

  free(words);

  return 0;
}
于 2011-01-09T21:34:34.080 に答える
1

あなた15の例が変数である場合は、利用可能な回答の1つを使用してください(NinefingersまたはJohn BokerまたはMuggenから)。1000変数の場合は、次を使用しreallocます。

words = malloc(1000 * sizeof(char*));
// ... read 1000 words
if (++num_words > 1000)
{
    char** more_words = realloc(words, 2000 * sizeof(char*));
    if (more_words) {printf("Too bad");}
    else {words = more_words;}
}

上記のコードでは、定数2000は簡略化されています。capacity2000 語以上をサポートするには、別の変数を追加する必要があります。

if (++num_words > capacity)
{
    // ... realloc
    ++capacity; // will reallocate 1000+ words each time; will be very slow
    // capacity += 1000; // less reallocations, some memory wasted
    // capacity *= 2; // less reallocations but more memory wasted
}
于 2011-01-09T20:38:04.603 に答える
0

最新の C (C99) では、次のような可変長配列、VLA という追加の選択肢があります。

char myWord[N];

原則として、このようなことは 2 次元でも行うことができますが、サイズが大きくなりすぎると、スタック オーバーフローのリスクが生じる可能性があります。あなたの場合、最も簡単な方法は、そのような配列へのポインターを使用し、malloc/reallocを使用してそれらのサイズを変更することです。

typedef char Word[wordlen];
size_t m = 100000;

Word* words = malloc(m * sizeof(Word));
/* initialize words[0]... words[m-1] here */
for (size_t i = 0; i < m; ++i) words[i][0] = '\0';

/* array is too small? */
m *= 2;
void *p = realloc(words, m*sizeof(Word));
if (p) words = p;
else {
 /* error handling */
}
.
free(words);

wordlenすべてを 1 つの関数内に保持する限り、このコードは定数または変数の場合に機能するはずです (モジュロ タイプミス) 。関数に配置したい場合は、関数を次のように宣言する必要があります

void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]);

つまり、長さパラメータは、 の宣言で認識されるために最初に来なければなりませんwords

于 2011-01-09T21:07:52.663 に答える
0

以下は、2 次元配列の動的割り当てに関する情報です。

http://www.eskimo.com/~scs/cclass/int/sx9b.html

于 2011-01-09T20:15:30.177 に答える
0
char ** words = malloc( 1000 * sizeof(char *));
int i;
for( i = 0 ; i < 1000 ; i++)
     *(words+i) = malloc(sizeof(char) * 15);

//....
for( i = 0 ; i < 1000 ; i++)
     free(*(words+i));

free(words);
于 2011-01-09T20:17:27.243 に答える