# 1.5 字符输入输出

### 1.5.1 字符输入输出 <a href="#j7scy" id="j7scy"></a>

主要讨论 getchar() 和 putchar()

在实际的小程序中去学习这些规则，掌握规则很重要，然后去理解规则是怎么定义的，这是一个循序渐进的过程。

Exercise 1-7. Write a program to print the value of EoF.

{% code title="1.5.1 EOF.c" lineNumbers="true" %}

```c
# include <stdio.h>
int main()
{
    printf("EOF is %d\n", EOF);
    return 0;
}
```

{% endcode %}

<figure><img src="https://labspc.com/wp-content/uploads/2024/01/1705654589-word-image-260-1.png" alt=""><figcaption></figcaption></figure>

增加程序可移植性，EOF 的值的多少和具体环境也有关系，这里显示我这是 `-1`.

在这里我们要编写三个实用程序：

Exercise 1-8. Write a program to count blanks, tabs, and newlines. 统计

{% code title="1.5.2 count-nb-nt-nl.c" lineNumbers="true" %}

```c
#include <stdio.h>

int main()
{
    int c, nl, nb, nt;
    nl = 0;
    nb = 0;
    nt = 0;
    while ((c = getchar()) != EOF)
    {
        if (c == '\n')
            ++nl;
        else if (c == ' ')
            ++nb;
        else if (c == '\t')
            ++nt;
    }
    printf("nl = %d, nb = %d, nt = %d\n", nl, nb, nt);
    return 0;
}
```

{% endcode %}

Exercise 1-9. Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank. 将输入复制到输出，并将其中连续到多个空格用一个空格代替。

{% code title="1.5.3 getline-copy.c" lineNumbers="true" %}

```c
#include <stdio.h>

#define NONEBLANK 'a'

int main() 
{
    // 定义变量c和last
    int c, last;
    // 将last赋值为NONEBLANK
    last = NONEBLANK;
    // 循环读取字符
    while ((c = getchar()) != EOF)
    {
        // 如果当前字符不是空格
        if (c != ' ')
            // 将当前字符打印出来
            putchar(c);
        // 如果当前字符是空格
        else if (last != ' ')
            // 将当前字符打印出来
            putchar(c);
        // 将当前字符赋值给last
        last = c;
    }
    // 返回0
    return 0;
}
```

{% endcode %}

这个程序中间有几步，其实我还不是不太懂。 第二个 if 在处理多个空格的时候？

Exercise 1-10. Write a program to copy its input to its output, replacing each tab by t , each backspace by \ b , and each backslash by \ 1 . This makes tabs and backspaces visible in an unambiguous way. 用可见的方式打印出来

{% code title="1.5.4 visible.c" lineNumbers="true" %}

```c
#include <stdio.h>

int main()
{
    int c;
    while ((c = getchar()) != EOF)
    {
        if (c == '\t')
        {
            printf("\\t");
        }
        else if (c == '\b')
        {
            printf("\\b");
        }
        else if (c == '\\')
        {
            printf("\\\\");
        }
        else
        {
            putchar(c);
        }
    }
    return 0;
}
```

{% endcode %}

UNIX 中 wc 程序主体：

统计行数、单词数、字符数

state 变量记录当前程序是否处于一个单词之中，默认是“OUT”不在之中。

{% code title="1.5.5 unix-wc.c" lineNumbers="true" %}

```c
#include <stdio.h>

#define IN 1
#define OUT 0

int main() 
{
    //Declare variables to store the number of newlines, words, and characters
    int c, nl, nw, nc, state;
    //Initialize the state to OUT
    state = OUT;
    //Initialize the values of nl, nw, and nc to 0
    nl = nw = nc = 0;
    //Read each character from the input
    while ((c = getchar()) != EOF) 
    {
        //Increment the number of characters
        ++nc;
        //If the character is a newline, increment the number of newlines
        if (c == '\n') 
        {
            ++nl;
        }
        //If the character is a space, newline, or tab, set the state to OUT
        if (c == ' ' || c == '\n' || c == '\t') 
        {
            state = OUT;
        }
        //Otherwise, if the state is OUT, set the state to IN and increment the number of words
        else if (state == OUT) 
        {
            state = IN;
            ++nw;
        }
    }
    //Print the number of newlines, words, and characters
    printf("%d %d %d\n", nl, nw, nc);
    return 0;
}
```

{% endcode %}

```
if (c == ' ' || c == '\n' || c == '\t') 
```

逻辑或 OR，从左至右求值；这一点要和赋值操作区分开。

### 1.5.2 格式说明符 <a href="#pwfpu" id="pwfpu"></a>

format specifiers 是一个用于格式化输出的概念，它们指示在输出文本时如何处理和显示不同类型的数据。它们告诉格式化输出函数（如 printf）应该在输出中的哪个位置插入相应类型的数据，并如何表示这些数据。这是一个关于格式规则的指令。来标记变量应该在输出中的哪个位置出现，以及它们应该以何种方式呈现。格式指示符以 % 开头，后跟一个字符，表示数据类型，例如 %d 表示整数，%f 表示浮点数，%s 表示字符串，等等。

* %d：用于格式化和打印整数。示例：`printf("%d", 42);`
* %f：用于格式化和打印浮点数（小数）。示例：`printf("%f", 3.14159);`
* %c：用于格式化和打印单个字符。示例：`printf("%c", 'A');`
* %s：用于格式化和打印字符串（字符数组）。示例：`printf("%s", "Hello, World!");`
* %x：用于以十六进制（base 16）格式格式化和打印整数。示例：`printf("%x", 255);`（输出 "ff"）
* %o：用于以八进制（base 8）格式格式化和打印整数。示例：`printf("%o", 63);`（输出 "77"）
* %u：用于格式化和打印无符号整数。示例：`printf("%u", 123);`
* %p：用于格式化和打印指针（内存地址）。示例：`printf("%p", &variable);`
* %ld：用于格式化和打印长整数。示例：`printf("%ld", 1000000000L);`
* %lu：用于格式化和打印无符号长整数。示例：`printf("%lu", 4294967295UL);`
* %lld：用于格式化和打印长长整数。示例：`printf("%lld", 9000000000000000000LL);`
* %llu：用于格式化和打印无符号长长整数。示例：`printf("%llu", 18446744073709551615ULL);`

这些是C语言中用于不同数据类型的常用格式说明符。当你将这些格式说明符与诸如 `printf` 或 `scanf` 之类的函数一起使用时，它们指定了相应数据应该如何格式化或读取。\ <br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://labspc.gitbook.io/cnippets/chap1.-dao-yan/1.5-zi-fu-shu-ru-shu-chu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
