字符串字面量(又名字符串常量)是不能被修改的,但可以被读取。字符串变量是可以被修改的,还可以被访问。
1 |
|
字符串字面量
字符串字面量是用一对双引号括起来的字符序列。通常存储在只读数据区(只读内存区域),它的内容是不可修改的。尝试修改字符串字面量会导致未定义行为。编译器自动计算并在编译时确定其长度,通常包括末尾的 \0
终止符。
从本质而言,C语言把字符串字面量作为字符数组来处理。当C语言编译器在程序中遇到长度为的字符串字面量时,它会为字符串字面量分配长度为的内存空间。这块内存空间将用来存储字符串字面量中的字符,以及一个用来标志字符串末尾的额外字符(空字符)。空字符是一个所有位都为0的字节,因此用转义序列\0
来表示
字符串变量
存储在栈(或堆)内存中,可以被修改。字符串变量通常是一个字符数组或指向字符数组的指针。可以存储不同长度的字符串,长度由你在定义数组时指定,或者在运行时动态确定。
一些编程语言为声明字符串变量提供了专门的 string 类型。C 语言采取了不同的方式:只要保证字符串是以空字符结尾的,任何一维的字符数组都可以用来存储字符串。
1 |
|
看起来好像是 字符串字面量,但其实不然。C编译器会把它看成是数组初始化式的缩写形式。实际上,我们可以写成:
1 |
|
如果指定数组大小没有被填充满,会自动补0。如果指定数组大小务必要能有一个位置给其添加\0
,否则这不是一个合法的字符变量。
字符数组和字符指针
1 |
|
前者声明 date 是一个数组,后者声明 date 是一个指针。正因为有了数组和指针之间的紧密关系,才使上面这两个声明中的 date 都可以用作字符串。尤其是,任何期望传递字符数组或字符指针的函数都能够接收这两种声明的 date 作为参数。
然而,需要注意,不能错误地认为上面这两种date可以互换。两者之间有很大的差异:
- 在声明为数组时,就像任意数组元素一样,可以修改存储在date中的字符。在声明为指针时,date指向字符串字面量,前面我们已经看到字符串字面量是不可以修改的。
- 在声明为数组时,date是数组名。在声明为指针时,date是变量,这个变量可以在程序执行期间指向其他字符串。
如果希望可以修改字符串,那么就要建立字符数组来存储字符串,声明指针变量就不够的。因为指针变量没有指向一个有效的地址,对其修改会产生未定义的行为。下面的声明使编译器为指针变量分配了足够的内存空间:
1 |
|
可惜的是,它不能为字符串分配空间。(怎么会这样呢?因为我们没有指明字符串的长度。)在使用p作为字符串之前,必须把 p 指向字符数组。可以把p指向已经存在的字符串变量:
1 |
|
现在 p 指向了 str 的第一个字符,所以可以把 p 作为字符串使用了。
1 |
|
因为 p 没有被初始化,所以我们不知道它指向哪里。用指针 p 把字符 a、b 写入内存会导致未定义的行为。