我应该如何为数组使用动态内存分配?
例如,这里是以下数组,其中我从.txt文件中读取单个单词并在数组中逐字保存:
代码:
char words[1000][15];
这里1000定义了数组可以保存的单词数,每个单词可以包含不超过15个字符。
现在我希望该程序应该为它计算的单词数量动态分配内存。例如,.txt文件可能包含大于1000的单词。现在我希望程序应该计算单词的数量并相应地分配内存。
由于我们不能使用变量代替[1000],因此我对如何实现逻辑完全空白。请帮助我。
答案 0 :(得分:22)
你使用指针。
具体来说,您使用指向地址的指针,并使用标准的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 */
}
这将为您提供一个二维数组,其中每个元素words[i]
可以具有不同的大小,在运行时可以确定,就像单词的数量一样。
完成后,你需要通过遍历数组来free()
所有结果内存:
for ( i = 0; i < num_words; i++ )
{
free(words[i]);
}
free(words);
如果不这样做,则会造成内存泄漏。
您也可以使用calloc
。不同之处在于调用约定和效果 - calloc
将所有内存初始化为0
,而malloc
则不会。{/ p>
如果您需要在运行时调整大小,请使用realloc
。
另外,重要的是,注意我使用过的word_size + 1 。 C中的字符串是零终止的,这需要额外的字符,您需要考虑。为了确保我记住这一点,我通常将变量word_size
的大小设置为单词大小应该是什么(字符串的长度如我所期望的那样)并明确地将malloc中的+1保留为零。然后我知道分配的缓冲区可以采用一串word_size
个字符。不这样做也没关系 - 我只是这样做,因为我喜欢以明显的方式明确地解释零。
此方法还有一个缺点 - 我最近明确将其视为已发布的错误。请注意我写了(word_size+1)*sizeof(type)
- 想象一下,我写了word_size*sizeof(type)+1
。对于sizeof(type)=1
,这些是相同的,但Windows非常频繁地使用wchar_t
- 在这种情况下,您将为最后一个零而不是两个保留一个字节 - 并且它们是类型为零的零终止元素{1}},而不是单个零字节。这意味着你将在读写时溢出。
补遗:无论你喜欢哪种方式,只要注意那些零终结符,如果你要将缓冲区传递给依赖它们的东西。
答案 1 :(得分:7)
虽然Ninefingers提供了an answer using an array of pointers ,但只要内部数组的大小是常量表达式,您也可以使用数组数组。这个代码更简单。
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);
答案 2 :(得分:1)
如果您打算使用C ++,STL对于动态分配非常有用,并且非常简单。你可以使用std :: vector ..
答案 3 :(得分: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
}
答案 4 :(得分: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, ¤tSize, 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;
}
答案 5 :(得分:0)
以下是有关动态分配2d数组的一些信息:
答案 6 :(得分: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);
答案 7 :(得分: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
的声明所知。