有关C语言,自己真的动了么?

在C中,字符串其实就是字符数组。C语言中,对字符串就是按字符数组的规律来处理的(ANSI的字符是unsigned char,对宽字符,字符是unsigned short int,即前者1byte,后者2byte)。由于是按数组方式处理的,所以必须知道每个串的实际有效元素到哪里结束,想像图书馆书柜中的格子,书柜尽管有100个格子,但未必要放满100本书,可能是10本、20本,所以不能按格数来算字符串长度(算格数那个就是sizeof()的值),实际放书的数量是动态变化的,所以C语言规定某个标志,告诉处理程序,遇到这个标志,就表示书放到此为止,后面不会有书了,这个标志就是'\0',也是整数0。

C标准库中的字符串处理程序,是只认'\0'的,只要没找到'\0',它就认为字符串没有结束,拼命地往后找,这个寻找的过程不理会可能已经超过书柜的格数了(计算机其实很蠢);同样,也可能你在一排书中的中间抽走一本,在那个位置上写上'\0',那么愚蠢的计算机也会认为书到这里为止,它不理会后面其实还有(这是某种截断字符串的技巧)。

其实,只要你明白这种类比,自然知道写程序的时候怎么办。比如,当你明白宽字符是16位整数亦即2字符的时候,就会明白,一个宽字符L'A'其实储存有一个字节的0,亦即假如你用常规的ANSI算法来处理这样的字符串,就会很快遇到'\0',后果如何可想而知。

标准库函数strlen(),就是在字符数组中搜寻'\0'的简短代码,找到后,把经历过的元素个数返回出来而已。知道这点原理,其实我们并不是必须遵守以'\0'为结束符的cz字符串规则的,以-1结束亦未尝不可,自己写一个_strlen()函数,不用strlen()就可以了。C的灵活性,就体现在这里。须知,C语言本身是没有strlen()这样的内置函数的,它其实就只有那些运算符和数据结构构造规则,你所用的库函数,全部是后人写的代码,不是C语言,最纯正的C语言,应该是所有函数都自己写。标准库函数认cz字符串,你完全可以不认,并非因此而说你没使用C语言写程序。

像BASIC类的语言,内部其实也是把字符串作数组看待的(所谓C是基础,也是指的这点原理,用来理解别的语言的实现机制,很可能这种语言是用C制作的),只不过,它不用认'\0'作结束符,而把数组的零号元素挪用为字符串长度的记录,所以迫使它的数组计数从1开始,但好处是求数组的有效元素数目不用像C那样遍历数组,而是直接从零号元素读出结果,比遍历快得多——当使用单字节字符系统时,单字节最大值是256,所以很多旧式的语言,字符串最大容量是255或254个字符,就很好理解了。

我们现在再看另一个例子:char* strcat(char* s1, const char* s2)这个函数,是字符串接驳,它的作用是把s2追加在s1的末尾,形成新的字符串。仍然使用上面书柜的例子,既然要在s1的柜子中放入更多的书,那么s1的格子数必须要能容纳全部的书,这是必然的,而书柜是在建造时就造好了的,所以创建s1的时候,首先要考虑这个问题,别指望C库函数会替你想这些,为了高效,它完全不检查这个,闷头就把数据扔过去,它的高效是这样来的(别的语言,为了完成任务,它会智能地做各种动作把任务完成,而C只是做错了报告一声“出错了”就干脆逃跑,被系统杀掉)。在容量满足条件的基础下,函数的动作,首先是找到s1的'\0'位置,然后从s2中逐个把数据复制过来,注意此时必须把'\0'覆盖掉并写上新的'\0',原因在上面说过了。所以,现在返回头看看函数的原型,它的s1是char*,表明这个字符串是可以被修改的,事实上它必须改这个,而s2是const char*,表明它不需要改动s2,返回的正是s1指针。

那么,假如要把两个被记录在只读储存空间的字符串接驳成一个,或者已经无法再修改s1的尺寸了,你该怎么做?用strcat是不要指望了,因为此时无法修改s1,你必须自己写一个,用动态申请内存。

学会语法很简单,但面对具体的情形,如何处理,这才是最需要学习的,假如连这点原理都不知道,那就悲催了,实际上这些动作用不了多复杂的算法、数据结构,但很多人就死在这种地方!现在明白学C到底要学什么了吗?

猜你喜欢

转载自blog.csdn.net/xiaohaigary/article/details/79097457