[英]Ways for reading inputs in C without reading newline or using scanf
我有一个大学练习要做,包括用 C 编写一个银行,我知道scanf
是一个非常有问题的函数,并且fgets
读取'\n'
,我真的不想被阅读。 所以我写了新的函数来解决这个问题:
char *readstr(char *buff, size_t bytes) {
char *ptr;
for (ptr = buff;
(*ptr = getchar()) != '\n' && *ptr != EOF && ptr - buff < bytes - 1;
ptr++)
;
int c = *ptr;
*ptr = '\0';
if (c != EOF && c != '\n') {
while ((c = getchar()) != '\n' && c != EOF)
;
}
return buff;
}
int readint() {
char buffer[256] = "";
readstr(buffer, 256);
return atoi(strpbrk(buffer, "0123456789"));
}
double readfloat() {
char buffer[256] = "";
readstr(buffer, 256);
return atof(strpbrk(buffer, "0123456789"));
}
char readchar() {
char buffer[2] = "";
readstr(buffer, 2);
return *buffer;
}
直到现在,我写了这些。 有什么建议或建议吗? 一个更优雅或更简单的解决方案? 显然他们工作,但我不知道这是否是最好的方法。
scanf 不是错误的,只是很难正确使用。
无论如何,您可以使用 fgets 并手动删除换行符。 一种方法是使用strcspn
函数,如下所示:
fgets(str, size, stdin);
str[strcspn(str, "\n")] = 0;
您的目标似乎是将一行输入读入具有给定大小的缓冲区,而不是存储尾随换行符并丢弃该行上存在的任何多余字符。 您确实需要读取换行符,以便它不会在输入流中逗留,但您不想像fgets()
那样将其存储到目标数组中。
请注意,这可以通过scanf()
以这种方式实现:'
char buf[100] = "";
if (scanf("%99[^\n]", buf) == EOF) {
// handle end of file
} else {
// line was read into buf or empty line was detected and buf was not modified
scanf("%*[^\n]"); // consume extra bytes on the line if any
scanf("%*1[\n]"); // consume the newline if present
}
这非常麻烦,如果缓冲区大小是可变值,情况会变得更糟。 正如许多精明的 C 程序员所指出的, scanf
不是错误的,只是很难正确使用。 我什至会说它的语义令人困惑且容易出错,但它可以安全地使用,不像gets()
,它已从 C 标准的最新版本中删除,因为任何任意长输入都可能导致未定义的行为。
可以使用fgets()
读取一行并丢弃尾随换行符,但结合读取行、丢弃额外字节和使用换行符作为单独的函数可能很有用。
你的代码有问题:
您将getchar()
的返回值直接存储到char
数组中,消除了EOF
和具有签名字符的体系结构上的 char 值'\377'
之间的区别,而*ptr != EOF
在char
无符号的体系结构上永远不会匹配默认。 您必须将其存储到一个int
变量中。
无法判断是否到达文件末尾:该函数在文件末尾返回一个空字符串,就像它对流中的空白行所做的那样
缓冲区大小不能为零。
无法检测到截断:您可以返回整行所需的字符数和文件末尾的-1,而不是返回目标数组。
调用atoi(strpbrk(buffer, "0123456789"))
会带来多个问题: strpbrk
可以返回一个空指针,导致未定义的行为,它会跳过一个前导符号,并且对于表示int
类型超出范围的值的内容, atoi
没有完全定义.
这是修改后的版本:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int readstr(char *buff, size_t bytes) {
size_t pos = 0;
int c;
while ((c = getchar()) != EOF && c != '\n') {
if (pos + 1 < bytes)
buff[pos] = (char)c;
pos++;
}
if (size > 0) {
if (pos < size)
buff[pos] = '\0';
else
buff[size - 1] = '\0';
}
if (c == EOF && pos == 0)
return -1;
return (int)pos;
}
int readint(void) {
char buffer[256];
long n;
if (readstr(buffer, sizeof buffer) < 0)
return -1;
n = strtol(buffer, NULL, 0);
#if LONG_MIN < INT_MIN
if (n < INT_MIN) {
errno = ERANGE;
return INT_MIN;
}
#endif
#if LONG_MAX > INT_MAX
if (n > INT_MAX) {
errno = ERANGE;
return INT_MAX;
}
#endif
return (int)n;
}
double readdouble(void) {
char buffer[256];
if (readstr(buffer, sizeof buffer) < 0)
return NAN;
else
return strtod(buffer, NULL);
}
int readchar(void) {
char buffer[2] = "";
if (readstr(buffer, sizeof buffer) < 0)
return EOF;
else
return (unsigned char)*buffer;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.