将元素添加到字符串数组

时间:2018-11-12 19:16:40

标签: c arrays string malloc

我有一个字符串数组

char **tab;

,我希望它能够随着用户输入新字符串而增加。我创建了以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
    char **tab=malloc(sizeof(char*));
    tab[0]=malloc(41*sizeof(char));
    int i=0;
    int d=0;
    while(strcmp(tab[i],"END"))
    {
        if(d==0)
        {
            i--;
            d++;
        }
        i++;
        scanf("%s",tab[i]);
        **tab=realloc(tab,(i+2)*sizeof(char*));
        tab[i+1]=malloc(41*sizeof(char));
    }
    return 0;
}

它的目的是读取新的字符串到制表符,直到用户输入关键字“ END”为止。由于不知道将输入多少个单词,因此我尝试在每次迭代后重新分配数组的大小。不幸的是,它在得到3个单词后会显示细分错误。 我做错了什么?有没有更好的方法来完成此任务?

任何单词的最大长度为40

2 个答案:

答案 0 :(得分:1)

您的算法在两个重要方面被破坏

    循环主体中的
  • **tab = ...是错误的。如果tabchar**,则*tab将是char*,而**tab将是char。为char分配一个内存地址应该标记出来自工具链的巨大警告,如果它没有提高警告级别或获得新的工具链。
  • 您的while条件的初始输入将评估不确定数据。那时您已经为tab[0]分配了原始内存,但是还没有填充它。因此,您的程序将调用未定义的行为

除上述内容外,扩展算法并不复杂,在编写任何代码之前,向您的rubber-duck进行解释将大有帮助。这样做时,您会看到为每个新读取重新分配指针数组既昂贵又效率低下。几何扩展算法使这一点变得更好。另外,它可以解决上述两个问题。

代码

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

#define MAX_BUFLEN  41
#define MAX_STR_FMT "%40s"

int main()
{
    char **tab = NULL;
    size_t size = 0, capacity = 0;

    char str[MAX_BUFLEN];

    while (scanf(MAX_STR_FMT, str) == 1 && strcmp(str, "END"))
    {
        // check for expansion 
        if (size == capacity)
        {
            size_t new_capacity = 2 * capacity + 1;
            void *tmp = realloc(tab, new_capacity * sizeof *tab);
            if (tmp == NULL)
            {
                perror("Failed to expand dynamic table");
                break;
            }

            // save expanded table, and update capacity
            tab = tmp;
            capacity = new_capacity;
        }

        size_t slen = strlen(str)+1;
        if ((tab[size] = malloc(slen)) == NULL)
        {
            perror("Failed to allocate buffer for new string");
            break;
        }

        // copy incoming string; update 'size' to reflect new count
        memcpy(tab[size++], str, slen);
    }

    //
    // TODO: use 'tab' holding 'size' pointers. 
    //

    // then free the table
    while (size-- > 0)
        free(tab[size]);
    free(tab);

    return 0;
}

替代:没有指针

如果您的需求确实需要固定长度的分配(如代码所示),则根本不需要指针的指针(除非对于诸如交换指针的排序这样的工作有一些隐藏的议程) 比交换完整的字符串缓冲区更有效。

代码

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

#define MAX_BUFLEN  41
#define MAX_STR_FMT "%40s"

int main()
{
    char (*tab)[MAX_BUFLEN] = NULL; // see difference here
    size_t size = 0, capacity = 0;

    char str[MAX_BUFLEN];

    while (scanf(MAX_STR_FMT, str) == 1 && strcmp(str, "END"))
    {
        // check for expansion 
        if (size == capacity)
        {
            size_t new_capacity = 2 * capacity + 1;
            void *tmp = realloc(tab, new_capacity * sizeof *tab);
            if (tmp == NULL)
            {
                perror("Failed to expand dynamic table");
                break;
            }

            // save expanded table, and update capacity
            tab = tmp;
            capacity = new_capacity;
        }

        // notice no additional allocations here
        strcpy(tab[size++], str);
    }

    //
    // TODO: use 'tab' holding 'size' strings. 
    //

    // then free the table
    free(tab);

    return 0;
}

摘要

修复代码非常简单,但是也要使其更好。在制定算法时,请不要停止思考为什么为什么,并且花大量时间与rubber-duck进行交流。

答案 1 :(得分:0)

问题出在这一行:

**tab=realloc(tab,(i+2)*sizeof(char*));

此处**tab取消引用tabtab中存储的第一个字符串中的第一个字符,这不是您想要的。尝试以下方法:

tab=realloc(tab,(i+2)*sizeof(char*));

如果您打开编译器警告,则它们应该捕获这种类型的错误。