Чтобы понять% * d и если ((scanf ("% d", & n)! = 1) || (n <= 0)) в c - PullRequest
0 голосов
/ 28 апреля 2020

Я должен напечатать этот шаблон в 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" ??

Ответы [ 2 ]

2 голосов
/ 28 апреля 2020

Выражение 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 в качестве спецификатора формата.


Если вы заинтересованы в более кратком и структурированном решении, вы можете найти это полезным. Не используйте это, если это образовательная работа, поскольку есть намерение научиться делать это самостоятельно, но полезно увидеть другой подход.

Этот код исключает логику c для выполнения одной строки, печать достаточного количества элементов до go от максимального значения до одного, а затем повторное резервное копирование (но установка минимального значения для печати на основе строки).

Затем основной код просто печатает достаточно строк, так что середина значение каждой строки изменяется от максимума до единицы, а затем снова увеличивается (в основном те же логики c, которые использовались для каждой строки).

#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
1 голос
/ 28 апреля 2020

из C стандарта (7.21.6.4 функция scanf)

Возвращает

3 Функция scanf возвращает значение макроса EOF если сбой ввода происходит до того, как завершится первое преобразование (если оно есть). В противном случае функция scanf возвращает количество назначенных элементов ввода , которое может быть меньше предусмотренного или даже равно нулю в случае неудачного раннего сопоставления.

In это оператор if

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

подвыражение ( scanf( "%d", &n ) != 1 ) был ли успешным вызов scanf, то есть получила ли переменная n значение от пользователя. Если это так (то есть в случае успеха), то второе подвыражение ( n <= 0 ) проверяет, является ли введенное значение неположительным.

То есть, если либо вызов scanf не был успешным, либо пользователь выдает неположительное значение, элемент управления передается за время, пока l oop из-за оператора break. В результате программа завершает свое выполнение.

В этом вызове printf

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

спецификатор преобразования формата %*d указывает, что ширина выведенного поля (*) будет быть установлен в качестве аргумента вызова (width), а выражение value1 < value2 ? value2 : value1 выбирает максимальное значение между этими двумя значениями value1 и value2.

. Вы можете переписать этот вызов pf printf следующим образом путь

if ( value1 < value2 )
{
    printf( "%*d ", width, value2 );
}
else
{
    printf( "%*d ", width, value1 );
}
...