我正在构建一个程序,接受用户输入,操作它,并输出更改(如果有的话)。指导方针是:
删除所有数字
如果一行超过2行,则只打印2行
换文
为每个空间打印2个空格
正常打印所有其他字符
如果stdin和stdout相同,则从main返回1,否则返回0。
我不能为这个项目使用任何数据结构,所以我使用getchar()逐字符读取stdin char。
有没有办法把stdin和C中的stdout进行比较?我对这门语言还不熟悉,甚至不知道该如何看待它。我的代码和所有符合SAN 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);
}
最佳答案
虽然可以将测试分成多个函数,但由于处理的案例数量有限,只需将测试直接包含在一个“state”循环中,该循环跟踪换行的数量以及是否对输入进行了任何修改,这是一种同样可读的方法。(在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 */
}
注意:尽量避免在代码中使用幻数。如果需要
'A'
的ASCII值,则使用'A'
,而不是65
。阅读散布着神奇数字的思想代码(例如65
,32
,10
并不像'A'
,' '
和'\n'
那样具有信息性。另外,还可以使用宏is
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
如前所述,有许多方法可以解决这类问题。找一些逻辑性强、可读性强、易懂的东西。祝你编码顺利。
关于c - 如何在C中检查stdin == stdout,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48838232/