是小利同学 发表于 2023-6-4 23:29:02

s1++ == *s2++和*dst++ = *src++ 指针移动问题

本帖最后由 是小利同学 于 2023-6-4 23:30 编辑

{:10_254:}求助鱼友答疑

【先欣赏张美图,静静心!】{:10_288:}




在自定义字符串处理函数时遇到一些困难!!

【话不多说先上代码】{:10_256:}

【1.自定义比较字符串函数 mycmp()】

#include<stdio.h>
#include<string.h>

int mycmp1(const char* s1,const char* s2);
int mycmp2(const char* s1,const char* s2);

int main(int argc,char const *argv[]){
         char s1[] = "abc";
         char s2[] = "Abc";
      
      printf("mycmp1(s1,s2) = %d\n",mycmp1(s1,s2));
      printf("mycmp2(s1,s2) = %d\n",mycmp2(s1,s2));
      return 0;
      
}
/*
      @@自定义比较字符串函数 mycmp()
                mycmp1()数组的方式实现
                mycmp2() 指针的方式实现
      @比较两个字符串大小
                1.若s1等于s2,若字符串长度相等,且每一个字符都对应相等,则返回0
                2.若s1大于s2,依次比较s1s2的每个字符,若存在s1的字符>s2的字符,且是第一次出现,返回这两个字符的差值(正数 ) ,结束比较
                3若s1小于s2,依次比较s1s2的每个字符,若存在s1的字符<s2的字符,且是第一次出现,返回这两个字符的差值(负数) ,结束比较
      
*/
int mycmp1(const char* s1,const char* s2){
      int index = 0;
      while(s1 == s2 && s1 != '\0'){
                index++;
      }
      return s1 - s2;
}

int mycmp2(const char* s1,const char* s2){
      while(*s1 == *s2 && *s1 != '\0'){
                s1++;
                s2++;
      }
      return *s1 - *s2;
}
/**
      @为什么循环不能写成while(*s1++ == *s2++ && *s1 != '\0'); 为什么呢?
      ->我的猜想如下:
         1.首先,s1++ == *s2++是一个判断语句,因为这时s1++、s2++只是做判断使用,没有赋值给新的指针保存,并没有真正的移动指针,
         所以无论s1,s2如何自增自减,s1,s2还是指向原来的地址
      (ps:我感觉这时的s1++或者s1--;和s1+1,s1-1效果一样(而不是s1 = s1 + 1;),只是借助s1,读了s1的下一位,并没有移动s1的指向)
*/
【问题1】
   1.上述代码中,为什么while循环不能写成while(*s1++ == *s2++ && *s1 != '\0'); 为什么呢?(ps:代码中有我的猜测,请指出错误)


【2.自定函数mycpy()复制字符串】

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char *mycpy1(char* dst,const char* src);
char *mycpy2(char* dst,const char* src);

int main(int argc,char const *argv[]){
      char src[] = "Hello world!";
      char *dst = (char*)malloc(strlen(src)+1);//sizeof(char)*sizeof(src)

      printf("mycpy1(dst,src) = %s\n",mycpy1(dst,src));
      printf("mycpy2(dst,src) = %s\n",mycpy2(dst,src));
         
      return 0;
}
/**
      @自定函数
                mycpy(),复制字符串
                mycpy1()数组的方式实现
                mycpy2() 指针的方式实现
*/
char *mycpy1(char* dst,const char* src){
      int inx = 0 ;
      while(src){//src != '\0'
               dst = src;
               inx++;
      }
      dst = '\0';//dst = src;
      
      return dst;
}
char *mycpy2(char* dst,const char* src){
      char * ret = dst;
      
      while(*dst++ = *src++);
      *dst = '\0';//*dst = *src
      
      return ret;
}
/**
      @这里 *dst++ = *src++ 指针为什么又可以通过 自增自减 来移动指针?
         我的猜想如下:
         1、 首先,*dst++ = *src++ 这是一个赋值运算,先看指针src自增并取值后,赋值给了*dst,正是因为赋值运算,使得指针src可以移动
         2、而*dst++,显然这一个可以运算的式子,但同时它也是一个左值,是一个变量,正因为如此,使得指dst的自增运算可以被变量保存
      (ps:我感觉这时的指针dst或着指针src可以自增,关键在于有了个左值,以及赋值运算符,保存了指针的自增)
*/

/**      
      @@mycpy2() 指针的方式实现,三种不同的循环写法
      @1
      while(*src != '\0'){
               *dst = *src;
               dst++;
               src++;
      }
      @2
      while(*src){
               *dst++ = *src++;
      }
      @3
      while(*dst++ = *src++);
*/

【问题2】
2.上述代码中,@这里 *dst++ = *src++ 指针为什么又可以通过 自增自减 来移动指针? 为什么呢?(ps:代码中有我的猜测,请指出错误)

【3.@自定函数mycat()复制字符串】

#include<stdio.h>
#include<string.h>

char * mycat1(char *dst,const char *src);
char * mycat2(char *dst,const char *src);

int main(int argc,char const *argv[]){
      char dst[] = "Hello ";
      char src[] = "world!";
      
//      printf("mycat1(dst,src) = %s\n",mycat1(dst,src));
      printf("mycat2(dst,src) = %s\n",mycat2(dst,src));
      return 0;
}
/**
      @自定函数
                mycat(),复制字符串
                mycat1()数组的方式实现
                mycat2() 指针的方式实现
*/
char * mycat1(char *dst,const char *src){
      int inx = 0;
      
      int dstlen = strlen(dst);
      while(src != '\0'){      
                dst = src;
                inx++;      
      }
      dst = '\0';
      return dst;      
}

char * mycat2(char *dst,const char *src){
      char *ret = dst;
      dst = dst + strlen(dst);
      while(*dst++ = *src++);
      *dst = '\0';
      return ret;      
}

【问题3】
3.上述几个程序中有相同的代码while(*dst++ = *src++); *dst = '\0';这里想问该while(*dst++ = *src++);循环最后一次是否将*dst赋值 '\0' ?下面一行的*dst = '\0';是否多余?


期待各位鱼友和大佬们的解答,感谢!{:10_298:}



是小利同学 发表于 2023-6-7 15:05:13

本帖最后由 是小利同学 于 2023-6-7 15:14 编辑

1.为什么循环不能写成while(*s1++ == *s2++ && *s1 != '\0'); 为什么呢?
int mycmp2(const char* s1,const char* s2){
      while(*s1 == *s2 && *s1 != '\0'){
                s1++;
                s2++;
      }
      return *s1 - *s2;
}
int mycmp3(const char* s1,const char* s2){
      while(*s1++ == *s2++ && *(s1-1) != '\0');
      return *(s1-1) - *(s2-1);      //*--s1 - *--s2
}
      1.当然可以写成这样,不过需要给动一下-> while(*s1++ == *s2++ && *(s1-1) != '\0');
                2.*s1++ == *s2++,每次比较结束后指针自增(指向后移),
                当判断到最后一位'\0'时,*(s1-1) != '\0',这是s1指向的'\0'后面的字符,故要-1令其指向'\0'
                3.故当比较结束返回的时候,我们需要对s1,s2前移减一,让指针指向正确的值 如:mycmp3()      
                                                                                                      
2.这里 *dst++ = *src++ 指针为什么又可以通过 自增自减 来移动指针? 为什么呢?
char *mycpy2(char* dst,const char* src){
char * ret = dst;
while(*dst++ = *src++);
return ret;
}
         1.无论 *s1++ == *s2++ 还是 *dst++ = *src++ 都可以移动指针
      2.但要注意自增自减的指针是否指向了预想的地址。
      3.*dst++在while做循环条件时要特别注意:即使条件不满足也会进行自增,这是当我们还要用这个指针时做其他事情时就要判断指针的指向问题(一般需要自减)

3.while(*dst++ = *src++);循环结束指针的指向问题
char * mycat2(char *dst,const char *src){
      char *ret = dst;
      dst = dst + strlen(dst);    //det->'\0'
      while(*dst++ = *src++);
      return ret;      
}
      1.首先声明++的优先级高于*,虽然是是dst++,但取值*是++之前的地址
      2.循环条件一次执行的顺序:src自增,dst自增 -> 然后把src自增之前指向的位置取值*,赋值给dst自增之前指向的位置
            -> 判断dst自增之前的向的位置的值是否为 '\0'
         3.显然,易知src代表的那个字符串最后一位'\0'一定会赋值在dst代表那个字符串最后一位,为什么?因为当while判断'\0'循环才会退出
         4.这时当循环退出时,src,dst都已经自增, src指向src那个字符串'\0'的后面一位,dst指向dst那个字符串'\0'的后面一位
          5.这时我们发现 src,dst 这两个字符串的指针都已经越界访问了,所以*dst = '\0';时是多余的,或着说是不必要的


{:10_256:}{:10_256:}{:10_256:}

歌者文明清理员 发表于 2023-6-4 23:29:03

是小利同学 发表于 2023-6-4 23:33
你为什么回答的这么快,是不是用了什么”高科技“

手动回答,chat2.jinshutuan.com

歌者文明清理员 发表于 2023-6-4 23:30:50

【问题1】
循环不能写成 while(*s1++ == *s2++ && *s1 != '\0'),因为这个循环会导致指针 s1 和 s2 在判断完毕之后,再分别自增一次,这就导致了 s1 和 s2 指向了下一个字符,但根据逻辑,在只判断字符是否相同时,指针不应该向后移动,否则有可能错过比较。因此,正确的循环写法是 while (*s1 == *s2 && *s1 != '\0') { s1++; s2++; }。

【问题2】
在语句 *dst++ = *src++ 中,先执行取 src 指针所指向的值 *src,赋值给 dst 指针所指向的地址 *dst,然后再让指针 dst 和 src 分别自增一次。因此,整个语句的作用是把 src 所指向的字符串中的每一个字符依次复制到 dst 所指向的字符串中,并通过指针操作完成字符串的移动。

【问题3】
循环 while (*dst++ = *src++) 最后一次执行时,仍然会把 src 指针所指向的值复制到 dst 指针所指向的地址,但此时已经是字符串结束符 '\0',因此会把 '\0' 复制到 dst 所指向的字符串的最后一位,从而保证 dst 所指向的字符串以 '\0' 结尾。因此,*dst = '\0' 是多余的。

是小利同学 发表于 2023-6-4 23:33:22

歌者文明清理员 发表于 2023-6-4 23:30
【问题1】
循环不能写成 while(*s1++ == *s2++ && *s1 != '\0'),因为这个循环会导致指针 s1 和 s2 在判断 ...

你为什么回答的这么快,是不是用了什么”高科技“{:10_275:}

isdkz 发表于 2023-6-4 23:39:04

【问题1】
   上述代码中,为什么while循环不能写成while(*s1++ == *s2++ && *s1 != '\0'); 为什么呢?

你的理解是正确的。 s1++和s2++这两个操作并不仅仅是比较,它们同时会改变指针的位置。因此, *s1++ == *s2++会比较两个字符,并将指针向后移动。之后的*s1 != '\0'是在比较移动后的字符,而非原本要比较的字符,因此不会得到期望的结果。

【问题2】
2.上述代码中,@这里 *dst++ = *src++ 指针为什么又可以通过 自增自减 来移动指针? 为什么呢?

在 C 中, *dst++ = *src++语句的含义是先将*src的值赋给*dst ,然后dst和src都向后移动一位。这里的++操作符改变了指针的位置。所以在这种情况下, ++是用于移动指针的。

你的猜想是正确的,这个操作中, *dst++ = *src++既是一个赋值运算,又是一个移动指针的操作。

【问题3】
3.上述几个程序中有相同的代码while(*dst++ = *src++); *dst = '\0';这里想问该while(*dst++ = *src++);循环最后一次是否将*dst赋值 '\0' ?下面一行的*dst = '\0';是否多余?

while(*dst++ = *src++)这个循环将src字符串中的字符逐个复制到dst中,直到遇到src的末尾标志 '\0',然后停止。当src遇到 '\0' 时, *src为 '\0',这个 '\0' 也会被赋值给*dst ,但随后dst自增,使得dst指向了字符串的下一个位置,即原dst字符串的 '\0' 位置。所以*dst = '\0'这一行并不多余,它确保了dst字符串的结束标志。

总结,你的理解是基本准确的,继续学习C语言,你将对这些概念有更深入的理解。

不二如是 发表于 2023-6-5 09:39:27

配图用的好

是小利同学 发表于 2023-6-7 15:10:16

编辑测试帖

是小利同学 发表于 2023-6-7 15:23:17

歌者文明清理员 发表于 2023-6-4 23:29
手动回答,chat2.jinshutuan.com

不错不错,不过回答不是我最想要的答案{:10_266:}
不过问题我已经解决,看我顶置贴{:10_265:}

是小利同学 发表于 2023-6-7 15:24:11

isdkz 发表于 2023-6-4 23:39
【问题1】
   上述代码中,为什么while循环不能写成while(*s1++ == *s2++ && *s1 != '\0'); 为什么呢?

...

问题已经解决,感谢解答{:10_256:}
页: [1]
查看完整版本: s1++ == *s2++和*dst++ = *src++ 指针移动问题