要了解%* d以及if((c中的scanf(“%d”,&n!!= 1)||(n <= 0))

问题描述 投票:-1回答:2

我必须在c中打印此图案

4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4

而且我发现与此相关的代码

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

int main()  
{ 
    while ( 1 ) 
    { 
        printf( "Enter a non-negative number (0 - exit): " ); 

        int n; 

        if ( ( scanf( "%d", &n ) != 1 ) || ( n <= 0 ) ) break; 

        if ( INT_MAX / 2 < n )  
        { 
            n = INT_MAX / 2; 
        } 

        int width = 1; 

        for ( int tmp = n; tmp /= 10; ) ++width; 

        putchar( '\n' ); 

        int m = 2 * n - 1; 

        for ( int i = 0; i < m; i++ ) 
        { 
            for ( int j = 0; j < m; j++ ) 
            {
                int value1 = abs( n - i - 1 ) + 1;
                int value2 = abs( n - j - 1 ) + 1;

                printf( "%*d ", width, value1 < value2 ? value2 : value1 );
            } 
            putchar( '\n' ); 
        } 

        putchar( '\n' ); 
    } 

    return 0; 
 }

我想知道为什么在此语句中使用scanf( "%d", &n ) != 1

if (( scanf( "%d", &n ) != 1 ) || ( n <= 0 ));

以及这里的单一格式说明符如何接受两个值

printf( "%*d ", width, value1 < value2 ? value2 : value1 );

为什么%和*一起使用"%*d" ??

c if-statement conditional-statements format-specifiers
2个回答
2
投票

[scanf("%d", &n)表达式将尝试读入n的整数,如果成功,将返回值1(实际上,它将返回成功读取的事物的数量,但是,因为您只是在问一方面,这是您将获得的最多回报)。如果失败,您还会得到其他东西。

因此,与1的比较是为了确保其有效。如果您没有获得1,则出了点问题。

语句printf( "%*d ", width, something)实际上与printf("%5d", something)紧密相关(它将打印一个至少五个字符宽的字段),但是使用变量5而不是固定的width

因此下面的两个printf调用是等效的:

int val = 42;
int wid = 5;
printf("%5d", val);
printf("%*d", wid, val);

由于在您提供的代码中width总是看起来像是1,所以我不确定为什么这样完成。在我看来,仅使用%d作为格式说明符会更容易。


如果您对更简洁,结构化的解决方案感兴趣,您可能会发现这很有帮助。如果这是教育工作,请不要使用它,因为这样做的目的是要自己学习,但是查看另一种方法会有所帮助。

[此代码排除了执行单行的逻辑,打印足够多的元素以从最大值减小到一个,然后再次备份(但设置一个最小值以根据该行打印)。

然后,主代码仅打印出足够多的行,以使每行的中间值从最大值减小到一,然后又再次返回(基本上与每行使用相同的逻辑)。

#include <stdio.h>

// Code to print out a single line, values going from max down to min then back up.

static void outLine(int max, int min) {
    for (int i = max; i > 0; i--) printf("%d ", i < min ? min : i);
    for (int i = 2; i <= max; i++) printf("%d ", i < min ? min : i);
    putchar('\n');
}

int main()  {
    while ( 1 ) {
        // Get the value, <1 means stop.

        int n;
        printf( "\nEnter a non-negative number (< 1 = exit): " );
        if ((scanf("%d", &n) != 1) || (n <= 0)) break;

        // Do each line, max down to 1 then back up.

        for (int i = n; i > 0; i--) outLine(n, i);
        for (int i = 2; i <= n; i++) outLine(n, i);
    }

    return 0;
}

成绩单是,按要求:

pax> ./testProg

Enter a non-negative number (< 1 = exit): 2
2 2 2
2 1 2
2 2 2

Enter a non-negative number (< 1 = exit): 3
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3

Enter a non-negative number (< 1 = exit): 4
4 4 4 4 4 4 4
4 3 3 3 3 3 4
4 3 2 2 2 3 4
4 3 2 1 2 3 4
4 3 2 2 2 3 4
4 3 3 3 3 3 4
4 4 4 4 4 4 4

Enter a non-negative number (< 1 = exit): -42

0
投票

来自C标准(7.21.6.4 scanf函数)

返回

3 scanf函数如果输入则返回宏EOF的值在第一次转换(如果有)完成之前发生故障。否则,scanf函数将返回分配的输入项目数,该数量可以小于或小于指定的输入项目数,甚至为零。早期匹配失败的事件。

在此if语句中

if (( scanf( "%d", &n ) != 1 ) || ( n <= 0 ));

子表达式( scanf( "%d", &n ) != 1 ),是否成功调用了scanf,也就是变量n是否从用户那里获得了值。如果是这样(在成功的情况下),则第二个子表达式( n <= 0 )检查输入的值是否为非正值。

即,如果scanf调用未成功或用户设置了非正值,则由于break语句,控件将传递到while循环之外。结果,程序完成了执行。

在printf的此调用中

printf( "%*d ", width, value1 < value2 ? value2 : value1 );

格式转换说明符%*d指定将输出字段(*)的宽度设置为调用(width)的自变量,表达式value1 < value2 ? value2 : value1在这两个值之间选择最大值value1value2

您可以通过以下方式重写该调用pf printf

if ( value1 < value2 )
{
    printf( "%*d ", width, value2 );
}
else
{
    printf( "%*d ", width, value1 );
}
© www.soinside.com 2019 - 2024. All rights reserved.