中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > C/C++
大家看看这个程序哪个地方错了
作者:未知 时间:2005-09-13 19:28 出处:ChinaUnix.net 责编:chinaitpower
              摘要:大家看看这个程序哪个地方错了

[code:1:0d6df787b6]strcmp1(char *p,char *q)
{
        while((*p != '\0')&&(*p = *q))
        {
                p++;
                q++;
        }
        if(*p > *q)
                return(1);
        else
                return(-1);
        if(*p = *q)
                return(0);
}[/code:1:0d6df787b6]

 FH 回复于:2004-03-09 10:26:33
q比p短怎么办?
*p==*q时也返回-1
*p=*q这里少了一个=

 wpf8036328 回复于:2004-03-09 10:36:58
啊,对少个=,那就再加上一条件*q != '\0',这样能行了吗

 FH 回复于:2004-03-09 10:41:48
*p==*q的时候你也返回-1了

 wpf8036328 回复于:2004-03-09 10:59:51
改对了吧这样,呵呵,我刚调试过
[code:1:3dd1f81586]strcmp1(char *p,char *q)
{
        while((*p != '\0')&&(*p == *q))
        {
                p++;
                q++;
        }
        if(*p >= *q)
                return(1);
        if(*p < *q)
                return(-1);
}[/code:1:3dd1f81586]

 lenovo 回复于:2004-03-09 11:28:20
忘了返回值是int了吧。
你看一看我写的一个。
[code:1:43e01c1374]
int strcmp1( char *s1,  char *s2)
{
while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) )
;
return (*s1 - *s2);
}
[/code:1:43e01c1374]

 whyglinux 回复于:2004-03-09 13:26:05
[quote:3a3c14c3ac="lenovo"]
你看一看我写的一个。
[code:1:3a3c14c3ac]
int strcmp1( char *s1,  char *s2)
{
   while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) )
      ;
   return (*s1 - *s2);
}
[/code:1:3a3c14c3ac]
[/quote:3a3c14c3ac]

确实很精炼,不过程序中有错误存在,注意 ++ 的使用。仔细检查一下循环结束时的状态就知道应该怎样修改这个程序了。

其实循环条件还有进一步精简的余地。如下所示,跟上面程序得到的结果完全相同:
[code:1:3a3c14c3ac]
  while ( (*s1++ == *s2++) && *s1 )
    ;
[/code:1:3a3c14c3ac]

 wpf8036328 回复于:2004-03-09 13:28:39
感觉斑竹这个算法和系统的strcmp有点象啊,应该没有什么错把?

 FH 回复于:2004-03-09 13:43:23
[quote:1d78027594="whyglinux"][/quote:1d78027594]
版主的对,你的不对。
慢慢琢磨吧!

 wpf8036328 回复于:2004-03-09 13:46:02
我也试过了,斑竹的确实不错的,呵呵,也挺简洁的,

 FH 回复于:2004-03-09 13:47:26
说句题外话,我一直不太欣赏对strcmp返回码正负值的判断,strcmp针对英文比较好用,但对于双高位中文,会导致中文<英文的结果,因为strcmp是基于char *的而不是unsigned char *。

 whyglinux 回复于:2004-03-09 13:57:44
[quote:0f85c95839="FH"]
版主的对,你的不对。
慢慢琢磨吧![/quote:0f85c95839]

我在上面已经说过了,我对 lenovo 的程序的修改与原程序是完全等价的。他的对,我的就对;他的错,我的就错。

不妨比较一下这两个字符串:"abc" 和 "abd"。看到结果之后,你再说对错。

 BingbingNorth 回复于:2004-03-09 14:08:19
lenovo兄,whyglinux兄,FH兄:
先不讨论中/英文问题,这会增加复杂性,我的主题也不在此。
lenovo的肯定是对的,我不太清楚FH为什么说whyglinux的不对,原因可能是,(*s1++ == *s2++) && *s1 没有对*s2进行判断。但是可以证明,(*s1++ == *s2++) && *s1 和(*s1++ == *s2++) && *s1 &&  *s2是等价的。

 FH 回复于:2004-03-09 14:17:08
版主的程序从返回码>0,==0,<0能知道s1>s2,s1==s2,s1<s2,而另一个不行.
就这么简单!

 seaglexiao 回复于:2004-03-09 14:17:15
