我一直在研究一些关于C的书,试图得到我的C腿(海腿!得到它?!)。我刚从K& R书中完成了练习1-9,其参考是“编写一个程序将其输入复制到其输出中,用一个空格替换一个或多个空格的每个字符串。”我对我的代码有什么问题有疑问 -
#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;
}
除了第一个字符输入外,这大部分都有效。例如,如果第一行输入是
"This is a test"
我的代码输出
"his is a test".
在删除第一个字符输入后,程序会一直工作以满足练习的要求。
有人能让我知道我在循环中犯的错误导致了这个问题吗?我们也欢迎任何其他建议。
答案 0 :(得分:36)
在for-loop语句中,您有错误。
for(ch = getchar(); (ch = getchar()) != EOF; lch = ch){...}
在这里,您将第一个字符存储在ch中,然后再次通过再次读取字符输入来测试是否(ch!= EOF)。
从初始化声明中删除ch=getchar()
;让它在第二部分。
for(;(ch = getchar()) != EOF; lch = ch){...}
此外,您必须在运行之前初始化您的lch,因为在循环的第一次迭代中进行比较之前,lch将不会存储任何值。所以,先让lch=0
初始化。
for(lch = 0; (ch = getchar()) != EOF; lch = ch){...}
考虑在编译器中启用警告,它可能会检测并警告此问题,因此您可以修复它。
以上可以解决您的问题。
(感谢Blue Moon和hyde帮助我修改答案。)
答案 1 :(得分:16)
在循环初始化中调用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:感谢Blue Moon和shekhar suman用lch指出问题
答案 2 :(得分:13)
问题在于,循环的第一次迭代会调用getchar
两次 - 一次初始化ch
变量时,再一次检查ch
对EOF
。
删除ch = getchar()
将解决此问题:
for( lch = '?' ; (ch = getchar()) != EOF; lch = ch) {
...
}
请注意,您需要使用除space之外的任何值初始化lch
。
答案 3 :(得分:9)
您在循环开始之前调用getchar()
一次,然后在for
条件下每次迭代调用一次。您检索的第一个字符因此被丢弃。
在比较之前,您还需要在循环之前初始化lch
。当字符串的第一个字符是空格时,取决于您想要做什么:
' '
将修改前导空格&#34;预匹配&#34;它。您的循环标题变为(在第二种情况下):
for(lch = 'a' /*arbitrary*/; (ch = getchar()) != EOF; lch = ch)
感谢shekar suman关于未初始化lch
的单挑。
答案 4 :(得分:6)
更改此循环
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 );
}
否则在循环开始时你会读两次字符。
另外在我看来,作业描述了另一项任务
&#34;编写程序将其输入复制到其输出,替换每个 一个空格的一个或多个空格的字符串。&#34;
你应该用一个空白替换每一行空白。:) 上面显示的循环不执行此任务。
答案 5 :(得分:4)
除非任务是使用for循环执行,否则如果您尝试获得更清晰的代码,那么学习该语言会更好。只需告诉自己代码的作用,比较一下与for循环等效的while循环:
//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-construct,你也可以将它转换为hacky for-loop,但为什么会这样? while更容易阅读,编译器不关心,因为它将以相同的方式编译。 (可能)
答案 6 :(得分:4)
虽然有很多正确的答案,但是让我给你一个提示,告诉你如何使用调试器(gdb here)自行跟踪这个问题:
首先将代码更改为这样(每行一个语句!):
...
for(ch = getchar();
(ch = getchar()) != EOF;
lch = ch){
...
现在使用符号(g {的-g
)编译它,然后使用调试器运行代码:
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
在“运行”代码的各个阶段检查有趣的变量(ch
),同时逐步执行。
有关如何操纵gbd的更多详细信息:http://beej.us/guide/bggdb/
答案 7 :(得分:3)
是的,当你宣布你的声明时,首先你要用
初始化ch。for( ch= getchar();
所以此时你得到你的第一个字符(T)并且指针将一个位置前进到下一个字符(h)
然后你再次使用(ch = getchar()) !=EOF;
尝试更改for (ch= getchar();
并改为使用for (ch= '' ;
。
希望能解决它。
答案 8 :(得分:1)
for
语句有三个部分:初始化,条件和增量。这些部分用两个分号分隔。
当for
语句的条件部分有副作用时,这非常令人困惑。副作用属于增量部分:
for (ch = getchar(); ch != EOF; lch = ch, ch = getchar())
并且,正如其他人所指出的那样,lch
必须被初始化,所以:
int lch ='a';
最后,虽然这不会影响程序的正确性,但我会反转if
测试:
if (ch != ' ' || lch != ' ')
putchar(ch);
答案 9 :(得分:0)
这对我有用
<?php
class Rsl_Icon_For_Title {
public $myposts;
public function rsl_settings_page_get_data($myposts) {
$my_posts = new WP_Query;
$this->myposts = $my_posts->query( array('post_type' => 'post'));
return $this->myposts;
}
public function rsl_settings_page_render () {
$this->rsl_settings_page_get_data();
var_dump($this->my_posts);
}
}
答案 10 :(得分:0)
@elessar的更改不大。第12行必须从(blank> 1)更改为(blank> = 1),因为前一行不会打印单个空格。
#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;
}
答案 11 :(得分:0)
#include <stdio.h>
int main()
{
int charac;
// Variable declared for verifying consecutive whitespaces
bool blank = false;
// As long as you did not input EOF (Ctrl + Z on Windows, Ctrl + D on linux, macOS)
while ((charac = getchar()) != EOF){
// Current char is whitespace, the one before was also whitespace => go to next iteration
if((charac == ' ') && (blank == true)){
continue;
}
// If current char is whitespace, keep this in mind(blank = true) and output the whitespace
else if(charac == ' ')
{
blank = true;
putchar(charac);
continue;
}
// If current character is not whitespace, output it and reset the blank boolean
putchar(charac);
blank = false;
}
return 0;
}
答案 12 :(得分:0)
#include <stdio.h>
#include <ctype.h>
/* replace each string of one or more blanks by a single blank */
int main() {
int c, s1;
s1 = 0;
while ((c = getchar()) != EOF) {
if (isspace(c)) {
++s1;
} else {
s1 = 0;
}
if (s1 > 1) {
continue;
}
putchar(c);
}
return 0;
}
答案 13 :(得分:0)
我也在阅读这本书学习 C 并且我设法想出了这种方法,我希望得到一些反馈以改进。 我尽量不声明太多变量,以免浪费内存空间。 我最终定义了毯子空间以便稍后打印,因为我想将多个制表符和空格视为一种情况。
#include <stdio.h>
/* space char was defined so I can treat ' ' and '\t' on the same case */
#define BLANK ' '
int main(){
int c;
while((c = getchar()) != EOF){
/* if char is either ' ' or '\t' */
if((c == ' ') || (c == '\t')){
/* print a blank */
putchar(BLANK);
/* read next char */
c = getchar();
/* while after the ' ' or '\t' the char is again ' ' or '\t' ... */
/* I'm not going to bother with it and I'm going to read the next char */
while((c == ' ') || (c == '\t')){
c=getchar();
}
/* print the char */
putchar(c);
}
/* another char */
else {
putchar(c);
}
}
}