13

我应该如何为数组使用动态内存分配?

例如,这里是以下数组,我从 .txt 文件中读取单个单词并将它们逐字保存在数组中:

代码:

char words[1000][15];

这里 1000 定义了数组可以保存的单词数,每个单词可以包含不超过 15 个字符。

现在我希望该程序应该为它计算的字数动态分配内存。例如,一个 .txt 文件可能包含大于 1000 的单词。现在我希望程序应该计算单词的数量并相应地分配内存。

由于我们不能使用变量来代替 [1000],因此我对如何实现我的逻辑一无所知。请在这方面帮助我。

4

8 回答 8

25

你使用指针。

具体来说,您使用指向地址的指针,并使用标准 c 库函数调用,您要求操作系统扩展堆以允许您存储所需的内容。

现在,它可能会拒绝,您需要处理它。

下一个问题变成了——你如何要求一个二维数组?好吧,你要求一个指针数组,然后展开每个指针。

例如,考虑一下:

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 */
}

这将为您提供一个二维数组,其中每个元素words[i]可以具有不同的大小,可以在运行时确定,就像字数一样。

完成后,您将需要free()通过遍历数组来获取所有结果内存:

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

free(words);

如果不这样做,就会造成内存泄漏。

你也可以使用calloc. 不同之处在于调用约定和效果 -calloc将所有内存初始化为,0malloc没有。

如果您需要在运行时调整大小,请使用realloc.


另外,重要的是,请注意我使用的 word_size+1 。C 中的字符串以零结尾,这需要您考虑一个额外的字符。为了确保我记住这一点,我通常将变量word_size的大小设置为单词的大小(我期望的字符串长度),并明确地将 malloc 中的 +1 保留为零。然后我知道分配的缓冲区可以取一串word_size字符。不这样做也很好——我这样做是因为我喜欢以一种明显的方式明确地解释零。

这种方法也有一个缺点——我最近明确地将其视为一个已发布的错误。注意我写(word_size+1)*sizeof(type)的——想象一下我写的word_size*sizeof(type)+1。因为sizeof(type)=1这些是相同的,但 Windowswchar_t经常使用 - 在这种情况下,您将为最后一个零保留一个字节而不是两个 - 它们是 type 的以零结尾的元素type,而不是单个零字节。这意味着您将在读取和写入方面超出预期。  

附录:随心所欲地做,如果您要将缓冲区传递给依赖它们的东西,请注意那些零终止符。

于 2011-01-09T20:18:57.977 回答
7

虽然 Ninefingers使用指针数组提供了答案,但您也可以使用数组数组,只要内部数组的大小是常量表达式。用于此的代码更简单。

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

如果15您的示例中的 是可变的,请使用可用的答案之一(来自 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是一个简化;您应该添加另一个变量capacity以支持 2000 多个单词:

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 回答
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 回答
0

以下是有关动态分配二维数组的一些信息:

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 回答
0

在现代 C (C99) 中,您有一个额外的选择,可变长度数组,VLA,例如:

char myWord[N];

原则上你也可以在二维中做这样的事情,但是如果你的尺寸太大,你可能会冒堆栈溢出的风险。在您的情况下,最简单的方法是使用指向此类数组的指针并使用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只要您将所有内容都保存在一个函数中,此代码应该可以工作(模拼写错误)如果是常量或变量。如果你想把它放在一个函数中,你应该声明你的函数,比如

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

也就是说,对于 的声明,必须首先知道长度参数words

于 2011-01-09T21:07:52.663 回答