6.1 字符串的定义
什么叫字符串呢?其实 C 语言里边说:字符串就是一串字符的意思,那怎么来描述这一串字符呢?就是用双引号括起来的一串字符就是字符串
举个例子:比如说我们里写一个双引号 abcdef(一定是英文双引号),用英文双引号括起的这一串字符就被成为字符串,你也可以说 hello bit,这也是个字符串,由双引号引起的这一串就叫字符串,如图所示:
因此,这种由双引号( Double Quote )引起来的一串字符称为字符串字面值( String literal),或者简称字符串
6.2 字符串的结束标志
在学字符串里边有个非常重要的概念:字符串的结束表示是 \0 的转义字符,在计算字符串长度的时候 \0 是结束表示,不算作字符串内容
那这个地方我们怎么来证明它呢?在字符串里边是不是就有一个这样 \0 这么一个东西呢?假设定义一个字符串叫 hello,这个字符串如果要存起来,字符串是一串字符,也就是多个字符
那么多个字符要如何存起来?我们有个字符数组得到概念,数组是一组数的意思,或者说一组相同类型的元素,然后我们现在字符串里边是不是放的都是字符,那我们就可以把它存到一个字符数组。大致步骤:char 类型,给个 arr[ ],等于 "hello",再解释一下:我们用 char 类型,创建了一个数组叫 arr,后面给个中括号,这个方括号我们没有写大小,当我们不写这个数组有几个元素的时候,它就会根据后面这个字符串的内容来初始化它,如图所示:
运行结果后,我们就会发现:其实,字符串在结尾的位置隐藏了一个 \0 的字符,这个 \0 是字符串的结束标志,每一个字符串的后面其实都隐藏了一个 \0,它是隐藏起来的,我们没有看到。
6.3 深入解剖字符串结束标志
如何正确的理解字符串的结束标志?举一个例子,放我们去看它的结果的时候,当我们打印出来的时候,发现了它们好像不一样:第一个当我们打印的时候,就打印了 abc 就完了,第二种当打印abc之后,我们都不知道后面怎么会出现烫烫烫烫隐 bc,如图所示:
那么第二种为什么没有停下来?
第一种方式的时候,在内存里边放了个 a,还放了个 b,还放了个 c,c 的后面放了个 \0,这是我们 arr1 字符串的内容,a 在内存里边大致的情况是这样的:
详细分析:那么这个时候当我去打印的时候,第一个我们打印完 abc 之后就停下来了,为什么呢?是因为这个字符串里边放了一个结束标志叫 \0,当我打印 a,打印 b,打印 c之后遇到 \0,\0 是字符串的结束标志,就不再打印了,就停下来了
对于第二个来说,当然内存是一块连续的空间,除了刚刚这个的 abc,这块空间前边是内存,后边也是内存,内存空间是非常长的,所以第二种情况说:我们也是内存块,但是这个里边是怎么放的呢?b 在内存里边大致的情况是这样的:
详细分析:但是对于这种方法来说,我们也是从 a 的位置开始打印,打印 abc 完之后,有没有 \0 呢?后面这块内存里边放的是什么我们完全不知道,所以这个后面空间的内容是未知的,对于未知的内容,当我们去打印的时候,那我们打印出来什么我们自然而然不知道了,后面是什么就乱了,而刚刚第一种打印的时候,abc 打印完之后遇到字符串的结束标志了,就停下来了,不要往后走了,那代码就只打印了 abc,所以我们从这个例子里边就感受到了 \0 是字符串的结束标志
那我们测试一下,我们主动给 arr2 里边放上个 '\0' 的字符,它是不是也能打印 abc 呢?如图所示:
因此,这个测试就充分证明了一件事情:字符串的结束标志是 \0,对于字符串来说,它的结束标志是至关重要的
补充:char arr = "abcd"这种写法肯定是不行的,arr 现在是一个字符了,字符里边不可能存一个字符串
6.4 求字符串长度
想求字符串的长度怎么求呢?我们这里有一个函数叫 strlen,C 语言里边有个函数叫 strlen(全称 string length),如果在 strlen 里边给上一个 "abc",它其实就求这个字符串的长度,而这个 strlen 当求完参数部分字符串长度之后,它就会返回来,我们可以把求完的长度放到一个临时变量 int len 里边去,如图所示:
看到这里结果是3,有人就好奇了:这里边不是隐藏了一个 \0 吗,在这里注意一下,字符串的结束标志是 \0,仅仅是结束标志,当我们在计算这个字符串长度的时候,有没有包含它呢?没有。就是说这个 \0 是作为字符串结束标志而存在的,它存在,但我们求长度的时候,它是不算在里边的。
补充:当使用函数 strlen 的时候,需要引用头文件<string.h>
接下来求一下 arr1 的长度,再求一下 arr2 这个字符串的长度,这个地方结果第一个是3,第二个是15,第二个为什么是15呢?第二个是随机值,当我们打印15的时候,这个15其实应该是个随机值,如图所示:
重中之重:
第一种打印3很正常,因为 abc 后面是 \0 就是3个字符,所以3是正确的,而打印出来的15是随机值,为什么是随机值呢?因为 abc 它的存储方式 c 后面到底是什么呢?在内存里边刚刚说了,到底后面是什么我们不知道,我们不知道的情况下,那我们也就意味着下一个是不是 \0 我们也不知道
那怎么办呢?strlen 这个函数它就从 c 后面向后一直找 \0,直到找的 \0 的时候它就停下来了,刚刚打印15,可见它找了15个之的第16个位置上放的确实是 \0 的时候,它就停下来了
所以讲了这么多,唯一理解的一个东西就是:字符串的结束标志是 \0,但是 \0 是结束标志,不假,是存在不假,但是在计算字符串长度的时候 \0 只是结束标志而已,不算字符串内容,我们在求长度的时候不算它
思考题1:求字符串数组元素的个数会计算 \0 吗?
会算,因为 \0 是算数组内容,但是求字符串长度的时候不算 \0
思考题2:为什么会出现随机值?
因为这个内存后面到底是什么我们是不知道的,内存里边我们只知道自己的空间,当我们看到 arr2 的时候,arr2 里边放个 abc 3个字符,这是我们自己的空间内容,我们是清楚的,我知道我里边放的 abc,但是其他内容,其他空间不属于你,你知道他里边放的什么吗,不知道。
所以,当我们在这个地方打印的时候,打印 arr2 这个数组,我可以把我前面的 abc 打印出来,我自己的 abc 打印出来之后,我后面是没有 \0 的,而字符串打印的时候,没有遇到 \0 它就会一直往后打印,那这个后面是什么我们不知道,那后面里边放的内容也不是些准确的内容,所以打印的就是些随机值,直到遇到后面里边的 \0,它就打印停下来了
同理,对于求长度的时候,也是一样的道理: 因为后面没有 \0,所以它就一直往后找 \0,找到 \0 的时候,刚刚可能数的是15(不一定每次都是15)
总结:由单引号引起来的叫一个字符;由双引号引起来的是一串字符;%s 是打印一个字符串