Проблема в понимании следующей программы - PullRequest
0 голосов
/ 25 апреля 2020
#include <stdio.h>
#include <string.h>

int main(void) 
{
    enum { N = 1001 };

    char s[N] = "";

    fgets( s, sizeof( s ), stdin );

    const char *delim  = " \t\n";

    for ( const char *p = s; *p; )
    {
        p += strspn( p, delim );

        int n = strcspn( p, delim );

        if ( n ) printf( "%*.*s\n", n, n, p );

        p += n;
    }

    return 0;
}

Эта программа вводит строку и для каждого пробела между ними вставляет символ новой строки, из-за которого каждое слово печатается в новой строке.

Я хочу знать, как это для l oop и функция fgets работает.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2020
enum { N = 1001 };
char s[N] = "";

fgets( s, sizeof( s ), stdin );

fgets() читает строку, пока не встретит новую строку \n (не просто пробел () или табуляцию (\t) или если число элементов для записи будет превышено.

s распадается на указатель на массив char s. sizeof(s) даст количество элементов в s, по-видимому N, что составляет 1001. stdin - стандартный поток ввода.


for ( const char *p = s; *p; )
{
    p += strspn( p, delim );

    int n = strcspn( p, delim );

    if ( n ) printf( "%*.*s\n", n, n, p );

    p += n;
}

p - указатель на const char, здесь s, что означает s, рассматриваемый как строка или иным образом любые элементы его нельзя изменить внутри for l oop.

p получить разыменованный, означает, что он будет оценен до фактического символа p до. l oop продолжается до тех пор, пока p не будет указывать на нулевой символ строки внутри s.

    const char *delim  = " \t\n";

    ....

    p += strspn( p, delim );

p будет увеличиваться на количество символов пробела, как указано в строке, указывающей delim до, до первого появления любых других (читаемых) символов в s.

    int n = strcspn( p, delim );

n будет получить количество символов в s, прочитанном до первого появления любых пробельных символов, как указано в строке, на которую указывает delim.

    if ( n ) printf( "%*.*s\n", n, n, p );

Если n не равен нулю (означает если есть какое-либо количество непробельных символов, которые нужно напечатать перед следующим символом пробела), printf() напечатает последовательность последовательных непробельных символов (фактическое слово), содержащуюся в s, к которой p указывает на. Если строка содержит несколько слов, то каждое слово будет напечатано отдельно в явной строке, выполненной в разных итерациях for l oop.

Первый * после % указывает минимальное поле ширина (сколько символов должно быть напечатано), которая предоставляется n. Если p фактически указывает на последовательность символов, состоящую из меньшего числа элементов, чем n, левый пробел будет заполнен пробелами.

.* указывает точность (Сколько символов в последовательности символов указано на p фактически напечатаны.

    p += n;

p будет увеличен на количество символов в s, прочитанных до первого появления любого из символов пробела.

Условие l oop докажет, если *p фактически указывает на \0, что затем оценивается в 0, и l oop остановится. Иначе оно повторяется в другой раз через l oop.

0 голосов
/ 25 апреля 2020

И strspn, и strcspn возвращают количество последовательных символов в наборе accept или не содержат набор reject, состоящий из символов в delim - space, tab, newline (см. man 3 strspn ). for l oop продвигает указатель p, который указывает на символ в s, чтобы эффективно пропускать пробелы и затем считать длину следующей последовательности непробельных символов. Последовательность непробельных символов (n символов) затем печатается из буфера, заполненного fgets, начиная с символа, на который указывает p.

Попробуйте, введите следующее и посмотрите, что напечатано.

    my       dog     has                 fleas

(см. man 3 printf для объяснения "%*.*s\n" format-string )

Что касается конструкции for l oop, a for l oop - это просто al oop с формой for (init clause; test clause; increment clause) - любой из 3 может быть пустым. Например, for (;;) просто циклически повторяется.

В вашем случае s - это буфер 1001 символов, который заполняется fgets() чтением пользовательского ввода в stdin. The l oop:

for ( const char *p = s; *p; )

Инициализирует указатель константного символа p на первый символ s. Тест *p - это просто сокращение для *p != '\0' (не в символе * nul, отмечающем конец строки). Нет никакого предложения увеличения, потому что указатель p продвигается в l oop на:

    p += strspn( p, delim );       /* advance p by the number of sequential whitespace chars */

и

    p += n;                        /* advance p by the number of non-whitespace chars printed */

Это в значительной степени это в двух словах.

...