| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1501 人关注过本帖
标题:[求助]照书抄的程序却运行结果错误,错在哪儿?
只看楼主 加入收藏
bluesky3810
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2007-9-17
收藏
 问题点数:0 回复次数:13 
[求助]照书抄的程序却运行结果错误,错在哪儿?
我是个新手,今天按照书上的例题输入了一个程序,但最后运行结果不对,请高手给指点指点,错误在哪?原因何在?正确的该如何编写?请解释详细一点,先谢了。

程序要求:输入一行字符,统计其中有多少个单词,单词之间用空格分隔开。
程序如下:
#include "stdio.h"
main()
{
char string[81];
int i,num=0,word=0;
char c;
gets(string);
for (i=0;(c=string)!='\0';i++)
if(c=='')word=0;
else if(word=0)
{
word=1;
num++;
}
printf("There are %d words in the line\n",num);
}
不管我输入多少个字符,最后运行结果都为0个,这是怎么回事?
搜索更多相关主题的帖子: 结果 运行 
2007-09-17 16:57
雨中飞燕
Rank: 3Rank: 3
等 级:禁止访问
威 望:8
帖 子:2200
专家分:0
注 册:2007-8-9
收藏
得分:0 
有人告诉你书的一定对吗?????



by 雨中飞燕 QQ:78803110 QQ讨论群:5305909

[url=http://bbs.bc-cn.net/viewthread.php?tid=163571]请大家不要用TC来学习C语言,点击此处查看原因[/url]
[url=http://bbs.bc-cn.net/viewthread.php?tid=162918]C++编写的Windows界面游戏[/url]
[url=http://yzfy.org/]C/C++算法习题(OnlineJudge):[/url] http://yzfy.org/
2007-09-17 17:01
neverTheSame
Rank: 3Rank: 3
来 自:江西农业大学
等 级:新手上路
威 望:9
帖 子:1511
专家分:0
注 册:2006-11-24
收藏
得分:0 
for (i=0;(c=string)!='\0';i++)中(c=string),c是一个char型数据,string是一个字符型常指针.
应该是for (i=0;(c=string[i] )!='\0';i++)

wap酷禾网(http://wap.),提供免费的、优质的、快捷的wap资源下载服务。
2007-09-17 17:06
偑色幻想
Rank: 1
等 级:新手上路
帖 子:68
专家分:0
注 册:2007-9-12
收藏
得分:0 

虽然设置了i.但是后面不使用的话不就没意义了...帮你改了一下.而且也清晰了许多.
[CODE]#include "stdio.h"
#include "conio.h"
#include "string.h"
int main(void)
{
char string[81];
int i=0,num=0;
char c;
gets(string);
for (i=0;(c=string[i])!='\0';i++)
{
if ((c=string[i])==' ')
{
num++;//完全没有必要再设置一个标志了
}
}
printf("%d",num);
getch();
return 0;
}[/CODE]


2007-09-17 18:47
bluesky3810
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2007-9-17
收藏
得分:0 
回复:(neverTheSame)for (i=0;(c=string)!=\'\\0\';i+...

不好意思,你指出的这次错误是我发帖时不小心给弄掉的,在输入程序的时候这个地方我并没有搞错,但运行结果依然始终是0
不过还是非常感谢你啊。不然我还没发现自己帖子都给发错了。

2007-09-17 19:18
bluesky3810
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2007-9-17
收藏
得分:0 
回复:(偑色幻想)虽然设置了i.但是后面不使用的话不...
谢谢您的指点,但是你的代码运行的时候结果总是比正确结果少1.
而且我现在还是在学习C语言的阶段,您所运用的很多内容我还没有学到,我只是想通过这个程序掌握字符数组的应用。
不管怎么样,还是谢谢您了。
2007-09-17 19:25
我是菜鸟哦
Rank: 6Rank: 6
等 级:贵宾
威 望:22
帖 子:921
专家分:209
注 册:2007-5-4
收藏
得分:0 
回复:(bluesky3810)回复:(偑色幻想)虽然设置了i...
少一是因为空格总要比单词数少一个
这个判断的BUG最主要的问题在于如果连续打空格不就更统计错误了吗,所以最好再加个FLAG判断空格是否连续
连续就不加1,不连续就......OK?

偶是菜鸟鸟偶惧WHO?!!!!
2007-09-17 19:54
bluesky3810
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2007-9-17
收藏
得分:0 

补充一下,我是在TC2.O的平台上运行的,
刚才看了一篇帖子,说TC已经过时了,这种说法准确吗?



以下为引用原帖:

给使用TC的初学者的一篇文章 —— 作者:雨中飞燕

本文源自雨中飞燕之家C/C++学习论坛http://yzfy.org,转载请注明出处。

前言:

“TC过时了”,我说。接着就一堆人问,“为什么过时啊?”,“TC不是很好用吗”,
“教材上也是用这个啊”,“二级考试不也是规定用的TC吗?”。
于是乎我已经无语了。


/----------------------------------------------------------------------/
一。头文件的问题

好了,来看个经典的TC2下在老潭的书的《C语言程序设计(第二版)》,
第4页的一段代码:
main( )
{
printf("This is a C program.\n");
}

好了,当时的TC2的确允许使用printf和scanf可以不加头文件,
也的确允许main()这样的声明。允许是允许了,可是你写成这样对你有好处吗?

打个比方,Basic语言知道吗?这种语言可以不声明变量就使用。
的确同样也是允许了,可是给我的话,我会要求编译器强制检查变量是不是声明了再使用。
为什么?如果你需要用名字是nlen这个变量,当中有一个不小心写成n1en,
不强制检查的话,编译器不告诉你错,但运行结果是错误的。但这种错误要是在很多行
代码里你怎么找?特别是'l'和'1'如此相似。

编译器虽然允许,但你别以为那样写就是好事。说回刚刚的C代码,TC2允许不加头文件,
于是不少初学的人习惯了从不写头文件,以为C语言不需要头文件似的。
好了,等到看到那本书的138页,那个字符输入输出,用了gets,
就突然多了一个#include <stdio.h>,仔细一看,那一页中间有100来字强调
了要用库函数,可是没有讲怎么用,下面多了的那一行初学者也可能会觉得奇怪,
要是不理解的人就跳过了,要是没留意的更不当一回事了,谁让之前书里一直都
没有那句呢。然后,当有的初学者用TC3.0打代码的时候,编译提示说scanf没有
声明(或者是用TC2的打了gets函数说gets没有声明),他们就郁闷了,
都是按照书的代码啊,都一模一样还会错?于是跑来论坛问。有跑来问的还好,
最怕的就是用TC2的,看了数组觉得难还跳了过去的,于是一直都不会写头文件,
成了习惯。要是随便换个环境,结果没写头文件的,错了,结果还说自己写C代码
写那么多,这里怎么就错了,然后就怀疑编译器是不是坏的。然后就借口说这个
用不习惯要换TC2。结果就是恶性循环,跳不出TC2,学不到新领域的东西。
论坛上这种代码绝不少见,随便翻一些提问帖子肯定找得到。其实早在TC3.0已经
不再允许scanf和printf不加头文件了,随后的所有C编译器也不再支持TC2的
这个特性了。
本文源自雨中飞燕之家yzfy.org,作者雨中飞燕

/----------------------------------------------------------------------/
二。main的声明与返回值

其实如果只是算潭书的第二版,这个无类型的main声明没有问题,只是直到C99标准
的出现,这个声明才彻底废除。其实也是同样一个问题,允许你不写,但这不是说你
这样用就是好事。不过,这个的后果有点不一样的就是,你忽略不写,很可能以为是
不需要返回的,或者是以为返回一个无类型的(void),接着就出现了main函数里不
写return 0;的问题。那本书就是从头到尾所有main函数一律没有return 0; 。好了,
等到学了函数那章,书上说,没有返回值的函数应该要用void来声明,好了,
void main就这样诞生了。不信就看看谭书的第三版,变成从头到尾的void main()。
不过话说回头,这样的问题对于初学者学习基本语法和结构方面和写写小程序的都不会
出现任何影响。在编译器上来说,这只是一个标准的问题,但对于你来说别小看了这么
一点点的变化。因为你习惯了main这种写法的话,必然会把这个习惯带到编写其它函数里
(这里暂且不讲main本身返回值的问题)。
举个简单例子,写以下代码:
#include <stdio.h>
factorial(int n)
{
if(n==1)return 1;
else if(n>1)return n * factorial(n-1);
}
int main(void)
{
int n;
while(scanf("%d", &n),n>=0)
{
printf("%d\n", factorial(n));
}
return 0;
}

看得出来是计算阶乘的(主要看那个子函数,main函数用回标准写法),
只不过少了int声明和最后一个必然的return而已,

看看输入一个0进去会发生什么事吧:
TC2: 1 (结果居然是碰对了)
VC6: -858993460 (不确定的随机结果)
GCC: 0 (C99标准)
如果你用TC,那你还可能以为这份代码是正确的,
于是你就以为递归算阶乘就是这么写的。
于是还反过来问我:“喂,雨中飞燕,这个结果不就是正确的吗,还错什么啊?”
于是我无语了。。。然后你也就留下了一个你可能以后都不打算去检查的Bug。。。

现在我们再来看一个:
#include <stdio.h>
long Factorial(int n)
{
if(n==1)return 1;
else if(n>1)return n * Factorial(n-1);
return 1;
}
FactorialSum(int n)
{
float f = 0;
for(;n>0;--n)
{
f += 1.0/Factorial(n);
}
return f;
}
int main(void)
{
int n;
while(scanf("%d", &n),n>=0)
{
printf("%f\n", FactorialSum(n));
}
return 0;
}

这个是计算1/1! + 1/2! + 1/3! +...+ 1/n!的代码,Factorial的改好了,
然后加一个FactorialSum函数计算和。里面的变量f就是用来累加(喜欢用float来
保存浮点也是书上的一大不良特色),1写成1.0保证结果不是整数。似乎没错吧?
运行一下不就知道了嘛,输入1,输出0;输入2,输出0;输入5,输出0,
结果是输出全部是0。原因就是你省略类型埋的祸根,只需要在那个函数前面补上
一个float那结果就正确了。
本文源自雨中飞燕之家yzfy.org,作者雨中飞燕
这个危害有多严重吗?在这里不算严重,因为在这里代码很短,相当容易看得出来。
要是换成大程序呢?上千代码甚至上万的代码,要是最后都懒得写一下return,
或者一个返回类型,那么错误还怎么找?你要是这个也省略那个也省略,
写了N多行代码的时候,一运行,这个结果也错那个输入也不行的时候,
你再看看你是不是被你自己的“习惯”给难住你自己吧。

其实说实在的,WIN-TC自带的一个tcsearch.exe文件,那个可以查函数用法和示例,
上面的示例代码全部都是一样的风格: int main(void)
非常规范标准的写法,可是有多少人看了这个了呢?


/----------------------------------------------------------------------/
三。函数声明

经典的老代码:
int max(x,y)
int x,y;
{
return x>y ? x : y;
}

现在早已不是pascal时代了,这样的函数声明不但难读,并且现在C99标准已经不再
支持这种写法了。在老潭的书也仅仅用了半版不到的篇幅提到了一下,
其它地方并没有使用这种声明,这点做得还不错。不过很奇怪的是论坛上还时不时
能看见这种声明,这个到底是拜谁所赐呢?这我就不知道了,这里也不展开来讲了。


/----------------------------------------------------------------------/
四。代码风格

这个问题就非常严重了。现在的情况是,从代码风格,就可以知道你的大概水平了,
至少能知道你是不是菜鸟。那些代码缩进弄得乱七八糟的,不用看详细代码都知道
水平肯定高不到哪里去(当然不排除你可以故意弄乱)。因为要是作为一个新手,
要是写的代码乱,调试的时候或者自己看自己的代码的时候,要是你自己都觉得乱,
当代码有Bug,你要找出来的话,看你还头痛不头痛了。本来代码就有问题,再加上
格式乱,要是你自己看着都不舒服,那你还怎么去调试代码呢?自己不会看着头晕?
代码少的时候你可能不觉得,等你写了上百行代码的那再尝尝这种滋味吧。

更严重的问题是,DOS原版TC对缩进支持不好,
格式的控制相对其它的编辑器来说都要弱。
对于初学者,很容易弄出参差不齐的代码,
对于学习方面来说这是一个很不利的因素。
本文源自雨中飞燕之家yzfy.org,作者雨中飞燕
再者,大括号的位置及变量声明位置的问题。看以下几种风格:
1.
int main(void) //潭氏风格
{int n,s;
while(scanf("%d", &n),n>=0)
{
s = factorial(n);
printf("%d\n", s);
}
return 0;
}

2.
int main(void) //视频教学风格?
{ int n,s;
while(scanf("%d", &n),n>=0)
{ s = factorial(n);
printf("%d\n", s);
}
return 0;
}

3.
int main(void) //不知道这风格的来源
{
int n,s;
while(scanf("%d", &n),n>=0)
{
s = factorial(n);
printf("%d\n", s);
}
return 0;
}

4.
int main(void){ //这种风格也有不少高手使用的
int n,s;
while(scanf("%d", &n),n>=0){
s = factorial(n);
printf("%d\n", s);
}
return 0;
}

5.
int main(void) //C Primer Plus 上的风格
{
int n;
while(scanf("%d", &n),n>=0)
{
int s = factorial(n);
printf("%d\n", s);
}
return 0;
}

我推荐的写法是第5种。第三种写法貌似较少见,雨中飞燕本人不好作出评论。
但对于1,2,4三种写法,都是有原因的。原因也很简单,减少占用的行数。
特别是纸版书,节省这点行数累积起来可以节约不少纸张,降低书的成本。
对于powerpoint演示,如果不节约行数,代码根本没办法显示完。
但你要注意,它这样写可能不是为了告诉你要这样写出这样紧密的代码。
但同样的问题出现在TC上。DOS窗口标准大小80*25,高度只能显示25行,
再加上TC菜单和最下面的输出窗口,你能同时看到最多20行,要是按第5种风格
来写代码,会看得很辛苦(因为TC2用不了鼠标,TC3能用不过也麻烦),
于是造成N多紧缩型代码。如果你换成现在新的编辑软件,根本用不着这样。
Windows上的集成编辑软件一页下来就是三四十行,用鼠标滚轮滚一下就能上下拉,
一个代码块要是不想看还可以折叠起来,这些特性都是TC所无法比拟的,
都比TC方便得多。你还有什么理由抱着TC不放呢?还何必写紧缩型代码来为难
自己的那双眼睛呢?


/----------------------------------------------------------------------/
五。TC图形库

TC图形库这个可以说是TC一大特色,用TC2写出来的代码一般可以一眼看出,因为TC2
编译运行的时候,屏幕上原有的东西并不会清除,所以用TC的人一般会习惯在程序开头
写上clrscr()。当然,要是用Win-TC就不会发生这种情况。如果使用者本人知道这个
库是TC专有(好比是VC的MFC)的话,这倒问题不大。问题是如果使用者不知道的话,
屏幕输出用习惯了gotoxy,变得理所当然地认为C就应该支持这类函数的话,
那就糟糕了。论坛上跑来问VC6可不可以输出图形,或者问有没有gotoxy函数的人
不是一个两个人的问题了。
本文源自雨中飞燕之家yzfy.org,作者雨中飞燕

/----------------------------------------------------------------------/
六。越界检查

由于在DOS下,DOS系统根本不会去检查程序的访问越界问题,无论你要对内存的哪里
进行读写,都是允许的(只要不把自己程序的代码区改写了就没事)。但在Windows下,
尤其是WinXP,内存是分块的,对只读块写数据或者对不可读写块进行读数据都会引发
异常,如果程序不能够处理这个异常,那么这个程序就会被强制关闭。有了这个异常
机制,当然会使你更容易查出程序的错误。特别地,在VC6的Debug模式下,
堆里未被初始化的内存被0xCD字节模式填充,堆里释放的内存被0xDD字节模式填充。
于是一但发生越界的时候,很容易通过程序运行结果得知当中有错,为调试带来了方便。
然而TC则不然,不管你越界了多少,你都收不到任何的警告或者错误。
而且在多数情况下,TC下运行正常的越界代码换VC6上就会结果出错。
有初学者以为这是VC6编译器有问题,其实不然,而是TC给你掩盖了这个错误。
#include <stdio.h>
int main(void)
{
int n;
int num[8];
int sum[8] = {0};
for(n=1;n<=8;++n)num[n] = 1;
for(n=1;n<8;++n)sum[n] = num[n]+num[n+1];
for(n=1;n<8;++n)
printf("%d\n", sum[n]);
getchar();
return 0;
}

这个程序的目的是给num数组全部给1,然后sum数组计算num相邻两个数的和。
有的初学者可能会说,这个程序没问题,如果他以为int num[8];的下标是从1至8的话。
然后,照样运行一下看看。TC的结果是7个2,结果正常。
VC6的结果是,什么都没有显示,然后你打开资源管理器查看一下进程,
你就会发现这个程序占用CPU高达90%以上。你不要以为这是编译器发生了问题,
原因正是因为这里的越界导致了一个死循环!如果是GCC或更高版本的VC编译器,
把for里的8改成11也会发生死循环。但即使改成11,在TC上运行的结果也非常正常,
TC里完全没有任何错误的征兆。这里不分析这个死循环产生的原因,这里只是想告诉你,
你在TC上运行结果无误的程序不一定就逻辑上正确了(包括VC和GCC)。特别是TC几乎
没有任何的越界检查,所以更要求程序员在TC上编写代码时候要十分谨慎和细心。
但现在问题是现在使用TC的大多是初学者,在没有什么经验的情况下,很大可能
会写出类似这样的越界访问代码。这种代码也许在TC上没有问题,可是只要换一个
编译环境,问题就马上暴露出来了。不信就看看下面的经典TC错误代码吧:
#include <stdio.h>
int main(void)
{
char *pstr;
gets(pstr);
puts(pstr);
getchar();
return 0;
}

(别告诉我说你不知道这代码错在哪里,你不知道错哪里的话那你平时一定是使用TC的)
本文源自雨中飞燕之家yzfy.org,作者雨中飞燕

/----------------------------------------------------------------------/
七。结束语

现在再来回答文章一开头的内容:“为什么说TC过时”?
主要原因其实不是过时不过时的问题,主要是不适合现在初学C语言的学生们使用。
很容易因为TC过于宽松的一些语法,或者一些与C99标准不一样的语法,
让初学者养成不良习惯或者产生特定环境下的依赖性。这些都是对学习上不利的因素。
所以我一般给别人推荐DevC++或者VC2005就是这个原因,借助编译器的强制能力,
迫使你使用较为规范的方式去写代码。新加坡的环境为什么好?不是因为公民素质高,
是因为有法律规定,随便扔垃圾或者破坏环境的都会有严重的法律后果。

归根究底,不让你用TC,就是不希望你有不良习惯,更何况有很多比TC优秀的编译器呢?
何必因为教材或者考试是TC,你就一定用TC呢?

知识是属于自己的,用来真正充实你自己的
考试是给别人看的,用来得到一时之虚荣的
你希望得到充实,还是一时之虚荣?

本文源自雨中飞燕之家C/C++学习论坛http://yzfy.org,转载请注明出处。

2007-09-17 20:01
交流者
Rank: 1
等 级:新手上路
帖 子:21
专家分:0
注 册:2007-9-5
收藏
得分:0 

还有一个也抄错了
#include "stdio.h"
main()
{
char string[81];
int i,num=0,word=0;
char c;
gets(string);
for (i=0;(c=string[i])!='\0';i++)
if(c==' ') word=0;
else if(word==0)
{
word=1;
num++;
}
printf("There are %d words in the line\n",num);
}

2007-09-17 20:26
偑色幻想
Rank: 1
等 级:新手上路
帖 子:68
专家分:0
注 册:2007-9-12
收藏
得分:0 

TC并非过时.
现在还有很多人使用TC
但是TC对于编程的比如头文件.函数管理都很松.这样容易养成不好的习惯.
当然你很好的约束自己那就算了.
如果不能的话而且想多多练习编程的一些习惯还有一些风格的话还是推荐使用别的.例如VC6.0和DEV_C++都可以.

PS:下次直接把网址加上就好了.


PS2:我的那些程序你应该能看懂的吧...我也是才学的.那些头文件还有后面返回值都是习惯问题.而getch()是因为自己使用的是DEV-C++...要结果一闪而过的问题...所以才加的.

[此贴子已经被作者于2007-9-17 21:24:06编辑过]


2007-09-17 21:17
快速回复:[求助]照书抄的程序却运行结果错误,错在哪儿?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.024740 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved