【问题标题】:How to check if stdin == stdout in C如何在C中检查stdin == stdout
【发布时间】:2018-02-17 05:36:28
【问题描述】:

我正在构建一个程序,该程序接受用户输入、对其进行操作并输出更改(如果有)。指导方针是:

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

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

有什么方法可以将标准输入与 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);
}

【问题讨论】:

  • 你可以使用'a'这样的字符——我们不记住ascii值——所以你的代码的可读性为零。
  • 比较stdinstdout是什么意思?
  • 要将大写字符变为小写,考虑iochar += 'a' - 'A'; 更容易理解。它适用于 ASCII 和 EBCDIC(适用于那些具有复古思想的编码人员)。标准方式是iochar = tolower(iochar);
  • (6) 最简单的形式 if (stdin == stdout) return 1; 应该可以。 (可以比较相同类型的指针,都是FILE*)没有技巧。
  • 错误的标题:stdin 总是不同于 stdout

标签: c stdout stdin getchar putchar


【解决方案1】:

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

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

您只需弄清楚您需要遵循什么(这里是连续换行符的数量,以及您是否以任何方式修改了输出)。很简单,只需将读取的连续换行符计数为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 */
}

注意:尽量避免在您的代码中使用幻数。如果您需要'A' 的 ASCII 值,则使用'A',而不是65。阅读散布着幻数的思想代码(例如653210 的信息量不如'A'' ''\n')。 p>

还请注意,您可以使用宏是 ctype.h(例如 isupper()islower()isdigit() 等)以非常易读的方式轻松测试当前字符是什么。手动执行它也有学习价值,以了解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

检查返回值

并验证return 是否正确。

$ echo $?
0

尝试一个(不变的)案例

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

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

检查适当的回报

$ echo $?
1

如前所述,有很多方法可以解决此类问题。只要找到合乎逻辑、稳健、可读和可理解的东西。祝你编码顺利。

【讨论】:

    【解决方案2】:

    您似乎遇到了 XY 问题。

    根据您的描述,我了解到您真正想要做的是检查输出是否与输入相同。所以解决方法很简单:你只需要跟踪在这个过程中是否至少有一个字符被修改过,如果是,那么你就知道输入和输出会有所不同。

    int modified = 0;
    
    void testChars(int iochar){
        while(iochar != EOF){
            if (iochar == 10){
                iochar = newline(iochar);
            } else if(iochar == 32) {
                space(iochar);
                modified++;
            } else if (iochar > 64 && iochar < 91) {
                upperCase(iochar);
                modified++;
            } else if (iochar < 123 && iochar > 96) {
                lowerCase(iochar);
                modified++;
            } else if (iochar < 58 && iochar > 47) {
                digit();
                modified++;
            } else {
                putchar(iochar);
                // Nothing modified
            }
    
            iochar = getchar();
        }
    }
    
    int newline(int iochar){
        int count = 0;
        while (iochar == 10){
            if (count < 2) {
                putchar(iochar);
            } else {
                modified++;
            }
            count++; 
            iochar = getchar();
        }
        return iochar;
    }
    

    然后测试一下modified == 0你就知道了。

    【讨论】:

    • Quib​​bles:modified 应设置为 1 而不是递增,以避免溢出。 count 应该同样受到限制。 10 应该是 ’\n’。硬编码的字符操作应该改用isdigitisuppertolower
    • @EricPostpischil 我刚刚复制了 OP 的代码并对其进行了最少的修改。
    猜你喜欢
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-27
    • 2017-08-18
    相关资源
    最近更新 更多