2017-02-03 91 views
1

任何提示我将如何动态分配myArray,这样我就可以输入任意数量的字符串,并且它可以正确存储。动态分配我的二维数组c

int main() 
{ 

char myArray[1][1]; //how to dynamically allocate the memory? 
counter = 0; 
char *readLine; 
char *word; 
char *rest; 

printf("\n enter: "); 
ssize_t buffSize = 0; 
getline(&readLine, &buffSize, stdin);//get user input 

//tokenize the strings 
while(word = strtok_r(readLine, " \n", &rest)) { 

      strcpy(myArray[counter], word); 
      counter++; 
      readLine= rest; 
} 

//print the elements user has entered 
int i =0; 
for(i = 0;i<counter;i++){ 
    printf("%s ",myArray[i]); 
} 
printf("\n"); 

} 
+0

'getline()'不是标准C函数,虽然我相信它是Posix。最好使用'fgets()'来实现可移植性。 –

+0

生病请记住,谢谢 – cmptUser

+0

如果对非POSIX机器的便携性很重要,请使用 ['fgets()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fgets.html) POSIX没有定义['函数getline()'](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getline.html)只要你记住释放它分配的内存是非常有用的。 –

回答

2

使用realloc的是这样的:

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

int main(void){ 
    char **myArray = NULL; 
    char *readLine = NULL; 
    size_t buffSize = 0; 
    size_t counter = 0; 
    char *word, *rest, *p; 

    printf("\n enter: "); 
    getline(&readLine, &buffSize, stdin); 
    p = readLine; 
    while(word = strtok_r(p, " \n", &rest)) { 
     myArray = realloc(myArray, (counter + 1) * sizeof(*myArray));//check omitted 
     myArray[counter++] = strdup(word); 
     p = NULL; 
    } 
    free(readLine); 
    for(int i = 0; i < counter; i++){ 
     printf("<%s> ", myArray[i]); 
     free(myArray[i]); 
    } 
    printf("\n"); 
    free(myArray); 
} 
0

我建议你先扫描数据,然后调用malloc()用适当的大小。 否则,您可以在遍历数据时使用realloc()重新分配内存。

+0

我如何扫描数据?即时通讯新的C – cmptUser

+0

请参考[这个答案](http://stackoverflow.com/questions/2496668/how-to-read-the-standard-input-into-string-variable-until-eof-in-c )以获得更详细的解释。 – Daniel

1

这里是你可能会解决这个问题的方法之一。如果要为未知数量的未知长度的单词动态分配存储空间,可以从看起来合理的buffSize开始,为readLine缓冲区分配足够的空间,并根据需要增大此内存量。同样,您可以根据需要为单词数量选择合理的大小,并根据需要增加单词存储量。

在下面的程序中,myArray是指向指向char的指针。 arrSize被初始化,以便指向100个字的指针可以被存储在myArray中。首先,readLine填充了输入行。如果需要比初始分配提供的空间更多的空间,则存储器是两倍大的存储器。在阅读完该行后,内存再次被realloc修剪为该行的大小(包括空间为'\0')。

strtok_r()将行分解为令牌。指针store用于保存分配用于保存该字的内存的地址,然后使用strcpy()word复制到此内存中。如果需要更多空间来存储单词,myArray指向的内存大小为realloc,并且大小加倍。在所有单词已被存储后,myArrayrealloc最后一次修剪到最小尺寸。

当进行这么多的分配时,最好编写分配内存和检查错误的函数,这样你就不必每次手动分配内存。 xmalloc()需要一个size_t参数和一个错误消息字符串。如果发生分配错误,则将信息打印到stderr,程序退出。否则,返回指向分配内存的指针。同样,xrealloc()需要一个指向要重新分配的内存的指针,一个size_t参数和一个错误消息字符串。请注意,如果存在分配错误,realloc()可返回NULL指针,因此您需要将返回值分配给临时指针以避免内存泄漏。将realloc()转换为单独的功能有助于保护您免受此问题的困扰。例如,如果直接将realloc()的返回值分配给readLine,并且如果存在分配错误,则readLine将不再指向之前分配的内存,该内存将丢失。该功能打印错误消息,并在出现错误时退出。

此外,您需要free所有这些内存分配,所以这是在程序退出之前完成的。

该方法比行内每个添加的字符的内存效率更高,并且对于每个添加的指针来说,该方法的效率都高于myArray。凭借buffSizearrSize的慷慨起始值,您可能只需要初始分配,然后将其调整为最终大小。当然,每个单词仍然有单独的分配。你也可以使用strdup()作为这个部分,但是你仍然需要记住释放这些分配。但是,将不会需要分配readLinemyArray一个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; 
} 
+0

非常好,完整的答案。我想添加(为了完整性),建议在执行内存分配后将结果转换为变量类型。所以;我会添加这个。店内=(字符*)的xmalloc(...) –

+1

@ J.Laderoute--在C++中必须转换,但它不是在C要求的其实很多人都认为它是最好避免铸造的malloc'的结果( )'和朋友。 [你可以阅读更多关于这里](http://stackoverflow.com/questions/953112/should-i-explicitly-cast-mallocs-return-value)。有些人对此表示强烈不满。我个人更喜欢不投射,但对每个他自己:)注意使用identifers而不是显式类型,例如'sizeof(* myArray)'而不是'sizeof(char *)'用'sizeof'运算符。我认为这更重要,因为它避免了错误,并且如果类型改变,它更易于维护。 –

+1

'inline = rest;':这取决于实现。它应该是'直列= NULL;' – BLUEPIXY