[quote:d20f8f5917="BingbingNorth"]可以证明,(*s1++ == *s2++) && *s1 和(*s1++ == *s2++) && *s1 && *s2是等价的[/quote:d20f8f5917]
同意
而且(*s1++ == *s2++) && *s1可以少比较一次

 lenovo 回复于:2004-03-09 14:18:07
[quote:4d0293531f="FH"]说句题外话,我一直不太欣赏对strcmp返回码正负值的判断,strcmp针对英文比较好用,但对于双高位中文,会导致中文<英文的结果,因为strcmp是基于char *的而不是unsigned char *。[/quote:4d0293531f]
当时只是一时兴起,就写了这个。
说老实话,我还没从处理过中文,所以也没
考虑这方面的问题。
我也不知该怎么处理。 :wink:

 FH 回复于:2004-03-09 14:18:53
至于中英文的问题,你比较一下"abc"和"abc中文"就知道其重要性了!

 lenovo 回复于:2004-03-09 14:28:21
[quote:15719bae1c="BingbingNorth"]lenovo兄,whyglinux兄,FH兄:
先不讨论中/英文问题,这会增加复杂性,我的主题也不在此。
lenovo的肯定是对的,我不太清楚FH为什么说whyglinux的不对,原因可能是,(*s1++ == *s2++) && *s1 没有对*s2进行判断。..........[/quote:15719bae1c]
whyglinux 的是先对*s1和*s2比较,然后每个指针++,再判断*s1的值不为空。我的顺序和他的反了一下,先判断*s1和*s2是否为空,然后再判断它们是否相等,再让它们++。
whyglinux  的函数但用strcmp1(""," ")测试时(注意前一个是空字符串,后一个是一个空格),我的运算结果是错误的。

 whyglinux 回复于:2004-03-09 14:30:11
同下

 whyglinux 回复于:2004-03-09 14:44:09
[quote:f0d6d095ef="FH"]版主的程序从返回码>0,==0,<0能知道s1>s2,s1==s2,s1<s2,而另一个不行.
就这么简单![/quote:f0d6d095ef]

FH 老弟:你可能又误会我的意思了。注意:我只是对 while 这一句进行了修改,其它的代码还是不变的。

[color=red:f0d6d095ef][b:f0d6d095ef]请注意:[/b:f0d6d095ef][/color:f0d6d095ef]
我说 lenovo 的代码有错误是有根据的,难道没有人能看出错误之所在吗?能实现“程序从返回码>0,==0,<0能知道s1>s2,s1==s2,s1<s2”这一要求吗?难道非要我具体指出错误后大家才能明白吗?

 BingbingNorth 回复于:2004-03-09 14:51:55
lenovo兄,不是你的错了,而是whyglinux兄的错了,在整个条件为假时,++操作是不能进行的,我也看错了,真抱歉。

 lenovo 回复于:2004-03-09 14:56:16
[quote:f9ebb04b36="BingbingNorth"]lenovo兄,不是你的错了,而是whyglinux兄的错了,在整个条件为假时,++操作是不能进行的,我也看错了,真抱歉。[/quote:f9ebb04b36]
没什么了,这样讨论才能让我们学习的更快。

 whyglinux 回复于:2004-03-09 15:16:51
[quote:e085fa2448="lenovo"]
whyglinux 的是先对*s1和*s2比较,然后每个指针++,再判断*s1的值不为空。[/quote:e085fa2448]
兼答
[quote:e085fa2448="BingbingNorth"]
 lenovo兄,不是你的错了,而是whyglinux兄的错了,在整个条件为假时,[color=red:e085fa2448]++操作是不能进行的[/color:e085fa2448],我也看错了,真抱歉。
[/quote:e085fa2448]

哈哈,越来越热闹了,大家加油!

你上面的分析不正确。while ( (*s1++ == *s2++) && *s1 ) 这一句中 (*s1++ == *s2++) && *s1 是一个表达式,它是这样执行的:(1) 求表达式的值,即 (*s1 == *s2) && *s1进行计算,得到这个表达式的值,while就是用这个值作为判断条件的;(2) s1++; s2++; 完成对变量s1和s2的加1赋值。 可见应该解释成“先对*s1和*s2比较,[color=red:e085fa2448]再判断*s1的值不为空,然后每个指针++[/color:e085fa2448]”才对。

我已经说过,我修改之后和你的程序的功能是完全一致的。只不过我这样修改之后问题暴露得明显些,而你的程序中的错误更加荫蔽罢了。

 lenovo 回复于:2004-03-09 15:25:07
[quote:f04983a5f0="whyglinux"]辈哦浴?

我已经说过,我修改之后和你的程序的功能是完全一致的。只不过我这样修改之后问题暴露得明显些,而你的程序中的错误更加荫蔽罢了。[/quote:f04983a5f0]
我认为你的理解是错误的。
对于&&运算符,先计算左边的值,在左边的值为真时,再计算右边的值。
这就是&&的副作用,而我们的程序正是利用了它的副作用。在计算右边的
值时已经++了。
还有strcmp1(""," ")你测试了吗?

 whyglinux 回复于:2004-03-09 15:45:27
[quote:b5cf7b6cbb="lenovo"]
我认为你的理解是错误的。
对于&&运算符,先计算左边的值,在左边的值为真时,再计算右边的值。
这就是&&的副作用,而我们的程序正是利用了它的副作用。在计算右边的
值时已经++了。
[/quote:b5cf7b6cbb]
正是由于你的这种错误的理解,才产生了错误。是的,当到了字符串结尾标志'\0'时,(*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) 中 (*s1 != '\0') 或 (*s2 != '\0') 为假,(*s1++ == *s2++) 不再被计算。但这不是说 s1++和 s2++也不执行。你自己可以测试一下这种情况。

对strcmp1(""," ")的测试得不到预期的结果是因为你程序中有错误,把错误改正之后我和你的程序才能运行正确。

不相信自己的程序有错误?请你测试 strcmp1( "abc", "abd" )。

 lenovo 回复于:2004-03-09 16:15:24
[quote:0a424d12bd="whyglinux"]
正是由于你的这种错误的理解,才产生了错误。是的,当到了字符串结尾标志'\0'时,(*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) 中 (*s1 != '\0') 或 (*s2 != '\0') 为假,(*s1++ == *s2++) 不再被计算。但?.........[/quote:0a424d12bd]
我测试了,我的错了!
谢谢你的指教。
不过对你的有些说法有些不同。
你的意思是说(*s1 != '\0') 或 (*s2 != '\0')为假的话,++还是要执行的是不是?不知我这样理解对不对。
那你说下面这段代码的输出是什么。
[code:1:0a424d12bd]
#include <stdio.h>

int 
main(void)
{
int a = 1;
int b = 2;
if ( (a != 1) && (b != 2) && a++ && b++);
printf("%d,%d\n",a,b);
return 0;
}
[/code:1:0a424d12bd]
执行完后,a,b应为什么值?

 mzpvsww 回复于:2004-03-09 16:31:32
strcmp1(char *p,char *q) 

        while((*p != '\0')&&(*p = *q)) 
        { 
                p++; 
                q++; 
        } 
        if(*p > *q) 
                return(1); 
        else 
                return(-1); 
        if(*p = *q) 
                return(0); 



一错在 if(*p=*q)本来的错,应该是==
二错在没给这个函数前定义int
三就根本不用最后的判断,一个return 0 就够了!

 whyglinux 回复于:2004-03-09 18:49:10
[quote:741debca0e="lenovo"]不过对你的有些说法有些不同。
你的意思是说(*s1 != '\0') 或 (*s2 != '\0')为假的话,++还是要执行的是不是?不知我这样理解对不对。 
[/quote:741debca0e]
我也测试过了,仔细研究了一下,结果发现关于我在上面的“当到了字符串结尾标志'\0'时,(*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) 中 (*s1 != '\0') 或 (*s2 != '\0') 为假,(*s1++ == *s2++) 不再被计算。但这不是说 s1++和 s2++也不执行。”这一描述是[color=red:741debca0e]完全错误[/color:741debca0e]的!即原来我认为的“(*s1 != '\0') 或 (*s2 != '\0')为假的话,++还是要执行的”是错误的,实际上为假的情况下,++是不被执行的。

lenovo 兄弟,非常感谢你指出我的错误。好像不知道从什么时候起我就形成了以上错误概念(汗……)。你的指正,只能用“振聋发聩”来形容对我的感触了。再一次表示感谢!这样跟大家讨论问题真有意思,很有收获!

既然这样,那么我把你程序中的 while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) ) 这一句改为 while ( (*s1++ == *s2++) && *s1 ) 之后,两个程序在功能上就不是完全一致或者等价的了。而且还存在着 BingbingNorth 指出的“在整个条件为假时,++操作是不能进行的”这一问题(BingbingNorth:我对你的正确说法妄加否定,也同时向你道歉)。

