理解c-风格字符串

总结

C语言没有原生的字符串类型!
C-风格字符串就是最后一位为'\0'的字符数组!
C语言通过字符指针来管理字符串!
指向字符串的指针和字符串本身是分开的两个东西
存储多个字符的两种方式:申请连续字符空间和字符数组
这个链接,对c-风格字符串的理解也是很到位的,辅助理解很重要!
https://www.jianshu.com/p/4db7a5eedc42?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

课本理解,C++ primer plus 中文版第五版,P225
首先从C语言开始说

1.什么是人理解的字符串?

program就是字符串,没有单引号,没有双引号,没有\0,任何连续的字符都认为是字符串(字符串在一起就是字符串),包括写的这句话,中英文夹杂,带标点符号,这在人看来也可以认为是字符串。

计算机没法理解人的思维,到底啥是字符串,就得给字符串立个规定,规定啥是字符串,让计算机一看,噢,这个东西就是个字符串!规定!规定!规定!

怎么立规定就要理解计算机中的数据类型。

类型是计算机存储数据的方式,让计算机知道,这个变量是int类型,那个变量是double类型。

首先明确一点,字符串不是一种类型,字符串是一种概念,概念的实现才是类型。
比如整型是概念,不是类型,int是类型,unsigned int是类型!

可以通过人为创建某个数据类型,让这个数据类型来表示字符串,计算机就理解了什么是字符串。

问题又来了,怎么创建这种类型来存储字符串,方便后续对字符串的操作?

C语言没有创建一个新的类型符来表示字符串,而是通过char类型的数组来存储字符串,暂且叫他char数组类型,这里强调下,char数组类型不是字符串的一种类型,只是字符串依靠char数组来存储。

前面提到了,字符串是概念,概念的实现是类型,而类型表示的是存储方法,那么表示字符串的char数组这种类型是如何存储字符串呢?

答案是把字符串拆分成一个个字符,依次放到数组里面,注意这里强调下,字符串是依靠字符数组,char[]来存储的,不代表字符数组就是字符串!
char str[8] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm'};

这里也解释下,为啥会有单引号和双引号,单引号圈住了p,表示p是个字符常量,p是个值。

到这里,我们就明白了,c语言是如何在计算机中存储一个人类认知中的字符串。通过字符数组来依次存放每个字符。这里强调了人类认知的字符串,因为它与计算机认识的字符串是不同的。

2.接下来介绍什么是编译器眼中的字符串

编译器规定了,字符串和字符数组的区别:最后一位是否是空字符。最后一个字符为'\0'的字符序列就是字符串,也就是所谓的c-风格字符串。

这里是字符序列,不是字符数组。比如刚才提到的char str[8] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm'};不是c-风格字符串,而char str[8] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm', '\0' };是c-风格字符串,序列最后以'\0'结尾。

如何把人类眼中的字符串赋值给代码中的变量,让编译器知道变量是个字符串,而不是字符数组

这里强调是如何完成赋值!

赋值操作需要4个东西,0.变量的类型,1.左边的变量名,2.=号,3.右边的值,重点是右边的值

3.人得告诉计算机,我输的这个值是什么类型,比如1,它既可以是整型,也可以是字符类型。问题来了,怎么告诉,这个值是什么类型。

这是个有趣的问题

比如,可以这么写,int ch='a';这肯定是对的,'a'是个字符此时ch的值打印出来是97,这是因为ASCII码上的字符有对应的int值,这里属于映射。想说明的问题是,赋值这个操作得到的结果是否是我们想要的取决于2个因素,1.变量的类型,2.值的类型。这里就是值为char类型,变量为int类型,进行了类型转换,通过ASCII映射表,找到了char类型的值对应的int类型的值。再强调下变量的类型与值的类型影响赋值过程。

回到刚才的问题,人得告诉计算机,我输的这个值是什么类型。

变量设为int类型,然后进行赋值,那么编译器很自然知道,2是个数字,不是个字符
int a; // a是整型
a=2; // 2是个整型数字

很自然,设定一个属于字符串概念的某种类型变量的语句也应该类型,如下
[实现字符串的类型名称] a;
a=字符串;

如何把字符串program赋值给a,又回到了刚才的问题,人得告诉计算机,我输的这个值是什么类型

字符的值是通过单引号告诉编译器,这个值是字符类型,那么字符串的值怎么告诉编译器,这个值属于c-风格字符串。

这里注意,我强调的是C-风格字符串,不是c-风格字符串类型或字符串类型!,C语言没有字符串类型,只有C-风格的字符串。

规定:用单引号表示单个字符,双引号表示人类认知中的字符串,单双引号两者不可混用,这就是字符串的值。

使用单引号赋值就是前面的数组赋值的方法,只不过最后一个字符要求是'\0'
char str[8] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm', '\0' };或者char str[] = { 'p', 'r', 'o', 'g', 'r', 'a', 'm', '\0' };

