在第十五讲里面我们用一个copy函数来结束,让大家验证的不知道大家有没有验证,这个函数从各方面看起来都总觉得怪怪的,但是似乎该有的功能却还是有的,我之所以说是似乎,大家不要觉得奇怪,因为这真的只是似乎。 ----------------------- char* copy(char* dest, const char* src) memset(dest,'\0',sizeof(dest)); while((*dest++ = *src++)!='\0') ; ------------------------------ 这是我们昨天定义的函数,从这几句代码里,我们看得出,这个函数是有返回值的,返回值就是传给他的第一个指针。所以我们再来验证一下这个函数的返回值。 ------------------------------ char m_array[20] = 'Hello World'; -------------------------------- 大家是不是觉得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; -------------------------------- 现在我们同样用昨天的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; return get; ------------------------------------ 这似乎看上去才有些像strcpy()伪码,但是到底是与不是还得靠大家去验证,因为今天太晚了,我也没验证他的可行性,改天有时间我亲自验证一下是否可行,如果有误,大家请注意后续内容,一般会在下一讲会纠正,今天再不推送就浪费次数了。
==================== 回复D&d直接查看目录,通知一下,春节不推送,节后继续。
|
|
来自: 昵称29398856 > 《第二天》