那么请大家思考,如果用我(whyglinux)和lenovo提出的思路来写这个程序,应该分别怎样实现呢?请把你的代码贴出来让大家评论。

 lenovo 回复于:2004-03-09 19:44:21
[quote:fda3db497d="whyglinux"]模〖丛次胰衔摹?*s1 != '\0') 或 (*s2 != '\0')为假的话,++还是要执行的”是错误的,实际上为假的情况下,++是不被执行的。

lenovo 兄弟,非常感谢你指出我的错误。好像不知道从什么时候起我就形成了以上错..........[/quote:fda3db497d]
whyglinux太谦虚了,我只测试了一些特殊情况,
没想到最普通的情况都不行,惭愧。
我把我的代码改了一下,不知行不行。
[code:1:fda3db497d]
int strcmp1( char *s1,  char *s2)
{

while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) ) 

    ;
    if( (*s1 == '\0') && (*s2 == '\0') )
return (*(--s1) - *(--s2));
else
return (*s1 - *s2);
}
[/code:1:fda3db497d]

 whyglinux 回复于:2004-03-09 21:46:56
[quote:6229e84a1c="lenovo"]
我把我的代码改了一下,不知行不行。
[code:1:6229e84a1c]
int strcmp1( char *s1,  char *s2)
{
   
   while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) )

    ;
    if( (*s1 == '\0') && (*s2 == '\0') )
      return (*(--s1) - *(--s2));
   else
      return (*s1 - *s2);
}
[/code:1:6229e84a1c]
[/quote:6229e84a1c]
直接看你的代码,一时不好说对错。让我按照你的思路换个角度来分析一下吧。

循环结束的条件就是:*s1为0 或者 *s2为0 或者 进行比较的两个字符 *s1和 *s2不同,用C语言表达式来表示就是:(*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++),这应该没有任何问题。问题表现在:循环结束时,++操作能否得到执行,这牵涉到最后“s1、s2是否指向应该被比较的字符本身亦或是指向应被比较字符的下一个字符”这一问题。程序的返回的时候应该能处理这两种情况。
由上可知,根据++操作能否得到执行,又分成了两种情况。那么,++操作得到执行的条件是什么呢?从这个表达式 (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) 来看,是表达式 (*s1 != '\0') && (*s2 != '\0') 的值为真;相反,++操作得不到执行的条件是 !(  (*s1 != '\0') && (*s2 != '\0') ),也即对上面的条件取反。继续进行逻辑转换:!(  (*s1 != '\0') && (*s2 != '\0') ) [color=red:6229e84a1c]=>[/color:6229e84a1c] !(*s1 != '\0') || !(*s2 != '\0') ) [color=red:6229e84a1c]=>[/color:6229e84a1c] (*s1 == '\0') || (*s2 == '\0')。

现在很清楚了,从上面的分析上来看似乎应该这样写才正确:
[code:1:6229e84a1c]
int strcmp1( char *s1,  char *s2)
{
   while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) )
    ;
  if ( (*s1 != '\0') && (*s2 != '\0') ) // 最后自加,s1、s2各多加 1
    return *(s1 - 1) - *(s2 - 1); // 比 *(--s1) - *(--s2) 少两次赋值运算
  else  // 自加运算没有被执行,s1和s2指向的是应该进行比较的字符
    return *s1 - *s2;
}
[/code:1:6229e84a1c]

 lenovo 回复于:2004-03-09 22:01:28
[quote:8ef5bde00c="whyglinux"][/quote:8ef5bde00c]
whyglinux兄,你的代码我用
strcmp1("adb", "adc");
做测试,是相等。

 whyglinux 回复于:2004-03-10 00:21:50
是的,我刚才对你的程序的修改还是不对。如果用 while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) ) 来作循环的话,最后s1和s2指向的字符位置不固定,不一定就是我们要进行比较的字符。刚才认真考虑了一下,我发现一个问题是:竟然[color=red:c6cb5de4a0]没有一种简单的方法来判断循环结束后++操作是否得到执行[/color:c6cb5de4a0]!是的,我刚才提出根据 (*s1 != '\0') && (*s2 != '\0') 这一条件来判定,但是当用到这一条件的时候,s1和s2可能已经自加了,所以又要求我们判断s1、s2是否已经自加,而这正是我们想知道的。所以不能根据 (*s1 != '\0') && (*s2 != '\0') 来判断。

