这是realloc()的正确用法吗?

时间:2018-12-31 13:26:57

标签: c malloc stdin realloc

我希望能够让用户输入他们想要做的事情。会有其他选择,但现在我正在研究“插入”。其他两个选项将是“搜索”和“删除”。

int main() {

    char *input = malloc(sizeof(char) * 6);
    printf("%s", "WELCOME TO USER'S SKIP LIST!\n\nWhat do you wish to do? ");
    scanf("%6s", input);
    if (strcmp(input, "insert") == 0) {
        printf("%s", "What is the item? ");
        input = realloc(input, (size_t)scanf("%s", input));
    }
}

我最初为input分配了足够的内存以包含6个字符。这是因为其他两个选项也只能包含6个字符。输入insert后,他们将必须输入一个可以包含任意数量字符的项目,因此我想根据他们输入的项目为input重新分配内存。因此,如果他们输入Nintendo Switch,则将重新分配15个字符。我对realloc()的实现是否是这样做的正确方法?

2 个答案:

答案 0 :(得分:5)

我想你主要是在问这个问题:

    input = realloc(input, (size_t)scanf("%s", input));

否,这不是realloc()中正确的 使用 。仅此行至少存在四个不同的问题,包括:

  • scanf()返回成功扫描和记录的输入项目数,如果发生错误,则返回EOF。 “输入项”对应于字段指令,例如您的%s,因此特定的scanf()调用将永远不会返回大于1的值。但是,它可能会返回0或EOF (通常为-1)。

  • 即使scanf()确实返回读取的字符数,

    • 任何重新分配都为时已晚。数据通过scanf()存储到提供的空间中,如果空间不够大,则其边界将在重新分配任何机会之前超出范围。

    • 没有为字符串终止符保留空间。

    • realloc()可能会失败,在这种情况下它将返回NULL。即使您通过在input之后检查realloc()来进行检查,您也将不再有指向原始空间的指针,因此它会泄漏。

答案 1 :(得分:4)

仔细阅读 scanfmallocrealloc 的文档,因此请多次阅读。您也可以参考C11标准n1570提及它们(在§7.22.3中)。

  

这是realloc()的正确实现吗?

您不是实施 realloc 。这是它的笑话实现(另请参见malloc的{​​{3}}笑话实现):

void *realloc(void*ptr, size_t siz) {
  errno = ENOMEM;
  return NULL;
}

当然,您实际上会使用realloc serious 实现(不是上面的笑话),它是由您的this实现提供的(例如,在{{3以上) }}原语或C standard library,例如Linux上的operating system

所以,不,您没有realloc实现(并且您会使用已在C语言中实现的realloc标准库)。并且(至少在Linux上)您可以研究realloc的实现,因为它通常是在某个system calls内部实现的(例如mmap(2)或GNU free software)。 musl-libc(在其文件src/malloc/malloc.c第369行中)是musl-libc的{​​{1}}实现。

您错误地使用 realloc

然后,您将glibc用作realloc。但是scanf("%s", input)失败时返回scanf,成功时返回成功输入值的数量。通常EOF为-1。因此,在您的情况下,EOF可以返回-1(失败时),0(如果未处理任何输入值)或1(如果它在scanf("%s", input)中放了东西)。

Here类型是某些 unsigned 整数类型。在我的Linux / x86-64系统上,它是一个无符号的64位数字,与input相同。因此unsigned long成为一个巨大的数字,即2 64 -1。然后(size_t)(-1)肯定会失败(因为我的系统没有那么多内存),如果给定realloc,那么(size_t)(-1)应该给realloc(input, (size_t)-1)

如果给NULL给了realloc,则在Linux上记录了它(请参阅scanf)以执行(size_t)0的作用:释放给定的内存。但是C标准不需要这种行为。

如果给free realloc,是否(至少允许)收缩存储区(仅保留一个字节,这对于您的需求)。

所以您的程序完全错误

顺便说一句,您需要处理(size_t)1的失败,因此对realloc进行编码非常幼稚。

此外,您的input = realloc(input, newsize);是错误的(对于正好六个字节的输入,可能是size_t),因为您需要空格来结尾 NUL 字符。

因此,将程序扔到垃圾桶中。休息一下(或找点乐子)。阅读标准函数的文档(以及realloc(3)的Wikipage)。想一想。然后完全重写您的程序。

然后使用所有警告和调试信息编译程序:scanf("%6s", input);buffer overflow。改进您的代码,不发出任何警告。确保您的程序处理失败的情况(gcc -Wall -Wextra -gscanfmalloc等)。阅读C dynamic memory allocation。使用GCCHow to debug small programs。成为gdb debugger中的valgrind

对于您的程序(从头开始重写的程序),您可能有兴趣使用scared(甚至在Linux上是undefined behaviorfgets ...)进行输入。有时您可能需要在进行实际输入之前用getline(3)清除输入缓冲区。

请注意,readline(3)已被缓冲,realloc通常是行缓冲的。因此,请养成以stdout结束memset格式的字符串或适当使用stdio的习惯。

PS。 \n在Linux上是printf(在Windows上不是),这是使Linux成为对开发人员和学生友好的操作系统的众多原因之一。因此,我建议您使用一些fflush来学习C编程。