第1章 简介

 

1.5 字符输入和输出

如下两个输入和输出函数,是基础版本,它们可以以扩充出很多版本
int getchar(void)
int putchar(int char)

1.5.3 行统计

#include <stdio.h>
void main() {
    int ch, nl = 0;
    while ((ch = getchar()) != EOF)
        if (ch == '\n')
            ++nl;
    printf("nl = %d\n", nl);
}

个人理解,如果该行没有换行符,就EOF,应该算一行,修改如下

复制代码
#include <stdio.h>
void main() {
    int ch, nl = 1, cnt = 0;
    while ((ch = getchar()) != EOF) {
        if (ch == '\n') {
            nl++;
            cnt = 0;
         } else {
            cnt++;
        }
    }
    if (cnt == 0)
        nl--;
    printf("\nnl = %d\n", nl);
}
复制代码

1.5.4 单词计数

在1.5.4 单词计数中,梳理一下功能拆分的思路。几个小功能,分开处理,相互之间没有关联

练习题

练习 1_8  编写统计空格、制表符、换行符个数的程序

复制代码
#include <stdio.h>
void main() {
        int ch = 0;
        int n_blank = 0, n_tap = 0, n_enter = 0;
        while(EOF != (ch = getchar())) {
                if (' ' == ch)
                        n_blank++;
                else if ('\n' == ch)
                        n_enter++;
                else if ('\t' == ch)
                        n_tap++;
        }
        printf("n_blank=%d, n_tap=%d, n_enter=%d\n",
                n_blank, n_tap, n_enter);
}
复制代码

 练习1-9  编写一个程序,将输入复制到输出,并将其中多个连续的空格合并成一个。

复制代码
void main() {
    int ch = 0, c_last = 'a';  // c_last 的初始值不是空格字符就可以
    while(EOF != (ch = getchar())) {
        if (' ' != ch) {
            putchar(ch);
        } else if (' ' != c_last) {
            putchar(ch);
        }
        c_last = ch;
    }
}
然后可以通过 || 进行程序简化
void main() {
    int ch = 0, c_last = 'a';
    while(EOF != (ch = getchar())) {
        if (' ' != ch || ' ' != c_last) {
            putchar(ch);
        }
        c_last = ch;
    }
}
复制代码

上述处理是题解答案,可认为使用双指针分别保留了上一个字符和当前字符。而我的思路如下

复制代码
void main() {
    int ch = 0, flag = 0;
    while(EOF != (ch = getchar())) {
        if (' ' != ch) {
            putchar(ch);
            flag = 0;
        } else if (0 == flag) {
            putchar(ch);
            flag = 1;
        }
    }
}
复制代码

1.9 字符数组

读入一组文本行,并打印最长的文本行

复制代码
#include <stdio.h>
int get_line(char *s, int limit);
void copy(char *to, char *from);

#define MAXLINE 10 //一行可以保存的最大字符数
void main() {
        int len = 0, max = 0;
        char line[MAXLINE], char tgt[MAXLINE];
        while ((len = get_line(line, MAXLINE)) > 0) {
                if (len > max) {
                        max = len;
                        copy(tgt, line);
                }
        }

        if (max > 0)
                printf("max=%d,%s\n", max, tgt);
}

int get_line(char *s, int limit) {
        int ch = 0, len = 0;
        while (len < limit - 1 && (ch=getchar()) != EOF && ch != '\n')
                s[len++] = ch;

        if (ch == '\n')
                s[len++] = ch;
s[len] = '\0'; return len; } void copy(char *to, char *from) { for (int i = 0; '\0' != (to[i]=from[i]); i++); }
复制代码

 

练习1-17 编写一个程序,打印长度大于80个字符的所有输入行。

该程序 只需要在 main() 的处理逻辑中,判断 get_line() 的返回值 大于 80,打印该行即可

复制代码
#include <stdio.h>
#define MAXLINE 1000 //一行可以保存的最大字符数
int get_line(char *s, int limit);void main() {
    int len = 0;
    char line[MAXLINE];
    while ((len = get_line(line, MAXLINE)) > 0) {
        if (len > 80)  printf("%s\n", line);
    }
}
复制代码

