K&R练习1-9:输出input,用一个空白replace多个空格
我一直在努力通过一些关于C的书来获得我的C腿(海腿!得到它?!)。 我刚刚从K&R书中完成了练习1-9,其中提到的是“编写一个程序,将其input复制到输出中,用一个空白replace每个一个或多个空白string”。 虽然我有一个关于我的代码发生了什么的问题,
#include <stdio.h> //Copy input to output. Replace each string of multiple spaces with one single space int main(int argc, char *argv[]){ int ch, lch; // Variables to hold the current and last characters, respectively /* This loop should 'put' the current char, then store the current char in lc, * loop back, 'get' a new char and check if current and previous chars are both spaces. * If both are spaces, do nothing. Otherwise, 'put' the current char */ for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ if(ch == ' ' && lch == ' ') ; else putchar(ch); } return 0; }
除了第一个字符input之外,这大部分工作。 例如,如果第一行input是
"This is a test"
我的代码输出
"his is a test".
在放下第一个字符input之后,程序一直工作以满足练习的要求。
有人能给我一个我在循环中造成的错误的想法吗? 任何其他build议也是受欢迎的。
在for循环语句中,你有错误。
for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){...}
在这里,你将第一个字符存储在ch中,然后再次读取字符input来再次testing(ch!= EOF)。
从初始化语句中移除ch=getchar()
; 让它在第二部分。
for(;(ch = getchar()) != EOF; lch = ch){...}
另外,你必须初始化你的lch才能运行,因为在循环的第一次迭代中进行比较之前,lch将没有任何存储的值。 所以,先让lch=0
初始化。
for(lch = 0; (ch = getchar()) != EOF; lch = ch){...}
考虑在你的编译器中启用警告,它可能会检测并警告这个问题,所以你可以修复它。
以上将解决您的问题。
(感谢Blue Moon和海德帮助我修改答案。)
您可以在循环初始化中调用两次getchar:
for(ch = getchar(); (ch = getchar()) != EOF; lch = ch)
相反,您应该在初始化时调用它(获取第一个字符),然后在迭代结束时(获取下一个字符):
int ch, lch = 0; // avoid using uninitialized variable for(ch = getchar(); ch != EOF; lch = ch) { if(ch == ' ' && lch == ' ') ; else putchar(ch); ch = getchar(); }
UPD: 谢谢蓝月亮和谢克尔苏曼用lch指出这个问题
问题是你的循环的第一次迭代调用getchar
两次 – 一次初始化ch
variables,一次检查ch
对EOF
。
删除ch = getchar()
将解决这个问题:
for( lch = '?' ; (ch = getchar()) != EOF; lch = ch) { ... }
请注意,您需要使用除空格以外的任何值来初始化lch
。
您在循环开始之前调用一次getchar()
,然后在for
条件中每次迭代一次。 您检索的第一个字符因此被丢弃。
在比较之前,您还需要在循环之前初始化lch
。 当string的第一个字符是空格时,取决于你想要做什么:
- 将其设置为
' '
将通过”预先匹配“来裁剪前导空间。 - 将其设置为其他任何东西都将正常处理领先空间。
你的循环头成为(在第二种情况下):
for(lch = 'a' /*arbitrary*/; (ch = getchar()) != EOF; lch = ch)
感谢shekar suman提醒未初始化的lch
。
改变这个循环
for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ if(ch == ' ' && lch == ' ') ; else putchar(ch); }
采取以下方式
for( lch = EOF; ( ch = getchar() ) != EOF; lch = ch ) { if ( ch != ' ' || lch != ' ' ) putchar( ch ); }
否则,在循环的开始,你读了一个字符两次。
在我看来,这个任务也描述了另外一个任务
“编写一个程序将其input复制到其输出中,用一个空白replace一个或多个空白string。”
你应该用一个空白来replace每一行空格。:)上面的循环不执行这个任务。
除非任务是用for循环来完成,否则如果你试图获得更干净的代码,那么最好是学习这种语言。 只要告诉自己代码的作用,比较等效的while循环和for循环:
//initialize lch to prevent undefined behaviour //if the first character is a space, it will be printed lch = 'A'; // as long as you can read characters while((ch = getchar()) != EOF) { // if either the current character or the previous one is not a space if(ch!=' ' || lch!=' ') { //print it putchar(ch); } // remember the current for the next round lch = ch; }
一旦你理解了while构造,你也可以把它转换成hacky for循环,但你为什么要这样做呢? 这段时间比较容易阅读,编译器也不在乎,因为它会以相同的方式编译。 (大概)
虽然有很多正确的答案,但让我给你一个提示,你可以通过使用debugging器(gdb)来自己追踪这个问题:
首先将代码更改为这样(每行只有一条语句!):
... for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){ ...
现在使用符号进行编译( -g
为gcc),然后使用debugging器运行代码:
gdb ./a.out
在main()
放置一个断点:
(gdb) break main
启动程序:
(gdb) run
看到停在main()
:
Breakpoint 1, main (argc=1, argv=0x7fffffffe448) at main.c:15 15 for(ch = getchar(); (gdb)
浏览代码:
(gdb) step
在gbd命令行中使用print ch
在“运行”代码的各个阶段检查感兴趣的variables( ch
),同时逐步执行。
更多关于如何引导gbd的细节: http : //beej.us/guide/bggdb/
是的,当你声明你的陈述时,首先你要用ch初始化
for( ch= getchar();
所以在这一刻你得到你的第一个字符(T),指针前进一个位置到下一个字符(h)
(ch = getchar()) !=EOF;
尝试更改for (ch= getchar();
并使用for (ch= '' ;
相反。
希望修复它。
for
语句有三个部分:初始化,条件和增量。 这些部分由两个分号隔开。
当for
语句的条件部分有副作用时,这是非常混乱的。 副作用属于增量部分:
for (ch = getchar(); ch != EOF; lch = ch, ch = getchar())
而且,正如其他人所指出的,我们必须初始化,所以:
int lch ='a';
最后,虽然这不影响程序的正确性,但是我会将if
testing颠倒过来:
if (ch != ' ' || lch != ' ') putchar(ch);
这对我有效
#include <stdio.h> int main(int arg, char *argv[]){ char c = 0; long blank = 0; long tab = 0; while((c=getchar())!= EOF){ if(c == ' '){ ++blank; } if(c != ' '){ if(blank>1){ printf("%c", ' '); blank = 0; printf("%c", c); } else{ printf("%c", c); } } } //end of while return 0; }