这里是你可能会解决这个问题的方法之一。如果要为未知数量的未知长度的单词动态分配存储空间,可以从看起来合理的buffSize
开始,为readLine
缓冲区分配足够的空间,并根据需要增大此内存量。同样,您可以根据需要为单词数量选择合理的大小,并根据需要增加单词存储量。
在下面的程序中,myArray
是指向指向char
的指针。 arrSize
被初始化,以便指向100个字的指针可以被存储在myArray
中。首先,readLine
填充了输入行。如果需要比初始分配提供的空间更多的空间,则存储器是两倍大的存储器。在阅读完该行后,内存再次被realloc
修剪为该行的大小(包括空间为'\0'
)。
strtok_r()
将行分解为令牌。指针store
用于保存分配用于保存该字的内存的地址,然后使用strcpy()
将word
复制到此内存中。如果需要更多空间来存储单词,myArray
指向的内存大小为realloc
,并且大小加倍。在所有单词已被存储后,myArray
是realloc
最后一次修剪到最小尺寸。
当进行这么多的分配时,最好编写分配内存和检查错误的函数,这样你就不必每次手动分配内存。 xmalloc()
需要一个size_t
参数和一个错误消息字符串。如果发生分配错误,则将信息打印到stderr
,程序退出。否则,返回指向分配内存的指针。同样,xrealloc()
需要一个指向要重新分配的内存的指针,一个size_t
参数和一个错误消息字符串。请注意,如果存在分配错误,realloc()
可返回NULL
指针,因此您需要将返回值分配给临时指针以避免内存泄漏。将realloc()
转换为单独的功能有助于保护您免受此问题的困扰。例如,如果直接将realloc()
的返回值分配给readLine
,并且如果存在分配错误,则readLine
将不再指向之前分配的内存,该内存将丢失。该功能打印错误消息,并在出现错误时退出。
此外,您需要free
所有这些内存分配,所以这是在程序退出之前完成的。
该方法比行内每个添加的字符的内存效率更高,并且对于每个添加的指针来说,该方法的效率都高于myArray
。凭借buffSize
和arrSize
的慷慨起始值,您可能只需要初始分配,然后将其调整为最终大小。当然,每个单词仍然有单独的分配。你也可以使用strdup()
作为这个部分,但是你仍然需要记住释放这些分配。但是,将不会需要分配readLine
和myArray
一个char
或一次一个指针。
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void * xmalloc(size_t size, char *msg);
void * xrealloc(void *ptr, size_t size, char *msg);
int main(void)
{
char **myArray;
size_t buffSize = 1000;
size_t arrSize = 100;
size_t charIndex = 0;
size_t wordIndex = 0;
char *readLine;
char *inLine;
char *word;
char *rest;
char *store;
/* Initial allocations */
readLine = xmalloc(buffSize, "Allocation error: readLine");
myArray = xmalloc(sizeof(*myArray) * arrSize,
"Allocation error: myArray\n");
/* Get user input */
printf("\n enter a line of input:\n");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
if (charIndex + 1 >= buffSize) { // keep room for '\0'
buffSize *= 2;
readLine = xrealloc(readLine, buffSize,
"Error in readLine realloc()\n");
}
readLine[charIndex++] = c;
}
readLine[charIndex] = '\0'; // add '\0' terminator
/* If you must, trim the allocation now */
readLine = xrealloc(readLine, strlen(readLine) + 1,
"Error in readLine trim\n");
/* Tokenize readLine */
inLine = readLine;
while((word = strtok_r(inLine, " \n", &rest)) != NULL) {
store = xmalloc(strlen(word) + 1, "Error in word allocation\n");
strcpy(store, word);
if (wordIndex >= arrSize) {
arrSize *= 2;
myArray = xrealloc(myArray, sizeof(*myArray) * arrSize,
"Error in myArray realloc()\n");
}
myArray[wordIndex] = store;
wordIndex++;
inLine = NULL;
}
/* You can trim this allocation, too */
myArray = xrealloc(myArray, sizeof(*myArray) * wordIndex,
"Error in myArray trim\n");
/* Print words */
for(size_t i = 0; i < wordIndex; i++){
printf("%s ",myArray[i]);
}
printf("\n");
/* Free allocated memory */
for (size_t i = 0; i < wordIndex; i++) {
free(myArray[i]);
}
free(myArray);
free(readLine);
return 0;
}
void * xmalloc(size_t size, char *msg)
{
void *temp = malloc(size);
if (temp == NULL) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
return temp;
}
void * xrealloc(void *ptr, size_t size, char *msg)
{
void *temp = realloc(ptr, size);
if (temp == NULL) {
fprintf(stderr, "%s\n", msg);
exit(EXIT_FAILURE);
}
return temp;
}
'getline()'不是标准C函数,虽然我相信它是Posix。最好使用'fgets()'来实现可移植性。 –
生病请记住,谢谢 – cmptUser
如果对非POSIX机器的便携性很重要,请使用 ['fgets()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fgets.html) POSIX没有定义['函数getline()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html)只要你记住释放它分配的内存是非常有用的。 –