我有一个字符串数组
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
答案 0 :(得分:1)
您的算法在两个重要方面被破坏
**tab = ...
是错误的。如果tab
是char**
,则*tab
将是char*
,而**tab
将是char
。为char
分配一个内存地址应该标记出来自工具链的巨大警告,如果它没有提高警告级别或获得新的工具链。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
取消引用tab
到tab
中存储的第一个字符串中的第一个字符,这不是您想要的。尝试以下方法:
tab=realloc(tab,(i+2)*sizeof(char*));
如果您打开编译器警告,则它们应该捕获这种类型的错误。