【问题标题】:scanf is not waiting for input within my loop?scanf 没有在我的循环中等待输入?
【发布时间】:2012-08-15 00:09:33
【问题描述】:

我是 Objective-C 的新手,这确实是我的第一个交互式程序。我已经学习了大约 2 周了。

所以,我的问题是:通常我注意到,当您连续有多个 scanf 时,它们每个都在等待输入 - 但是在这种情况下,我要求提供帐户所有者姓名和余额 - 它触发两个 NSLog 函数,而不是等待第一个输入。

这是我的主要内容:

int main(int argc, char* argV[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    bank *columbiaBank = [[bank alloc] init];

    int iteration = 0;
    while (true) {
        int selection = 0;
        NSLog(@"\n1. Add Account \n2. Remove Account \n3. Modify Account \nWhat would you like to do?:");
        scanf("%i", &selection);

        if (selection == 1) {

            NSLog(@"\nEnter account owner:");
            char accountOwner;
            scanf("%c", &accountOwner);

            NSLog(@"\nEnter opening balance:");
            float openingBalance;
            scanf("%f", &openingBalance);

            // create and add new account
            bankAccount *newAccount = [[bankAccount alloc] initWithProps:[NSString stringWithFormat:@"%c", accountOwner] :[NSString stringWithFormat:@"%i", iteration] :openingBalance];
            [columbiaBank addAccount:newAccount];
            [newAccount release];
            NSLog(@"\nAccount successfully added!");

       } else if (selection == 2) {

            NSLog(@"\nEnter account id:");
            int accountId;
            scanf("%i", &accountId);
            // remove account
            [columbiaBank removeAccount:[NSString stringWithFormat:@"%i", accountId]];
            NSLog(@"\nAccount successfully removed!");

        } else if (selection == 3) {

            NSLog(@"\nThe bank currently has %i accounts.", columbiaBank.totalAccounts);
            NSLog(@"\nThe bank's current balance from all accounts is $%f", columbiaBank.totalBankBalance);
            NSLog(@"\n-- Output of all account info --");
            [columbiaBank printAccounts];

        } else {

            NSLog(@"You did not enter a valid action.");

        }
        iteration++;
    }

    [columbiaBank release];
    [pool drain];
    return false;
}

【问题讨论】:

标签: objective-c c scanf foundation


【解决方案1】:

大概您希望帐户所有者名称不止一个字符,但您只读取了 scanf 中的单个字符。如果您尝试在那里输入多个字符,第一个 scanf 将读取第一个字符,并且由于输入缓冲区中有更多字符,下一个 scanf 将尝试立即读取而不等待您的数字输入.如果您使用单个字符作为所有者名称,那么您将需要使用输入缓冲区中的换行符。

如果您想读取一个字符串作为帐户所有者名称,您需要为多个字符分配空间,并使用%s 而不是%c 作为您的scanf 格式字符串。还记得检查scanf 的返回值。该函数将返回成功扫描的项目数,如果没有扫描任何项目,则返回 0,通常是由于输入无效,或者返回 EOF

char accountOwner[26];

// ...

// note that you can specify a width (max length) for a string using scanf
scanfReturn = scanf("%25s", accountOwner);

【讨论】:

  • 确保将NAME_MAXLEN - 1 指定为scanf 可以读取的最大字符数,例如如果NAME_MAXLEN 是16,scanf("%15s", accountOwner"); 顺便说一句,记住effects of whitespace in a format specifier... 格式字符串中的任何单个空白字符都会消耗输入中所有可用的连续空白字符
  • @veer 对,谢谢,如果帐户所有者是 firstname lastname,那就有问题了。
  • 试试scanf("%15[a-zA-Z ]s") :-)
【解决方案2】:

其他用户已经说了一切。 scanf 会在缓冲区中自动插入一个新行“\n”,然后传递给下一个 scanf。这是因为任何未写入的数据都会写入下一个流中。

我想补充一点,你可以使用fflush来清除流缓冲区,这种情况下你要使用

scanf("%i", &selection);
fflush(stdin)

在每个scanf 之后清除stdin(控制台输入)的缓冲区。

编辑:我不知道,但正如@Peter Kowalski 所说,应避免将 fflush(stdin) 用于输入流,因为它对输入流具有未定义的行为。

Cprograming.com FAQ > Why fflush(stdin) is wrong.

但似乎没有保证在 C 中刷新输入流的方法。

Cprograming.com FAQ > Flush the input stream

我知道在 C++ 中,标准方法是在 cin >> selection 之后使用 cin.ignore(),但我不知道如何在 C 中做到这一点。也许一些更有经验的用户可以对 @ 发生的事情提供一些见解987654329@.

【讨论】:

  • 我听说非常不推荐使用 fflush 作为输入缓冲区。我说的对吗?
【解决方案3】:

*[注意:如果您打算使用 Objective-C,您可能希望使用来自 Cocoa 的输入转换方法,而不是混合使用 Cocoa (NSLog) 和 stdio (scanf)。但这并不能回答您的问题...]

在解析整数、浮点数甚至字符串时,scanf 会跳过空格 - 例如空格、制表符、行尾等 - 每个输入行至少以行尾结束(可能是回车、换行或两者都取决于系统)。这意味着在读取您的第一个整数之后,至少在输入中仍然存在行尾,并且尝试读取字符将返回它 - 因此无需等待输入。要丢弃剩余的未使用的输入,您可以使用fpurge。例如:

#include <stdio.h>

int main(int argc, char* argV[])
{
    int selection = 0;
    fputs("\n1. Add Account \n2. Remove Account \n3. Modify Account \nWhat would you like to do?: ", stdout);
    scanf("%i", &selection);

    if (selection == 1)
    {

        fputs("\nEnter account owner: ", stdout);
        fpurge(stdin); // skip any input left in the buffer as %c takes the very next character and does not skip whitespace
        char accountOwner;
        scanf("%c", &accountOwner);

        fputs("\nEnter opening balance: ", stdout);
        float openingBalance;
        scanf("%f", &openingBalance);

        printf("%c - %f\n", accountOwner, openingBalance);
    }
}

请注意,读取字符串确实会跳过空格,因此如果您的帐户所有者是字符串,则不需要fpurge

【讨论】:

    猜你喜欢
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2012-10-13
    • 2013-12-30
    相关资源
    最近更新 更多