【问题标题】:time using gap between while(scanf("%d",&n)!=EOF) and while(scanf("%d",&n) && n!=EOF)使用 while(scanf("%d",&n)!=EOF) 和 while(scanf("%d",&n) && n!=EOF) 之间的间隔的时间
【发布时间】:2014-12-28 02:46:18
【问题描述】:

我的问题不是关于算法,而是关于 C 编程语言的一些令人困惑的问题。 我遇到了如下问题:

问题描述

N! (N 阶乘)对于较大的 N 值可能非常烦人且难以计算。因此,我不想计算 N!,而是想知道其中有多少位。 (记住 N!= N * (N - 1) * (N - 2) * ... * 2 * 1)

输入

输入的每一行都有一个整数 N 0

输出

对于 N 的每个值,打印出 N! 中有多少位数。

我的代码是这样的:

 #include<stdio.h>
 int main()
{
    int n ;
    while(scanf("%d",&n)&&n!=EOF)//1
    //while(scanf("%d",&n)!=EOF)//2
    {
        int result=1;
        int i;
        double temp = 1;
        for(i=n;i>0;i--)
        {
            temp*=i;
            while((temp/10)>1)
            {
                result++;
                temp=temp/10;
            }           
        }
        printf("%d\n",result);
    }
    return 0;
}

当我使用while(scanf("%d",&amp;n) &amp;&amp; n!=EOF)时,我使用的在线法官显示Time Limit Exceeded,当我将其更改为while(scanf("%d",&amp;n)!=EOF)时,一切顺利。我认为n!=EOF可能需要太多时间,所以什么是EOF的本质?

【问题讨论】:

  • EOF 定义为 -1 I.E. 0xFFFFFFFF 对于 32 位系统。但是,对 scanf 函数的调用存在几个问题:1) 代码应始终检查 scanf 的返回值以确保输入/转换成功 2) scanf 的返回值永远不会被 EOF,它会为 0 或更大。
  • 位数的计数很尴尬,而且位置不正确。只需要对 N! 的最终值执行“位数计数”。没有10!很快就超过了“int”持有的能力。建议使用“long long int”(64 位)(或者可能是“bignum”函数)。
  • @user3629249 1) EOF 未定义为-1。它肯定总是一个负的int 常数。 2)scanf("%d",&amp;n)的可能返回值为01EOF
  • 注意:使用for(i=n;i&gt;0;i--) { temp *= i; while(temp &gt;= 1.0e31) { result += 31; temp /= 1.0e31; } } while(temp &gt;= 10.0) { result++; temp /= 10.0;} printf("%d\n",result); 之类的代码可以运行得更快(更准确)。 31 被选为DBL_MAX 至少是 1.0e31 * 1,000,000

标签: c scanf eof


【解决方案1】:

不是两个句子的时间,是它们有不同的含义

下一个比较scanf读取的值和EOF,这是一个错误,scanf到达文件末尾时不会加载n中的任何值:

while(scanf("%d",&n) && n!=EOF)

这是检测文件结尾的正确方法:

while(scanf("%d",&n)!=EOF)

通常EOF == -1,因为判断中的输入不包含-1,您的程序无限期循环。

正如 cmets 中所述,检查 scanf 进行了多少次转换通常会更好,因为它检查输入是否或多或少有效 (*)。鉴于您在格式字符串(“%d”)中询问了 1 次转换,您可以检查 scanf 是否返回 1:

while(scanf("%d", &n) == 1)

(*) 如果必须遵循严格的格式(例如,如果数字后面必须紧跟一个 \n),可能无法验证某些情况,最好使用 strtol 进行转换,检查 strtol 是否使用了整行。

由于这个特殊问题来自使用在线评委的编程竞赛,因此输入格式正确,通常不需要此类测试。

【讨论】:

  • 请注意,如果输入格式错误并且在输入中包含诸如'=' 之类的字母或杂散标点符号,则检测EOF 将无济于事。正确的测试是 while (scanf("%s", &amp;n) == 1) 继续,而 scanf() 成功地将输入转换为 int 值。不过,在这两者中,scanf(…) != EOF 在输入受到合理控制的情况下更接近正确,如在线裁判操作中。
【解决方案2】:

这两种情况都不适合使用(但带有scanf("%d", &amp;n) != EOF 的情况更好)。

循环应该写成:

while (scanf("%d",&n) == 1)

因为您要求scanf转换1个值,而scanf的返回值是成功转换的项目数。

【讨论】:

    【解决方案3】:
    I would strongly suggest using the following code rather than 
    the illmannered scanf() function:
    
    #include<stdio.h>
    
    int main()
    {
        unsigned int n ;            // user input after conversion
        long long int result=0;     // maybe use uint64_t
        char inArray[100] = {'\0'}; // user input array
        int i;                      // loop counter
        int digitCount = 0;         // number of digits to display factorial value
    
        printf("\nwhen enter a number\n"); 
        printf(" then pgm will output factorial for that number\n");
        printf(" then number of digits in factorial value\n");
    
        printf("\n\nPlease enter first number: (or <ctrl-z> to exit)");
        while( NULL != fgets( inArray, sizeof(inArray), stdin )
        {
            n = (unsigned)atoi( inArray );
            if( 0 == n )      {result = 0;}
            else if( 1 == n ) {result = 1;}
            else if( 2 == n ) {result = 2;}
            else
            {
                result = n;
                for(i=(n-1);i>1;i--)
                {
                    result *= i;
                } // end calculate factorial
            } // end if
    
            printf("factorial value: %lld\n",result);
    
            // setup work area usage
            memset( inArray, 0x00, sizeof(inArray) );
            sprintf( inArray, "%lld", result );
    
            // calculate and display number of digits
            digitCount = strlen(inArray);
            printf("digit count: %d\n", digitCount );
    
            // clear work area and prompt for next input from user
            memset( inArray, 0x00, sizeof(inArray) );
            printf("\n\nPlease enter next number: (or <ctrl-z> to exit)");
        } // end while
    
        return 0;
    } // end function: main
    

    【讨论】:

      猜你喜欢
      • 2017-07-27
      • 2018-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-28
      • 2012-03-19
      • 1970-01-01
      • 2013-02-17
      相关资源
      最近更新 更多