打印
[PIC®/AVR®/dsPIC®产品]

字符串长度与字符串在内存空间的占位长度

[复制链接]
1048|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1. 字符串常量的概念

    字符串常量是一个字符序列,且被括在双引号中(双引号称为定界符)。字符串常量可以包含零个或多个字符集中的字符,也可以包括任意转义字符。其中若出现双引号、反斜线或回车换行符等必须用其转义字符(\", \\, \n)表示。
    例如,"123 C program","11.11%","123\nabc"等都是合法的字符串常量。
    特别地,定界符中没有字符时,""称为空串。

2. 字符串的长度

   字符串常量是由若干字符常量组成的,一个字符常量占一个字节的内存空间。字符串的长度为字符串的个数。字符串用转义字符'\0'作为字符串的结束标志,占用1个字节。对于字符串何时结束,系统以出现的第一个'\0'为界。
    (1)字符串的长度:只统计第一个'\0'之前的有效字符个数。

    例如:

    "123\0abc\0"字符串长度为3。

    (2)字符串在内存中所占的字节数:还要包含'\0'占用的一个字节。
    例如:
    "ba\n\0cde" 字符串长度为3,在内存中占4个字节。

3. 字符串常量和字符常量的区别

    (1)字符常量由单引号括起来,字符串常量由双引号括起来。
    (2)字符常量只能是单个字符,字符串常量则可以含一个或多个字符。
    (3)可以把一个字符常量赋予一个字符变量,但不能把一个字符串常量赋予一个字符变量。在C语言中没有字符串变量。但是可以用一个字符数组来存放一个字符串常量。
    (4)字符常量占一个字节的内存空间。字符串常量占的内存字节数等于字符串中字节数加1。增加的一个字节中存放字符串结束的标志――字符’\0’ (ASCII码为0)。

   例如:字符串 "C program" 在内存中所占的字节数为10,存储如下图所示:



使用特权

评论回复
沙发
huahuagg|  楼主 | 2024-4-24 15:04 | 只看该作者
字符数组和结束符/0之间的关系
在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个字符,就很好理解了。(wsj注:剩余空间用来存放'\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到底要学什么了吗?



实例:

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’它占用存储空间,但是不算字符串长度。

(wsj注:在申请字符串存储空间时要考虑末尾的结束符'\0'空间,即在单字节字符系统中要多申请一个字节。)

使用特权

评论回复
板凳
幸福小强| | 2024-4-26 22:43 | 只看该作者
之前还没研究过,原来字符串要多占用一个字节空间存储吖

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

1254

帖子

2

粉丝