分享

第十六讲 指针

 昵称29398856 2016-01-21

      在第十五讲里面我们用一个copy函数来结束,让大家验证的不知道大家有没有验证,这个函数从各方面看起来都总觉得怪怪的,但是似乎该有的功能却还是有的,我之所以说是似乎,大家不要觉得奇怪,因为这真的只是似乎。

-----------------------

char* copy(char* dest, const char* src)
{

      if(dest != NULL && src != NULL)
      {

           memset(dest,'\0',sizeof(dest));  

           while((*dest++ = *src++)!='\0')

                          ;
       }
       return dest;
}

------------------------------

      这是我们昨天定义的函数,从这几句代码里,我们看得出,这个函数是有返回值的,返回值就是传给他的第一个指针。所以我们再来验证一下这个函数的返回值。

------------------------------

       char m_array[20] = 'Hello World';
       char m_array2[25]= 'ni hao ,zhei shi shen me';
       char* m_array3;
       m_array3 = copy(m_array2,m_array);

--------------------------------

       大家是不是觉得m_array3的值和m_array2一样的呢?为了验明正身,我们不妨将结果打印出来看看:

 

      嗯,为什么结果不和想象中的呢?这不是我们想要的啊,我们想要的是m_array2 = m_array3,为什么会有这种奇怪的结果呢?好吧,我们现在再回头来研究一下这个函数。

      现在看来, memset(dest,'\0',sizeof(dest)); 并没有起到真正的作用,干脆把他去掉吧。

      接下来我们看到的是拷贝过程,这个过程是通过while循环来控制的呢,直到遇到src的结尾符'\0'终止,于是我们在这里便得到了为什么我们的m_array2能够得到正确的答案的解释了。但是接下来return dest。不过这时的dest已经不是再最初的那个dest,也不是我们刚才得到的那个dest,这个dest是上面循环用剩下的,那么要怎么才能实现返回的和得到的和我们拷贝的是同一个数据呢?这就是我们这里要说的指针了。

        为什么说指针是C/C++的高阶知识呢?为什么会说C++是面对对象编程中唯一一门在内存上操作的编程语言?他是怎么实现在内存上操作的呢?这就是我们这里所要说的指针,指针就是指向内存块的东东,所以我们要在内存上操作,就得依靠指针。指针既然这么重要,那么我们要就来说一下指针。

        怎么声明一个指针?

        int*  ptr;

        就这么简单,“*”是指针标识符,声明一个指针很简单,和声明一个数据变量没有两样,唯一的不同点就是在变量前添加这个”*“,这样普通变量就变成了该类型的指针。

       int a = 6;

       int *ptr = &a;

       上面的两个声明,第一句声明的是一个变量,第二句是声明一个指针,并且让他指向变量a的地址。

        想要取某个变量的地址,直接在该变量前添加”&“符号即可,所以对变量取地址同样是也相当于获取一个指针。

       大家可以试着用printf('ptr = %p \n.*ptr = %d',ptr,*ptr)看看输出的是什么结果。

       ptr的值根据不同系统会得到不同的值,这就是a所存放的地址,而*ptr却是这个地址里面所存放的数据6。

      说到这里,大家是不是想问,指针和数组有什么关系呢?在copy函数里我们声明的明明是指针,为什么最后却又用数组来作为参数呢?这就是现在我们所要说的。

        上一讲我们说到数组是存放在一连串的内存之中,那么这段内存怎么得到呢?我们是要用像上面那样取地址表示吗?当然可以,但是没有那个必要,因为在数组中,数组名就相当于一个指向这段连续的首地址的指针,所以我们这就是我们为什么用数组名去作为copy函数的参数的原因。

       在这里给大家说一个关系式,大家只要记住这个关系式就能够轻松在数组和指针之间相互转换了:

       array[i]  == *(ptr+i);

      &array[i] == ptr+i;

      这是两个恒等式,如果不明白指针和数组的关系时可以再次来查看这一讲。

      指针说到此处,也差不多了,对昨天我们的copy函数现在是不是已经明了了呢?既然都明白了,现在我们来改进这个函数。我们声明一个指针,然后同样让他指向dest的地址。

        char* get = dest;

        在最后我们返回get的地址就好。

        return get;

-----------------------------

char* copy(char* dest, const char* src)
{

      if((dest == NULL) || (src == NULL))

      {

           printf('参数不能空。');

           return NULL;

       }

       char* get = dest;  
       while((*dest++ = *src++)!='\0')
                ;
        return get;
}

--------------------------------

       现在我们同样用昨天的main()来调试这个函数,发现没问题了,m_array2 和 m_array3的结果相同了,我们多试试几个都没问题,这是不是表示已经完美了呢?可以直接代替strcpy()了呢?当然能不能我们不知道,但是从我们目前的测试中可以看出,基本的功能已经满足了,那我们还在怀疑什么呢?

       我们再来看看这个函数,他似乎遗漏了一个问题,当然这个问题通常都是我们会回避的,但回避就不代表真正的解决问题了,这个问题便是如果这两个指针都同时指向一块内存块呢?那岂不是糟糕了呢?如同下面一样:

       copy(m_array+1,m_array);

       当我们执行这句代码时,程序崩溃了。我们在用string.h里面的strcpy来试试:

      strcpy(m_array1+1,m_array);

      再执行程序,发现毫无问题,既然这个函数没问题,那么有问题的就是我们自定义的copy()函数了, 哎,看来想要编程真不是一件简单的事啊,很多人都以为这是strcpy的伪代码,但是他们都忽略了一个问题,重复内存的拷贝。

       那么怎么实现重叠内存的拷贝呢?我们再来定义一个函数:memcopy();

------------------------------------

char* memcopy(char* dest,const char* src)

{

      if((dest == NULL) || (src == NULL))

      {

           printf('无效参数。');

           return NULL;

       }

       char*  get = dest;

       int len = strlen(src)+1;

       if(dest <= src="" ||="" dest="">= (src+len))

       {

              while(len--)

              {

                    *dest = *src;

                     dest++;

                     src++;

              }

       }

       else

       {

                dest = dest + len -1;

                src = src + len -1;

                while(len--)

                {

                         *dest = *src;

                         dest--;

                         src--;

                }

       }

      return get;

}

----------------------------------------------

      然后我们在copy里面调用上面的memcopy函数:

------------------------------

char* copy(char* dest, const char* src)
{

      if((dest == NULL) || (src == NULL))

      {

           printf('参数不能空。');

           return NULL;

       }

       char* get = dest;  
       memcopy(dest,src);

       return get;
}

------------------------------------ 

        这似乎看上去才有些像strcpy()伪码,但是到底是与不是还得靠大家去验证,因为今天太晚了,我也没验证他的可行性,改天有时间我亲自验证一下是否可行,如果有误,大家请注意后续内容,一般会在下一讲会纠正,今天再不推送就浪费次数了。

 

====================

回复D&d直接查看目录,通知一下,春节不推送,节后继续。

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多