| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 13324 人关注过本帖
标题:字符数组和结束符/0之间的关系
只看楼主 加入收藏
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:20 
在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',后果如何可想而知。

[ 本帖最后由 TonyDeng 于 2013-2-11 22:29 编辑 ]

授人以渔,不授人以鱼。
2013-02-11 22:26
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:5 
标准库函数strlen(),就是在字符数组中搜寻'\0'的简短代码,找到后,把经历过的元素个数返回出来而已。知道这点原理,其实我们并不是必须遵守以'\0'为结束符的cz字符串规则的,以-1结束亦未尝不可,自己写一个_strlen()函数,不用strlen()就可以了。C的灵活性,就体现在这里。须知,C语言本身是没有strlen()这样的内置函数的,它其实就只有那些运算符和数据结构构造规则,你所用的库函数,全部是后人写的代码,不是C语言,最纯正的C语言,应该是所有函数都自己写。标准库函数认cz字符串,你完全可以不认,并非因此而说你没使用C语言写程序。

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

授人以渔,不授人以鱼。
2013-02-11 23:31
心灯甚亮
Rank: 8Rank: 8
等 级:蝙蝠侠
威 望:2
帖 子:441
专家分:996
注 册:2013-1-29
收藏
得分:0 
学习
2013-02-11 23:36
TonyDeng
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:贵宾
威 望:304
帖 子:25859
专家分:48889
注 册:2011-6-22
收藏
得分:0 
我们现在再看另一个例子: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到底要学什么了吗?

[ 本帖最后由 TonyDeng 于 2013-2-12 00:08 编辑 ]

授人以渔,不授人以鱼。
2013-02-12 00:01
hanlinxuea
Rank: 2
等 级:论坛游民
帖 子:4
专家分:20
注 册:2013-2-12
收藏
得分:20 
char s[6]={'h','e','l','l','o'};
char s[6]={"hello"};
char s[6]="hello";

字符数组和字符串的区别:字符数组的每个元素中可存放一个字符,(像这个char s[6]={'h','e','l','l','o'};
)但他不限定最后一个字符应该是什么,存储空间有剩余系统补‘\0’。而字符串则要求最后一个必须是‘\0’做为结束标示。在字符数组中可以存放字符串。
char s[6]={"hello"};看这个为什么是s[6],而不是s[5]呢?因为,字符串后面以‘\0’为结束标示,这个是系统补的,不用手动输入。但是必须要给它留一个存储空间。这个‘\0’它占用存储空间,但是不算字符串长度。
今天刚学的字符数组就理解这么多,有什么问题还请高手指点一下。
2013-02-12 02:10
wp231957
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:神界
等 级:贵宾
威 望:423
帖 子:13688
专家分:53332
注 册:2012-10-18
收藏
得分:5 
学习

DO IT YOURSELF !
2013-02-12 12:20
Ayiis
Rank: 12Rank: 12Rank: 12
等 级:火箭侠
威 望:2
帖 子:1086
专家分:3063
注 册:2011-4-10
收藏
得分:5 
对的

  • 该单位
  • 正在被拖走
2013-02-12 13:39
Susake
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:女儿国的隔壁
等 级:贵宾
威 望:23
帖 子:2288
专家分:6481
注 册:2012-12-14
收藏
得分:0 
.....哈哈

仰望星空...........不忘初心!
2013-02-12 20:32
tompobing
Rank: 8Rank: 8
等 级:蝙蝠侠
帖 子:260
专家分:809
注 册:2012-12-9
收藏
得分:5 
学习。。。
2013-02-13 18:49
Susake
Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15
来 自:女儿国的隔壁
等 级:贵宾
威 望:23
帖 子:2288
专家分:6481
注 册:2012-12-14
收藏
得分:0 
。。。。

仰望星空...........不忘初心!
2013-02-13 18:57
快速回复:字符数组和结束符/0之间的关系
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017388 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved