繁体   English   中英

在不读取换行符或使用 scanf 的情况下读取 C 中的输入的方法

[英]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 != EOFchar无符号的体系结构上永远不会匹配默认。 您必须将其存储到一个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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM