帮我看下这段小程序(10分)

  • 主题发起人 主题发起人 小唐
  • 开始时间 开始时间

小唐

Unregistered / Unconfirmed
GUEST, unregistred user!
下面这段程序看了很久也不太清楚它的运作,
请帮忙解释一下它是如何工作的,越详细越好
char *strrev(char *string)
{
char *original=string;
char *forward=string;
char temp;
while (*string)
string++;
while (forward<string)
{
temp=*(--string);
*string=*forward;
*forward++=temp;
}
return(original);
}
 
其主要功能是将字符串倒过来!
char *strrev(char *string)
{
char *original=string;
// 将string 首地址赋给 original
char *forward=string;
// 将string 首地址赋给 forward
// 注意:此时original 与 forward都是指字符串第一个字符
char temp;
// 临时变量
while (*string) // 这个循环的作用是找到字符串String的未地址(即最后一个字符)
string++;
// 注意:循环结束后,变量string已经指向字符串的最后一个字符
while (forward<string) // 这个循环的作用是:开始将字符串倒序!当字符串到第一个字符时结束
{ // 注意此时: 一开始forward 指向字符串的第一个字符;string指向最后一个字符
temp=*(--string);
// 通过string由后向前取字符,并放入临时变量temp中
*string=*forward;
// 把forward 指向的字符放入 string指向的位置(此时string指向的字符已经放在temp变量中了)
*forward++=temp;
// 再把temp变量中的字符(其实就是原来string指向的字符)
}
return(original);
// 将倒序过的字符串返回
}
//理解整个程序时要注意 字符指针 - string ,它是不断在变化的,所以一开始才把它保存下来(保存为original 和 forward)
不知这么讲明白没有?
 
lixx:
很感谢你的帮助,通过你的注解我稍微明白了一些,不过还是有些模糊。
我以字符串“ABCD”来讲讲我的理解,不对的地方请指教。
char *strrev(char *string)
{
char *original=string;
char *forward=string;
char temp;
while (*string)
string++;
//不知这个循环结束后,对于字符串“ABCD”而言,
              //string是等于多少,我觉得应该是4,我的理解是string的计数还
              //包括了“ABCD”最后一个字母“D”后的“NULL”,所以我
              //觉得应该是4,不知对否,请指教
while (forward<string) //forward=0,string=4,条件成立,进入循环
{ //以下是我对第一遍循环的理解,请指教
temp=*(--string);
//第一遍循环时,首先将指针string由指向“ABCD”最后的“NULL”
              //向左移动一个单位(--string)从而指向“ABCD”字符串中的“D”
              //并把指向的“D”字符赋给temp
*string=*forward;
//将“ABCD”中的“A”复制到“D”的位置,导致*string原先的值被覆盖
              //不过不要紧,*string原先的值已经保存到temp中了
*forward++=temp;
//将“ABCD”中的“D”复制到“A”的位置,
              //然后将指针forward加1,指向“ABCD”的“B”处,
              //为第二遍循环做好准备
//第一次循环结束后,“ABCD”变成了“DBCA”
}
return(original);
//返回指向调整好后的“DCBA”的首字符“D”的指针
}
/* 另外,对于循环的次数,我有疑问,我想对于字符串“ABCD”,应该是循环2次。
  不知对不对,我的理由是:
  在没有进入循环时,while (forward<string)即forward=0,string=4
  在第一遍循环中,forward由0变为了1,string由4变为了3,1<3,条件成立,进入第二遍循环,
  在第二遍循环中,forward由1变为了2,string由3变为了2,2<2,条件不成立,退出循环
  不知是不是这样,请指教。
  
  假如不是“ABCD”,而是“ABC”,则也会循环两遍,
  不过第二次的循环是多余的,不知我的理解对不对,请指教。
*/
 
你的理解好像是有点问题。
注意:string是一个字符指针,它的值是个地址!!
所以这个你理解不了的话,下面你的理解就都有问题了:-(
根本不存在第几遍循环的问题,只是从头到尾遍历一遍字符串而已
我再强调一遍:string 是个字符指针!!!!
不是1234之类的计数。
另外只有当字符指针到头时,循环才会退出的。
 
lixx:
谢谢。
  “string是一个字符指针,它的值是个地址!!”这个我知道,前面只不过是为了
说明方便而用数字代表特定的内存地址而已,不然说明起来也太麻烦了。
  “根本不存在第几遍循环的问题,只是从头到尾遍历一遍字符串而已”,我想应该
具体情况具体对待。像
while (*string)
string++;

这样的循环,是符合你说的情况的,研究它循环了多少遍确实没有多大意义。
但是像:
while (forward<string)
这样的循环,我们研究一下它倒底循环多少次,我想,对于学习和提高是有很大好处的。
除了以上两点,你还没有正面答复我的问题,还请你再不吝赐教。
 
刚才在TC下测试了一下,觉得自己的分析是对的:
#include <stdio.h>
char *strre(char *string)
{
char *original =string;
char *forward=string;
char temp;
int i=0,j=0;
while (*string)
{
string++;
printf("/nstring=%d",i++);
}
while (forward<string)
{
temp=*(--string);
printf("/n%d,*(--string)=%c",++j,temp);
*string=*forward;
*forward++=temp;
}
return(original);
}

void main(void)
{
printf("/n%s",strre("abcdefghijklmnopqrstuvwxyz"));
}
 
看了半天,这么难读的程序,
改了一下,不知对不对,没调试。
char *strrev(char *string)
{
char *original=string;
char *forward=string;
char temp;
while (*string)
string++;
forward--;
while ((++forward)<(--string))
{
temp=*string;
*string=*forward;
*forward=temp;
}
return(original);
}
 
testnet:
我刚才试了一下你改的程序,顺利通过。
你改的程序条理更加清晰,好好学习!
只是有点弄不明白:
  forward--;
  这一句有何用意呢?
 
我想testnet兄这两句:
forward--;
while ((++forward)<(--string))
{
可以使字符串长度为奇数的时候省去一次多余的循环.
如"ABC"就只会循环一次了.不知我说的对不对.
 
kazema:
  我想你说得对。
  还有,我将这段代码:
forward--;
while ((++forward)<(--string))
{
改为:
// forward--;
while ((forward++)<(--string))
{
为何得到的结果会出现首尾两字符错而中间的结果却是正确的,这真是搞不懂。
 
小唐:
如字符串“ABCDE”;
因为forward原先指向的是'A';
while ((forward++)<(--string))
{
执行上面语句后forward指向'B';string则指向'E';
所以把BE互换了。也就是说这样把字符串的头两个字符换到一头一尾。
然后中间的倒置。 所以forward--;是必须的,这句先把forward移到'A'前面一个地址。
而string又在最后一个字符后一个地址。然后逐步逼近。把字符串倒置了。
比如把代码改成下面这样子。也是一样的。
char *strrev(char *string)
{
char *original=string;
char *forward=string;
char temp;
while (*string)
string++;
string--;
while (forward<string)
{
temp=*string;
*string--=*forward;
*forward++=temp;
}
return(original);
}
 
while (*string)
string++;
白用了一次循环,strlen就可以
 
kazema:
  我想我主要是对++运算符没有理解清楚。我以为
while ((forward++)<(--string))
上面这句中的forward++在第一次比较时不会先加1而是用原来的forward,
我这样理解主要是受了printf("%d",forward++)这样的语句的影响,
如:
#include <stdio.h>
void main(void)
{
int forward=0;
while (i<10)
printf("/ni=%d",forward++);
}
第一次printf显示的forward的值是0,第二次printf才显示的是1,
我以为while语句中也是这样,第二次循环时才将forward加1,
看来forward++在printf和while中是不同的。是这样吗?
 
几天没来,大家讨论的这么热闹了:-)
说实话,我认为原来的程序给的是最清晰易懂的(先不考虑效率问题)
while ((forward++)<(--string))
像这种紧凑型的语句,一般来讲是不提倡的,因为你有时搞不清楚优先级
(到底是先算左边还是先算右边,我时间久了,很有可能忘记了)
现在写程序 (1)功能要达到(2)要易懂,易维护(3)效率
当然如果仅仅是为了学习好玩,搞一些晦涩语句研究研究,也未尝不可。
但这对今后的开发没有多少好处。
说的不对的地方还请原谅。
 
dz2050:
strlen实际上也是执行的一个O(N)的循环.况且这样还要一个函数调用.
未必比直接用循环来得有效率.
小唐:
是这样的:
while ((forward++)<(--string))
//在这里先是用forward值进行判断.然后才自加1;

{
............
//当程序执行到循环里面的时候.forward已经自加过了.
//也就是说++符号已经起作用了.
}
我想你是误解了++要在循环结束后才起作用.实际上不是的.
forward++的含义是这个表达式的值先取forward的值.随后forward就自加一.
这是个符号优先级的问题.而++forward就是先让forward自加再让整个表达式取forward的值
也就是先执行++运算符再取这个表达式经过运算后的值.
这是C语言的一个比较酶涩的地方.C语言就是太灵活了.搞得常常写出来的程序语意不严谨.
灵活好是好. 就是常常错误都难找.这点PASCAL就好多了.当然.各种语言自有其独到之处嘛.
不过学C语言牛角尖少钻.得尽量避免用复杂的表达式和奇怪的变量名.不然不但别人可能看不懂.
出了错自己也难找.正如lixx所说.我一开始也是没少吃苦头:)
lixx:
兄台说的是. 写程序不是编天书.程序的风格也是很重要的.
不过有时稍为深究一下下也没坏处嘛.只要不要钻牛角尖便行:)
 
谢谢各位,特别感谢dazema,你的恰到好处的解答解决了我心中的疑惑,使我走出了++的误区。
本来发这个贴,并没有抱多大的希望,想不到得到了大家的热情解答,真让我感动。
以后肯定还会遇到这样或那样的问题,到时还请朋友们再次伸出援手。
这个贴只准备了10分,现在想想也太少了。真对不住大家。我再开一贴请在此贴发言的朋友领分。
 
strlen是汇编写的,应该快一点
 
后退
顶部