1_18 编写一个程序,对于输入行末尾的空格和制表符进行删除,然后打印; 如果该行都是空格,就不会打印了

复制代码
#include <stdio.h>
#define MAXLINE 1000 //一行可以保存的最大字符
int get_line(char *s, int limit); // 该函数和 1-9 中的get_line 一样
int _remove(char *s, int len) { /* 按照上下文,s[len-1] = '\0'; s[len-2] = '\n' */
for (len -= 2; len >= 0 && (s[len] == '\t' || s[len] == ' '); len--); if (len >= 0) { s[++len] = '\n'; s[++len] = '\0'; } return len; } void main() { int len = 0, cnt; // cnt 用来表示删除空格之后的效果 char line[MAXLINE]; while ((len = get_line(line, MAXLINE)) > 0) { printf("len = %d, ", len); if ((cnt = _remove(line, len)) > 0) { printf("cnt=%d, %s", cnt, line); } } }
复制代码

 1_19  编写一个 reverse(s)函数,将输入的文本行,翻转后进行输出

复制代码
#include <stdio.h>
#define MAX_LINE 1000

int get_line(char *s, int limit);
void reverse(char *s, int len) {
    // 该函数如果无len参数,需要先找到字符串末尾 for(int idx = 0; s[idx]; idx++); 如果s[--idx] = '\n', 还需要--idx
for (int left = 0, right = len - 2; left < right; left++, right--) { char tmp = s[left]; s[left] = s[right]; s[right] = tmp; } } void main() { int ch, len = 0; char line[MAX_LINE] = {}; while ((len = get_line(line, MAX_LINE)) > 0) { reverse(line, len); printf("%s", line); } }
复制代码

 练习 1_20 编写 detab,将输入中的制表符替换成适当数目的空格,使空格充满到下一个制表符终止的地方

复制代码
#include <stdio.h>
#define TAB 4

// 首先理解,tab对齐的位置和当前位置有关,需要用空格替换。 
// 然后依次处理输入的字符,进行分类讨论。
// pos位置的tab可转化成 TAB-pos%TAB个空格
// 每种情况的pos 变化不同,需要单独设置
void main() {
    int ch, pos = 0;
    while(EOF != (ch = getchar())) {
        if (ch == '\t') {
            int n_blank = TAB - pos % TAB;
            // pos = (pos / TAB + 1) * TAB;
            while (n_blank-- > 0) {
                putchar(' ');
                ++pos; // 如果每行有字符个数限制, 此处可修改为 if(++pos == LIMIT) {putchar('\n'); pos = 0; break;}
            }
        } else if (ch == '\n') {
            putchar(ch);
            pos = 0;
        else {
            putchar(ch);
            ++pos; // 如果每行有字符个数限制,此处可修改为 if (++pos == LIMIT) {putchar('\n'); pos = 0;}
        }
    }
}
复制代码

练习 1_21 编写entab, 将空格串替换成最少数量的制表符和空格

复制代码
#include <stdio.h>
// 将多个空格替换成 tab
#define TABINC  4

void main() {
    int ch, nb = 0, nt = 0, pos;

    for (pos = 1; EOF != (ch = getchar()); pos++) {
        if (' ' == ch) {
            if (pos % TABINC != 0) {
                nb++;
            } else {
                nt++;
                nb = 0;
            }
        } else {
            for (; nt > 0; --nt) // 使用while(nt-- > 0) 进行循环,nb会等于-1
                putchar('\t');

            if ('\t' == ch)
                nb = 0;
            else
                for (; nb > 0; --nb)
                    putchar(' ');

            putchar(ch);

            if ('\n' == ch) {
                pos = 0;
            } else if (ch == '\t') {
                pos = pos + (TABINC - (pos - 1) % TABINC) - 1;
            }
        }
    }
}
复制代码

如果只需一个空格就能达到下一个制表符,当前处理是替换成一个制表符,因为这有助于避免特殊情况

 

posted @   靖意风  Views(4)  Comments(1Edit  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示