Q为什么大家都不建议使用scanf?我应该用什么来替代?
A scanf存在许多问题——请参阅第 12.17、12.18a 和 12.19 题。此外,它的%s格式存在和gets()同样的问题(参阅第 12.23 题)——很难保证接收缓冲区不会溢出。[脚注]
更普遍地说,scanf设计用于相对结构化、格式化的输入(其名称实际上源自“scan formatted”)。如果您留意,它会告诉您是否成功或失败,但它只能大概地告诉您失败的位置,而无法告知如何或为何失败。您几乎没有机会进行任何错误恢复。
然而,交互式用户输入是最不结构化的输入。一个设计良好的用户界面将允许用户键入几乎任何内容——不仅仅是在期望数字的地方键入字母或标点符号,还可能输入比预期的多或少字符,或者根本不输入任何字符(即只按 RETURN 键),或者提前遇到 EOF,或者任何其他情况。在使用scanf时,很难优雅地处理所有这些潜在问题;读取整个行(使用fgets或类似函数)然后对其进行解释要容易得多,可以使用sscanf或一些其他技术。(诸如strtol, 、strtok,而、atoi等函数通常很有用;另请参阅第 12.16 和 13.6 题。)如果您确实使用了任何scanf变体,请务必检查返回值,以确保找到了预期的项目数。另外,如果您使用%s,请务必防范缓冲区溢出。
顺便说一句,请注意,对scanf的批评不一定是对fscanf和sscanf. scanf从stdin读取的指责, stdin 通常是交互式键盘,因此受到的限制最少,导致问题最多。另一方面,当数据文件具有已知格式时,使用fscanf读取它可能是合适的。使用sscanf(只要检查了返回值),解析字符串是完全合适的,因为很容易重新获得控制、重新开始扫描、在不匹配时丢弃输入等。
额外链接
参考文献:K&R2 第 7.4 节,第 159 页