我希望能够让用户输入他们想要做的事情。会有其他选择,但现在我正在研究“插入”。其他两个选项将是“搜索”和“删除”。
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()
的实现是否是这样做的正确方法?
答案 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)
仔细阅读 scanf
,malloc
,realloc
的文档,因此请多次阅读。您也可以参考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 -g
,scanf
,malloc
等)。阅读C dynamic memory allocation。使用GCC和How to debug small programs。成为gdb
debugger中的valgrind。
对于您的程序(从头开始重写的程序),您可能有兴趣使用scared(甚至在Linux上是undefined behavior或fgets ...)进行输入。有时您可能需要在进行实际输入之前用getline(3)清除输入缓冲区。
请注意,readline(3)已被缓冲,realloc
通常是行缓冲的。因此,请养成以stdout
结束memset格式的字符串或适当使用stdio的习惯。
PS。 \n
在Linux上是printf
(在Windows上不是),这是使Linux成为对开发人员和学生友好的操作系统的众多原因之一。因此,我建议您使用一些fflush
来学习C编程。