如何实现动态字符串矩阵?

时间:2016-01-17 09:35:21

标签: c malloc realloc

int i=0, ii=1, j, k, choose=0;
char q='a';
char **words = (char **)malloc(sizeof(char));
words[i] = (char *)malloc(sizeof(char)+1);

do {
    printf("you want again(0, 1)\n");
    scanf("%d", &choose);
    j = 0; k = 1;
    do {
        fflush(stdin);
        q = getchar();
        *words[j] = q;
        words[j] = (char *)realloc(words[j], (k+1) * sizeof(char));
        j++; k++;
    } while (q != '\n');
    *words[k] = '\0';
    i++; ii++;
    words = (char**)realloc(words ,ii*sizeof(char));
} while (choose);

puts("pRINT");
int d = 0, t = 0;
for (d = 0; d < i; d++) {
    printf("%s\n", words[d]);
}

我需要创建一个单词矩阵,但我不知道每个单词的大小以及会有多少单词。这就是我在每次迭代malloc开始和之后使用realloc (size+1)的原因,但是在第一次迭代之后,我得到了一个内存错误。我做错了什么,问题在哪里?

2 个答案:

答案 0 :(得分:2)

虽然您可以一次使用面向字符的输入读取和索引字符,但有更容易的方法来解决此问题。例如,使用面向行的输入函数(例如fgetsgetline),您可以一次读取/存储用户输入的整行数据。 / p>

getline的优点是可以分配足够的内存来保存用户输入的每个字符串(由您来强制执行任何长度的健全性检查)。但是,如果使用getline,则只需关注在达到初始指针数时重新分配。另外,正如评论中所提到的,没有理由realloc为每个输入(你可以,它只是相当低效)。您可以分配一些合理数量的指针,然后在达到该限制时仅分配realloc

以下是显示替代方案的简短示例。仔细看看,如果您有任何疑问,请告诉我。 (注意:)而不是在手动生成的EOF上停止循环,您只需检查是否nchr = 1并在用户只需按 Enter 没有输入数据。这取决于你。

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

#define NPTR 32

int main (void) {

    char *line = NULL;
    char **words = NULL;
    size_t i, n, idx = 0, nptr = NPTR;
    ssize_t nchr = 0;

    /* initially allocate NPTR pointers */
    if (!(words = malloc (sizeof *words * NPTR))) {
        fprintf (stderr, "error: virtual memory exhausted.\n");
        return 1;
    }

    printf ("\nEnter data [ctrl+d] ([crtl+z] on windows) to quit\n\n");

    while (printf (" input ") && (nchr = getline (&line, &n, stdin)) != -1) 
    {   /* for each line read */
        while (nchr && (line[nchr-1] == '\n' || line[nchr-1] == '\r'))
            line[--nchr] = 0;  /* strip newline or carriage rtn    */

        words[idx++] = strdup (line);

        if (idx == nptr) {  /* if limit reached -- realloc */
            void *tmp = realloc (words, 2 * nptr * sizeof *words);
            if (!tmp) {
                fprintf (stderr, "error: realloc - memory exhausted.\n");
                exit (EXIT_FAILURE);
            }
            words = tmp;
            nptr *= 2;
        }
    }
    free (line);

    printf ("\n\nInput provided by user:\n\n");
    for (i = 0; i < idx; i++)   /* print strings */
        printf (" words[%2zu] : %s\n", i, words[i]);
    putchar ('\n');

    for (i = 0; i < idx; i++)   /* free memory */
        free (words[i]);
    free (words);

    return 0;
}

<强>用法/输出

$ ./bin/getline_input

Enter data [ctrl+d] ([crtl+z] on windows) to quit

 input my
 input dog
 input has
 input fleas
 input

Input provided by user:

 words[ 0] : my
 words[ 1] : dog
 words[ 2] : has
 words[ 3] : fleas

当用户在空白行上按[Enter]

时退出

如上所述,完成输入后退出循环的另一种简单方法就是检查getline的返回值是否大于1。例如,您可以使用:

替换初始提示和条件
printf ("\nEnter data, ([Enter] on blank line to quit)\n\n");

while (printf (" input ") && (nchr = getline (&line, &n, stdin)) > 1)
{ ...

我觉得有时候会更方便。

答案 1 :(得分:0)

其中一个主要错误是:

char **words = (char **)malloc(sizeof(char));

words = (char**)realloc(words ,ii*sizeof(char));

您需要将其更改为

char **words = (char **)malloc(sizeof(char *));

words = (char**)realloc(words ,ii*sizeof(char *));

这是因为单词指向char *。

第二个问题是:

j = 0; k = 1;
do {
    fflush(stdin);
    q = getchar();
    *words[j] = q;
    words[j] = (char *)realloc(words[j], (k+1) * sizeof(char));
    j++; k++;
} while (q != '\n');
*words[k] = '\0';

你需要这样做:

j = 0;k = 1;
do {
    fflush(stdin);
    q = getchar();
    words[i][j] = q;
    j++; k++;
    words[i] = (char *)realloc(words[i], (k+1) * sizeof(char));
} while (q != '\n');
words[i][j] = '\0';