第11章 字符串和字符串函数
- 字符串是以空字符(\0)结尾的
char
类型数组 puts()
函数只显示字符串,并且自动在显示的字符串末尾加上换行符- 用双引号括起来的内容称为字符串字面量,也叫做字符串常量。双引号中的字符和编译器自动加入末尾的\0字符,都作为字符串存储在内存中
- 从ANSI C标准起,如果字符串字面量之间没有间隔,或者用空白字符分隔,C将会将其视为串联起来的字符串字面量
- 字符串常量属于静态存储类别,说明如果在函数中使用字符串常量,该字符串只会被存储一次,在整个程序的生命期内存在,即使函数被多次调用。
- 用双引号括起来的内容被视为指向该字符串存储位置的指针。
- 定义字符串数组时,必须让编译器知道需要多少空间
- 字符串数组的最后必须存在一个空字符,如果没有则为一个字符数组
- 在制定字符串数组大小事,要确保数组的元素个数至少比字符串长度多1(为了容纳空字符)。所有未被使用的元素都被自动初始化为0。
- 省略数组初始化声明中的大小,可以让编译器自动计算数组的大小
- 字符数组名和其他数组名一样,都是该数组首元素的地址。
- 可以使用指针表示法创建字符串
- 数组形式在计算机内存中分配为一个内含29个元素的数组(每个元素对应一个字符,还加上一个末尾的空字符\0),每个元素被初始化未字符串字面量对应的字符。通常字符串都作为可执行文件的一部分存储在数组段中。当程序载入内存时,也载入了程序中的字符串,字符串存储在静态存储区中,但是程序在开始运行时才会为该数组分配内存,此时,才将字符串拷贝到数组中。注意此时字符串有两个副本,一个是在静态内存中的字符串字面量,另一个是存储在数组中的字符串。
- 在数组形式中,数组名是地址常量,不能更改数组名,如果改变了数组名,则意味着改变了数组的存储位置(即地址)。
- 字符串字面量被视为
const
数据,由于指针指向这个const
数据,所以应该把指针声明未const
数据的指针。这意味着不能用指针改变它所指向的数据,但是仍旧可以改变指针的值。如果把一个字符串字面量拷贝给一个数组,就可以随意改变数据,除非把数组声明为const
。 - 编译器可以把多次使用的相同字面量存储在一处或多出。
- 静态数据使用的内存和数组使用的动态内存不同。不仅值不同,特定编译器甚至使用不同的位数表示两种内存。
- 初始化字符数组来存储字符串和初始化指针来指向字符串的区别在于:数组名是常量,指针名是变量。
- 建议在把指针初始化未字符串字面量时使用
const
限定符 - 如果打算修改字符串,就不要用指针指向字符串字面量
- 如果要用数组表示一系列待显示的字符串,则使用指针数组。如果要改变字符串或为字符串输入预存空间,不要使用指向字符串字面量的指针。
- 如果想把一个字符串读入程序,首先必须预存存储该字符串的空间,然后使用输入函数获取该字符串,如果不分配空间,则可能在读入字符串时导致擦写掉程序中的代码或数据。
- 分配空间两种方法:在声明时显式地指明数组的大小;使用C库函数分配内存。
- 为字符串分配内存后,便可以使用字符串函数读入字符串了。
fgets()
函数通过第2个参数限制读入的字符数来解决溢出的问题- 如果
fegts()
读到一个换行符,会将它存储在字符串中 fgets()
的第3个参数指明要读入的文件,如果读入从键盘输入的数据,则以stdio
作为参数- 因为
fgets()
函数把换行符放在字符串的末尾,通常要与fputs()
函数配对使用,除非该函数不在字符串末尾添加换行符 fputs()
函数的第2个参数指明它要写入的文件,如果要显示在显示器上,使用stdout
作为第2个参数puts()
函数会在待输出字符串末尾添加一个换行符,而fputs()
不会添加puts()
在输出末尾添加换行符,fputs()
不在输出末尾添加换行符- C库提供了多个处理字符串的函数,ANSI C把这些函数的原型放在
string.h
头文件中 strlen()
函数用于统计字符串的长度strcat()
函数接受两个字符串作为参数,该函数把第2个字符串的备份附加在第1个字符串末尾,并把拼接后形成的新字符串作为第1个字符串,第2个字符串不变。strcmp()
函数通过比较运算符来比较字符串,如果两个字符串参数相同,该函数旧返回0,否则返回非零值