我的结论是:[color=red:c6cb5de4a0]如果用 while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) ) 作为循环,是无法正确写出这个程序的![/color:c6cb5de4a0]

++运算导致的危害,以此例为最(不仅仅是错了,连改都无从改起)。

 lenovo 回复于:2004-03-10 09:27:50
[quote:af7c35293f="whyglinux"]

++运算导致的危害,以此例为最(不仅仅是错了,连改都无从改起)。[/quote:af7c35293f]
我说说我的看法。
字符串有两种情况,

一种是它们的长度相等。
在这种情况下,s1和s2最后都指向它们的最后,也就是'\0'字符。
所以我们要--来让它们指向实际的最后一个字符,相减做比较。

一种情况是它们的长度不等。
在这种情况下,或s1指向'\0',或s2指向'\0',两个不会同时指向'\0'。
如果s1指向'\0',s2不指向'\0',则*s1-*s2一定小于0。正确。
如果s1不指向'\0',s2指向'\0',则*s1-*s2一定大于0。正确。
欢迎whyglinux兄指出错误。

 lenovo 回复于:2004-03-10 09:33:09
[quote:62df74ad8b="lenovo"]
我说说我的看法。
字符串有两种情况,

一种是它们的长度相等。
在这种情况下,s1和s2最后都指向它们的最后,也就是'\0'字符。
所以我们要--来让它们指向实际的最后一个字符,相减做比较。

一种情况是它们?.........[/quote:62df74ad8b]

偶不用说了,偶又发现偶代码的bug了。
唉,bug太多。 :oops: 
whyglinux兄你是对了。看来只有推倒重来了。

 BingbingNorth 回复于:2004-03-10 09:43:13
whyglinux兄不必客气。
我先说明一下我一直没有发现lenovo错误的原因:
我把他的程序跟我的程序
[code:1:c66b4b004a]while ( (*str1 != '\0') && (*str2 != '\0') && (*str1 == *str2) )
{
str1++;
str2++;
}[/code:1:c66b4b004a]误认为等价了,因此在测试中没有用lenovo的程序,而是用我写的程序测试的,虽然我做了好几种情况的测试,还是没有测出问题来。
我原来是写pascal程序的,*str1++ = *str2++;这种写法我一般不用,因此我自己写的程序很少出错:)。
其实大家存在的问题很好解决,只要把++放在循环体中即可。

 whyglinux 回复于:2004-03-10 13:19:09
非常赞同BingbingNorth的观点,即一般不要用*str1++ = *str2++;这种形式。为了消除++运算的负作用对程序的不良影响,书写代码的时候应该注意要把++运算作为一个单独的语句使用,而不要把它混同于表达式中,这样其影响只局限于其本身所在的这一语句,对其它表达式语句没有不良影响。

我刚才分析了用  while ( (*s1 != '\0') && (*s2 != '\0') && (*s1++ == *s2++) ) 作为循环是不能正确地写出strcmp1的。如果把 (*s1++ == *s2++)放到条件表达式的左端的话,不存在漏掉执行++的情况,这时程序还是可以写出来的。用我的思路可写成如下程序:
[code:1:3a8b2e381b]
int strcmp1( char *s1,  char *s2 ) 

  while ( (*s1++ == *s2++) && *(s1 - 1) )
    ; 
  return *(s1 - 1) - *(s2 - 1);
}
[/code:1:3a8b2e381b]
优点是条件语句中少用一个条件判断,缺点是由于++的负作用,不得不多做一步指针减法运算:s1 - 1。

当然,对这个题目最好如BingbingNorth之处的那样把++同条件表达式分开。应该写成下面的程序:
[code:1:3a8b2e381b]

  while ( (*s1 == *s2) && *s1 ) {
    s1++;  // 也可以是 ++s1;
    s2++;  // 这两个++语句也可以写成一个:s1++, s2++; 因为它们两个之间没有相互影响
  }
  return *s1 - *s2;
}
[/code:1:3a8b2e381b]
这样写程序思路清晰、代码简洁、执行效率高。

 FH 回复于:2004-03-10 13:26:35
哈哈,越来越完美了。俺也凑个热闹,把最后一句改成:
[code:1:4d0a59e081]return ( (unsigned char) *s1 - (unsigned char) *s2 );[/code:1:4d0a59e081]
这样就更完美了。

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有