c-这是realloc()的正确用法吗



我希望能够让用户输入他们想要做的事情。还有其他选项,但目前我正在处理"插入"。另外两个选项是"搜索"one_answers"删除"。

int main() {
char *input = malloc(sizeof(char) * 6);
printf("%s", "WELCOME TO USER'S SKIP LIST!nnWhat 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()的实现是正确的方法吗?

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

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

否,这不是realloc()的正确使用。仅这条线路就至少有四个明显的问题,包括:

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

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

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

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

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

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

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

您不是在实现realloc。以下是它的一个笑话实现(另请参阅malloc的这个笑话实现):

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

当然,您实际上会使用realloc严重实现(而不是上面的笑话),它是由您的C标准库实现提供的(例如,上面的操作系统原语或Linux上的系统调用,如mmap(2))。

因此,不,您没有realloc的任何实现(并且您将使用已经在C标准库中实现的realloc)。(至少在Linux上)你可以研究realloc的实现,因为它通常是在一些自由软件(例如musl-libc或GNUglibc)中实现的。这里(在其文件src/malloc/malloc.c的第369行)是reallocmusl-libc实现。

您错误地使用realloc

然后,您将使用scanf作为scanf("%s", input)。但scanf在失败时返回EOF,在成功时返回成功输入值的数目。通常EOF为-1。因此,在您的情况下,scanf("%s", input)可以返回-1(失败时)、0(如果没有处理输入值)或1(如果它在input中放入了一些东西)。

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

如果realloc被赋予(size_t)0,那么它在Linux上被记录下来(请参阅realloc(3)),以执行free所做的事情:释放给定的内存。但C标准并不要求这种行为。

如果realloc被赋予(size_t)1,则If将(或至少被允许)收缩内存区域(仅容纳一个字节,这不足以满足您的需求)。

所以你的程序是完全错误的

顺便说一句,你需要处理realloc的故障,所以编码input = realloc(input, newsize);是非常幼稚的。

此外,您的scanf("%6s", input);是错误的(对于正好六个字节的输入,可能会出现缓冲区溢出),因为您需要终止NUL字符的空间。

因此,将您的程序扔进垃圾桶休息一下(或找点乐子)。阅读标准函数的文档(以及C动态内存分配的Wiki页面)。想一想。并且完全重写您的程序

然后用GCC编译带有所有警告和调试信息的程序:gcc -Wall -Wextra -g。改进您的代码以避免出现任何警告。确保您的程序处理(scanfmallocrealloc等的)故障情况。阅读如何调试小程序。使用gdb调试器和valgrind。害怕不明确的行为。

对于您的程序(您从头开始重写的程序),您可能有兴趣使用fgets(甚至在Linux上,使用getline(3)或readline(3…)用于输入。有时,您可能希望在进行实际输入之前使用memset清除输入缓冲区。

请注意,stdio是缓冲的,stdout通常是行缓冲的。因此,养成以n结束printf格式字符串的习惯,或者适当地使用fflush

PS。valgrind在Linux上可用(但在Windows上不可用),这也是使Linux成为一个非常适合开发人员和学生使用的操作系统的众多原因之一。因此,我建议使用一些Linux发行版来学习C编程。

相关内容

  • 没有找到相关文章