- Published on
字符串
- Authors
- Name
- Yanbin
- @ybtaimu
定义
C 语言没有单独的字符串类型,字符串被当作字符数组,即char类型的数组
。
编译器会给数组分配一段连续内存,所有字符储存在相邻的内存单元之中。 在字符串结尾
,C 语言会自动添加一个全是二进制0的字节,写作\0字符,表示字符串结束
。 字符\0不同于字符0,前者的 ASCII 码是0(二进制形式00000000), 后者的 ASCII 码是48(二进制形式00110000)。 所以,字符串“Hello”实际储存的数组是{'H', 'e', 'l', 'l', 'o', '\0'}
。
char localString[10];
上面示例声明了一个10个成员的字符数组,可以当作字符串。由于必须留一个位置给\0
,所以最多只能容纳9个字符的字符串。
字符串写成数组的形式,是非常麻烦的。C 语言提供了一种简写法,双引号之中的字符,会被自动视为字符数组。
{'H', 'e', 'l', 'l', 'o', '\0'}
// 等价于
"Hello"
上面两种字符串的写法是等价的,内部存储方式都是一样的。双引号里面的字符串,不用自己添加结尾字符\0,C 语言会自动添加。
注意,双引号里面是字符串,单引号里面是字符,两者不能互换。如果把Hello放在单引号里面,编译器会报错。
字符串变量的声明
// 写法一
char s[14] = "Hello, world!";
char s[] = "Hello, world!";
// 写法二
char* s = "Hello, world!";
上面两种写法都声明了一个字符串变量s。 如果采用第一种写法,由于字符数组的长度可以让编译器自动计算,所以声明时可以省略字符数组的长度。
字符指针
和字符数组
,这两种声明字符串变量的写法基本是等价
的,但是有两个差异
。
第一个差异是,指针指向的字符串,在 C 语言内部被当作常量,不能修改字符串本身
char* s = "Hello, world!";
s[0] = 'z'; // 错误
上面代码使用指针,声明了一个字符串变量,然后修改了字符串的第一个字符。 这种写法是错的,会导致难以预测的后果,执行时很可能会报错。
为什么字符串声明为指针时不能修改,声明为数组时就可以修改? 原因是系统会将字符串的字面量保存在内存的常量区,这个区是不允许用户修改的。 声明为指针时
,指针变量存储的值是一个指向常量区的内存地址
,因此用户不能通过这个地址去修改常量区
。 但是,声明为数组时
,编译器会给数组单独分配一段内存
,字符串字面量会被编译器解释成字符数组
, 逐个字符写入这段新分配的内存
之中,而这段新内存是允许修改
的。
第二个差异是,指针变量可以指向其它字符串
char* s = "hello";
s = "world";
上面示例中,字符指针可以指向另一个字符串。
但是,字符数组变量不能指向另一个字符串。
char s[] = "hello";
s = "world"; // 报错
上面示例中,字符数组的数组名,总是指向初始化时的字符串地址,不能修改。
为什么数组变量不能赋值为另一个数组? 原因是数组变量所在的地址无法改变
,或者说,编译器一旦为数组变量分配地址后, 这个地址就绑定这个数组变量了,这种绑定关系是不变的。 C 语言也因此规定,数组变量是一个不可修改的左值
,即不能用赋值运算符为它重新赋值。