【问题标题】:Issue in understanding the following program理解以下程序的问题
【发布时间】:2020-08-08 21:13:03
【问题描述】:
#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;
}

此程序输入一个字符串,并为中间的每个空格插入一个换行符,因此每个单词都打印在新行中。

我想知道这个 for 循环和 fgets 函数是如何工作的。

【问题讨论】:

    标签: c string enums character fgets


    【解决方案1】:

    strspnstrcspn 都返回accept 集合中的连续字符数,或者不包含由delim 中的字符组成的reject 集合——space、@987654329 @、newline(见man 3 strspn)。 for 循环将指针 p 推进,该指针指向 s 中的一个字符,以有效地跳过空白,然后计算下一个非空白字符序列的长度。然后从fgets 填充的缓冲区中打印非空白字符序列(n 字符),从p 指向的字符开始。

    试一试,输入以下内容并查看打印的内容。

        my       dog     has                 fleas
    

    "%*.*s\n"的解释见man 3 printfformat-string

    至于for 循环本身的构造,for 循环只是一个形式为for (init clause; test clause; increment clause) 的循环——这三个循环中的任何一个都可以为空。例如for (;;) 只是不断循环。

    在您的情况下,s1001 字符的缓冲区,由fgets() 读取stdin 上的用户输入填充。循环:

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

    将常量字符指针p初始化为第一个字符s*p 的测试只是 *p != '\0' 的简写(不是在标记字符串末尾的 *nul 字符处)。没有增量子句,因为指针p 在循环内通过:

        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 */
    

    简而言之就是这样。

    【讨论】:

      【解决方案2】:
      enum { N = 1001 };
      char s[N] = "";
      
      fgets( s, sizeof( s ), stdin );
      

      fgets() 读取一个字符串,直到遇到换行符 \n(不仅仅是空格 () 或制表符 (\t),或者如果要写入的元素数量超过了。

      s 衰减为指向chars 数组的指针。 sizeof(s) 将给出s 中的元素数量,显然是N,也就是1001stdin 是标准输入流。


      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 循环内被修改。

      p 被取消引用,意味着它将被评估为字符p 实际指向的对象。循环一直持续到p 指向s 中字符串的空字符。

          const char *delim  = " \t\n";
      
          ....
      
          p += strspn( p, delim );
      

      p 将在delim 指向的字符串中提供的空白字符数增加,在s 中第一次出现任何其他(可读)字符之前。

          int n = strcspn( p, delim );
      

      n 将获取在delim 指向的字符串中提供的任何空白字符第一次出现之前读取的s 中的字符数。

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

      如果n 非零(表示在下一个空白字符之前是否有任何数量的非空白字符要打印),printf() 将打印一系列连续的非空白字符(一个实际单词)包含在s 中,p 指向它。如果字符串包含多个单词,则每个单词将单独打印在显式行中,在 for 循环的不同迭代中完成。

      % 之后的第一个 * 指定由n 提供的最小字段宽度(应打印多少个字符)。如果p实际上指向一个比n少元素的字符序列,那么左边的空格会被空格填充。

      .* 指定精度(p 指向的字符序列中实际打印了多少个字符。

          p += n;
      

      p 将增加 s 在第一次出现任何空白字符之前读取的字符数。

      循环条件将证明*p 是否实际上指向\0,然后计算结果为0,循环将停止。否则它会在循环中再次迭代。

      【讨论】:

        猜你喜欢
        • 2011-01-20
        • 1970-01-01
        • 1970-01-01
        • 2014-02-03
        • 2017-10-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-07
        相关资源
        最近更新 更多