【问题标题】:want to call fgets() multiple times based on users need想根据用户需要多次调用 fgets()
【发布时间】:2017-08-03 01:28:14
【问题描述】:

用户输入“1”或“0”选项以继续使用 fgets() 获取字符串。因此,当用户输入选项时,fgets 从控制台读取它。我将它存储在另一个变量中。但是 fgets 获得选择并将其存储在消息中。收到选择后,我尝试使用 fflush(stdin)。请帮帮我。

int main() {
    int choice=1;
    char *message;
    int i=0;
    while (choice == 1) {
        fflush(stdout);
        printf("Enter the message: ");
        fflush(stdout);
        message = fgets(message,200,stdin);
        while (message[i]!='\n') {
            i++;
        }
        message[i] = '\0';
        send_message(message);
        printf("\nType '1' to continue or '0' to quit: ");
        scanf("%d",&choice);
        fflush(stdin);
     }
 }

【问题讨论】:

  • fflush(stdin); 是未定义的行为。为什么不只是阅读换行符,然后一次又一次地阅读一行?或者,只需对所有内容使用 fgets 并解析 int。 stackoverflow.com/questions/2979209/using-fflushstdin
  • char *message; ... fgets(message,200,stdin); 将未初始化的message 传递给fgets()。您希望函数如何处理此类数据?
  • 告诉用户输入yn,然后尝试用"%d" 读取整数不会带来快乐。即使您没有,您的用户也会感到困惑。您的另一个主要问题似乎是scanf() leaves newlines behind
  • @JonathanLeffler 已编辑。谢谢!

标签: c string scanf fgets


【解决方案1】:

看起来您正试图通过scanf() 读取用户的输入——这本身就是危险的。 (见https://www.reddit.com/r/learnprogramming/comments/1d0w4x/c_scanf_d_but_error_if_user_enters_a_character/)。

我建议将%s 用于您的格式字符串,或者更好的是,构建一个子例程来进行安全输入并以老式方式对其进行解析,例如以下几行:

/* getsafe() - Generic input using the preferred input method rather than gets() */

#include <stdio.h>
#include <string.h>


char *getsafe(char *inpstr,int inpsiz) {
    char    *seachr;                    /* Result of search via strchr()     */

    if (inpstr==NULL) {
        return(NULL);
    }
    if (fgets(inpstr,inpsiz,stdin)==NULL) {
        return(NULL);
    }
    seachr=strchr(inpstr,'\n');
    if (seachr!=NULL) *seachr=0;

    return(inpstr);
}

这样,您可以指定缓冲区长度并提供足够长度的字符串(字符数组)以防止缓冲区溢出(安全问题),然后解析该数组中的 [0] 位置以获得答案。

#define ANSSIZ 80               /* Maximum allowed size of user answer    */
char usrans[ANSSIZ];            /* User Answer                            */
printf("Enter 'y' or 'n': ");
getsafe(usrans, ANSSIZ-1);

【讨论】:

  • 按要求添加。 ++chux 另外,我知道我会在getsafe()(如#define ANSSIZ 10240)抛出不合理的大缓冲区。被一个非常年轻的程序员嘲笑使用如此大的缓冲区并担心缓冲区溢出——以及他发布的代码到 FidoNet 成为攻击向量 LOL。
  • 不需要ANSSIZ-1 中的负1。
  • 我会相信你的话,但会在我停止练习之前通过栅栏测试进行验证。距离我写那个子程序已经很久很久了。
  • Perhasp "fgets 函数读取的字符数最多比n 指定的字符数少一个..." C11dr §7.21.7.2 2 可能会有所帮助。
  • 我喜欢#define ANSSIZ 10240 的故事。 IMO,用户输入是邪恶的,在经过审查之前不可信。
【解决方案2】:

这有很多问题 - 它可能属于Code Review

然而,这里是对一些主要问题的批评

int main() {
    int choice=1;
    char *message; // This is a pointer, but is not malloc'ed. You might want "char message[200]" instead?
    int i=0; // This is the only time "i" is set to 0. It needs to be reset at the start of the loop
    while (choice == 1) {
        fflush(stdout); // No need for this
        printf("Enter the message: ");
        fflush(stdout);
        message = fgets(message,200,stdin);
        while (message[i]!='\n') { // Why not use strlen?
            i++; // "i" can keep growing forever if there is no newline (if someone entered 199 characters before pressing enter)
        }
        message[i] = '\0'; // fgets does this for you - The past loop was pointless
        send_message(message);
        printf("\nType 'y' to continue or 'n' to quit: "); // You forgot to flush here!
        scanf("%d",&choice); // I don't think this will result in a 0 or 1 output... %d is for a digit, and you're asking the user for y or n.
        fflush(stdin); // This is invalid and unneeded - You can't flush stdin
    }
}

【讨论】:

    猜你喜欢
    • 2020-10-25
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 2021-11-22
    • 1970-01-01
    相关资源
    最近更新 更多