c - 如何在 C 中检查 stdin == stdout

标签 c stdout stdin getchar putchar

我正在构建一个接受用户输入、对其进行操作并输出更改(如果有)的程序。准则是:

  1. 删除所有数字
  2. 如果连续有 > 2 个换行符,则只打印 2 个
  3. 改变字母大小写
  4. 每个空格打印2个空格
  5. 正常打印所有其他字符
  6. 如果 stdin 和 stdout 相同,则从 main 返回 1,否则返回 0。

我不能为这个项目使用任何数据结构,所以我使用 getchar() 逐个字符地读取标准输入。

有什么方法可以比较 C 语言中的标准输入和标准输出吗?我是这门语言的新手,甚至不知道如何研究它。我的所有准则都满足 sans 6 的代码如下:

#include <stdio.h>

int newline(int iochar);
void testChars(int iochar);
void upperCase(int iochar);
void lowerCase(int iochar);
void space(int iochar); 
void digit();


int main()
{
    int iochar = 0;
    iochar = getchar();

    testChars(iochar);

    return 0;
}

void testChars(int iochar)
{
    while(iochar != EOF) {
        if (iochar == 10)
            iochar = newline(iochar);

        else if(iochar == 32)
        space(iochar);

        else if (iochar > 64 && iochar < 91)
        upperCase(iochar);

        else if (iochar < 123 && iochar > 96)
        lowerCase(iochar);

        else if (iochar < 58 && iochar > 47)
        digit();

        else putchar(iochar);

        iochar = getchar();
    }
}

void space(int iochar)
{
    putchar(iochar);
    putchar(iochar);
}

int newline(int iochar)
{
    int count = 0;
    while (iochar == 10){
        if(count < 2)
            putchar(iochar);
        count++; 
        iochar = getchar();
    }
    return iochar;
}

void digit()
{
    return;
}

void upperCase(int iochar)
{
    iochar += 32;
    putchar(iochar);
}

void lowerCase(int iochar)
{
    iochar -=32;
    putchar(iochar);
}

最佳答案

虽然您可以将测试分解为多个函数,但由于您处理的案例数量有限,只需将测试直接包含在一个“状态”循环中,该循环跟踪换行符的数量以及是否有对输入的任何修改都是一种同样可读的方式。 (很好地捕获了 XY 问题上的@iBug)。

有多种方法可以解决字符分类问题,这基本上就是您所拥有的。 (意思是你读一个字符,分类是否符合一些预定义的测试,然后根据它的分类方式采取一些行动)。处理它的一种有效方法是使用一个循环来跟踪事物的状态(例如“有多少换行符已被顺序读取?”,或者我是否在一个单词中,读取空格等)通过设置,或重置或递增一些变量来跟踪您感兴趣的任何条件(或状态),这些条件(或状态)基于当前角色以外的其他内容。

您只需弄清楚需要遵循的内容(这里是连续换行符的数量,以及您是否以任何方式修改了输出)。很简单,只需以整数形式(如 nl)记录读取的顺序换行符,并保留一个整数标志,如果您进行任何更改,请将其称为 modified 或合乎逻辑的名称.当您阅读除 '\n' 以外的任何内容时,请重置您的换行符计数,例如nl = 0;

然后只需读取输入的每个字符,直到遇到 EOF 并进行大量测试以确定您读取的字符(使用 if、else if、else 或使用 switch 语句)。然后针对每个不同的测试,采取适当的操作。

例如,您可以通过类似以下的简单内容来满足您的标准:

#include <stdio.h>

int main (void) {

    int c, modified = 0, nl = 0;

    while ((c = getchar()) != EOF) {        /* loop over each char       */
        if (c == '\n') {                    /* am I a '\n'?              */
            if (nl < 2)                     /* have I ouput less than 2? */
                putchar ('\n');             /* output the newline        */
            else
                modified = 1;               /* set modified flag         */
            nl++;                           /* update the number seen    */
            continue;                       /* get next char             */
        }
        else if ('A' <= c && c <= 'Z') {    /* am I uppercase?           */
            putchar (c + 'a' - 'A');        /* convert to lowercase      */
            modified = 1;                   /* set modified flag         */
        }
        else if ('a' <= c && c <= 'z') {    /* am I lowercase?           */
            putchar (c + 'A' - 'a');        /* convert to uppercase      */
            modified = 1;                   /* set modified flag         */
        }
        else if (c < '0' || '9' < c) {      /* am I not a digit?         */
            if (c == ' ') {                 /* am I a space ?            */
                putchar (c);                /* output extra space        */
                modified = 1;               /* set modified flag         */
            }
            putchar (c);                    /* output unmodified char    */
        }
        nl = 0;                 /* reset newlines seen to zero */
    }

    return modified ? 0 : 1;    /* 0 - modified, 1 - stdout == stdin */
}

注意:尽量避免在您的代码中使用魔数(Magic Number)。如果您需要 'A' 的 ASCII 值,请使用 'A',而不是 65。阅读散布着魔数(Magic Number)的思想代码(例如653210)所提供的信息远不如'A', ' ''\n').

另请注意,您可以使用宏 ctype.h(例如 isupper()islower()isdigit () 等..) 以非常可读的方式轻松测试当前字符是什么。手动执行它也有学习值(value),可以了解 ctype.h 中那些方便的函数实际上在做什么,并练习正确设置条件测试。

示例输入文件

现在只需创建一个测试用例来练习您的字符分类,并确保您的循环按应有的方式工作。没有什么特别的要求。与其尝试构造无数的 assert() 语句,不如创建一个具有适合每种情况的字符的输入文件:

$ cat dat/stateloop.txt
This Is a Line followed by THREE-newlines


and with SEVEN single-spaced asterisk * * * * * * *
aND a lINE fOLLOWED bY five nEWLINES ('\N')




And A Few Numbers zERO-tO-nINE (123456789)
1
a b c d e f g - A B C D E F G
Done2Day

示例使用/输出

然后仔细检查输出:

$ ./bin/stateloop <dat/stateloop.txt
tHIS  iS  A  lINE  FOLLOWED  BY  three-NEWLINES

AND  WITH  seven  SINGLE-SPACED  ASTERISK  *  *  *  *  *  *  *
And  A  Line  Followed  By  FIVE  Newlines  ('\n')

aND  a  fEW  nUMBERS  Zero-To-Nine  ()

A  B  C  D  E  F  G  -  a  b  c  d  e  f  g
dONEdAY

检查返回值

并验证返回是否正确。

$ echo $?
0

尝试一个(不变)案例

对未修改的情况做同样的事情:

$ printf "~@##$@#$%%#*[]{};:^^&&*)\n" | ./bin/stateloop
~@###$%#*[]{};:^^&&*)

检查适当的返回

$ echo $?
1

如前所述,有多种方法可以解决此类问题。只需找到合乎逻辑、健壮、可读和可理解的内容即可。祝你编码顺利。

关于c - 如何在 C 中检查 stdin == stdout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48838232/

相关文章:

c - 从 C 中的文件描述符中检索文件名

c++ - 为什么我的代码在要求打印长度和宽度的值后不接受多个输入?

go - 从 Go 中的 StdoutPipe() 读取卡住

python - 在从 Python 中的 stdin 读取数据的同时对关键事件使用react

c - 标准输入/标准输出重定向,输入不起作用

c - 除十六进制数时的奇怪行为

c++ - 打包结构/避免填充

Java 处理 getOutputStream 到 String

Python - 在对齐的列中打印 CSV 字符串列表

go - 如何将容器 stdin 和 stdout 与 websocket 连接起来?