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两次 – 一次初始化chvariables,一次检查chEOF

删除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';

最后,虽然这不影响程序的正确性,但是我会将iftesting颠倒过来:

 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; } 
Interesting Posts