使用双引号赋值有两种语法
初始化方法1:char* str= "program";或者const char* str= "program"
初始化方法2: char str[] = "program";或者char str[8] = "program";本质是一样的

再次强调下,1和2的存储结构是一样的,都是依靠字符数组进行存储的,其实到这里就回答了问题,c语言是如何表示字符串的:

答案:通过指针,指向字符数组。

4.编译器认为字符串是什么类型

C语言中的字符串语句
char * p="hello world";
右值"hello world"的类型不叫字符串常量类型,c语言没有字符串常量类型,有很多种叫法,字符串直接量,字符串字面值等。

字符串字面值是一串常量字符,用双引号括起来的零个或多个字符表示字符串字面值

使用typeid("hello").name()来看其类型,返回的是A6_c,表示char 型 Array(数组),数组有6个元素,实际是个char * 的指针类型

5.如何理解字符串初始化在内存层次上的执行顺序是什么?

1.char* str = "program",在rom中申请(类似malloc)一个连续的内存空间,大小为7+1个字节,7字节存储字符数组program,编译器自动在字符数组后面添加了一个'\0'字符,存储在1字节上,于是便把"program"转换成c-风格字符串;接着,成功申请内存存放数据后,接着就会返回该字符数组申请的连续内存空间的首地址,这个地址是个char*类型,把地址赋值给同样是char *类型的变量str,完成这条语句。

  1. char str[] = "program",在rom中申请(类似malloc)一个连续的内存空间,大小为7+1个字节,7字节存储字符数组program,编译器自动在字符数组后面添加了一个'\0'字符,存储在1字节上。接着左侧的str变量会在栈内存中申请8个字节的连续空间,str的内存申请完成后,编译器把rom上连续内存上存储的program一一复制(等号的作用)到str指向的栈的连续内存空间中

第一种属于字符串常量,无法被修改,与字符串直接量相关联的内存空间位于只读部分。但是c语言是没有字符串常量这种类型,它是常量字符数组类型,即const char *。通过字符指针来管理字符串。

第二种当将字符串直接量赋值给字符数组的初始值的时候。由于字符数组存放与栈中,不允许引用其他地方的内存,因此编译器会将字符串直接量复制到栈的数组内存中。因此,可以进行相应的修改。通过字符数组来管理字符串。

你会发现字符串中没有字符'\0',怎么说是c-风格字符串呢。

可以发现,char str[8] = "program";这里用了8个字符空间,而program是7个字符,那么用7个可以吗?

答案是不可以,因为编译器会默认在最后一个位置填充字符'\0',占用了一个字符位置。也就是编译器通过自动在字符数组末尾添加'\0',把双引号的内容转换成了c-风格的字符串,然后赋值给了变量!

sizeof("C++"); //结果是4!
char c1[] = {'C', '+', '+'}; //不是c-风格,没有‘\0’。求sizeof(c1),结果为3
char c2[] = {'C', '+', '+', '\0'}; //是c-风格。求sizeof(c2),结果为4
char c3[] = "C++"; //自动添加空字符。求sizeof(c3),结果为4

c语言中字符串操作函数,比如scp,scm等操作的都是c-风格字符串,这些字符串函数定义中就默认了字符串的最后一个字符是'\0'。

6.你可能会问,为啥要这么设定'\0'是一个字符串的结尾?

这里就涉及到一个编码问题:

在C语言中,字符串是以字符数组的形式进行存储的,且在数组中以'\0'作为终结符。由于'\0'在ASCII中表示空字符(NULL),即在语意上不可能有有效字符与之重复,故用其来表示字符串的结尾至少在ASCII编码下是合理的。

ASCII编码及其扩充规范中,每个字符长度都不超过1Byte,因此,在C风格字符串中用'\0'表示结尾是合法的。

但在UTF16编码中,每个字符使用2Byte进行编码,故会出现其中一个字符为0x00的情况,此时如果仍使用C风格字符串,则在使用相关函数进行处理时,会在第一个0x00出现的位置就被认为是字符串已经结束,但其实字符串并不在此处终结。

UTF8是一种很好的解决方案,UTF8中字符的编码非定长,可能是1Byte或者是2Byte,但是这种编码方案中用每个字符的前缀来表示当前字符的长度,因此既有足够的空间来存储较多的字符,又不会出现0x00导致字符串在被以C风格字符串处理时异常结束。

7.设计字符串这种数据结构,一般有两种想法

1.类似c-风格字符串,以一个标识符表示字符串的结尾

2.在字符串的开头记录了字符的个数,其实在C++中设计的字符串string类,就不是在末尾以'\0'表示字符串的结尾,而是依靠在字符串前面放置了字符的个数!

8.c++中

在C++语言中,除了继承了C语言中的这种字符串表达形式外,还新添了string类用来表达字符串。

为了区分C++中这两种不同的字符串,使用“C风格字符串”来特指来源于C语言的字符串存储方式。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353