自言自语
1. 表示字符串和字符串I/O
字符串
是C语言最有用、最重要的数据类型之一。
字符串
是以空字符\0
结尾的char
类型数组。
1.1. 在程序中定义字符串
- 字符串字面量:用双引号括起来的内容称为
字符串字面量
,也叫字符串常量
双引号中的字符和编译器自动加入末尾的\0
字符,都作为字符串存储在内存中。 - 从ANSI C标准起,如果字符串字面量之间没有间隔,或者用空白字符串分隔,C将其视为串联起来的字符串字面量。
- 字符串字面量属于静态存储类别,若在函数中使用字符串,该字符串只会被存储一次,用双引号括起来的内容称为指向该字符串存储位置的指针。
printf("%s, %p, %c\n", "Hello", "OK", *"fine");
//输出:Hello,0x7ffe0f43, f
1.2. 字符串数组初始化
- 定义字符串数组时,必须让编译器知道多少空间。比如使用足够空间的数组存储字符串。
const char str[14] = "Hello OKfine.";
//上面的形式比下面的标准数组初始化方便的多
const char str[14] = {'H', 'e', 'l', 'l', 'o', ' ', 'O', 'K', 'f', 'i', 'n', 'e', '.', '\0'};
注意:最后的空字符。若没有这个空字符,就不是一个字符串,而是一个字符数组。
在指定数组大小时,要确保数组大小的元素个数至少比字符串长度多 1(容纳空字符)。
所有未被初始化的元素都被初始化未0(这里的0 指的是char
类型的空字符,不是数字0)。
下面是使用指针表示法和数组表示法创建字符串:
const char *pstr = "Hello OKfine.";
//这两种形式的声明几乎相同。
const char str[] = "Hello OKfine.";
1.3. 数组和指针
数组形式和指针形式有何不同?
-
上面的示例来说:数组形式
str[]
在计算机内的分配为一个含有14个元素的数组(每个元素对应一个字符,还加末尾的空字符\0
)。程序在开始运行时才为数组分配内存。此时才将字符串拷贝到数组中。注意:此时字符串有两个副本。一个是在静态存储区中的字符串字面量。另一个是存储在
str
数组中的字符串. -
str
是一个地址常量,不能更改str
,如果改变了str
则就改变了数组的存储位置。可以进行类似
str + 1
的操作,标识数组的下一个元素。但是不能进行str++
操作。递增运算符只能存在于变量名前(只能用于可修改的左值),不能用于常量。 -
初始化数组把静态存储区的字符串拷贝到数组中,初始化指针只需要把字符串的地址拷贝给指针。
1.4. 数组和指针的区别
char ht[] = "Nice to meet u.";
const char *pt = "How are you?";
两者的主要区别:
数组名ht
是常量,指针名pt
是变量。
- 两者都可以使用数组表示法
for (int i = 0; i < 6; i++)
putchar(ht[i]);
putchar('\n');
for (int j = 0; j < 6; j++)
putchar(pt[j]);
putchar('\n');
//输出:
// Nice t
// How ar
- 两者都能进行指针加法操作
for (int i = 0; i < 6; i++)
putchar(*(ht + i));
putchar('\n');
for (int j = 0; j < 6; j++)
putchar(*(pt + j));
putchar('\n');
//输出:
// Nice t
// How ar
- 只有指针表示法可以进行递增操作
while(*pt != '\0')
putchar(*(pt++));
//输出:How are you?
可以将pt = ht;
是的指针pt
指向数组的首元素。
但是不能将ht = pt;
,这类似x = 3; 3 = x;
在C中是非法的。
注意:pt = ht;
不会导致pt
指向的字符串消失,这样做只是改变了存储在pt
中的地址。除非已经保存了"How are you?"
的地址,否则当pt
指向别处时,就无法访问该字符串。
数组的元素
是变量,数组名是常量。
ht[1] = 'O';
或者*(ht + 1) = 'O';
推荐使用:const char * pt = "Hi, OKfine.";
。
1.5. 字符串数组
- 指向字符串的指针数组
- char 类型数组的数组
#define LIM 3
#define SIZE 40
const char * mytalents[LIM] =
{
"Adding numbers swiftly",
"Stashing data",
"Understanding the C language"
}
char yourtalents[LIM][SIZE] =
{
"Walking in a straight line",
"Sleeping",
"Reading email"
}
区别:
-
mytalents
数组是一个内含3个指针的数组,在我的linux系统中占用24个字节。其中的指针指向初始化时所用的字符串字面量的位置,这些字符串被存储在静态存储区。而yourtalents
数组是一个内含3个数组的数组,每个数组内含有40个char
类型的值,共占用120字节。其中的数组则存储着字符串字面量的副本,所以每个字符串被存储了两次。 -
由此可见字符串数组分配内存的使用率较低。
yourtalents
中的每个元素的大小必须相同,而且必须是能存储最大字符串的大小。 -
综上所述,如果用数组表示一系列待显示的字符串,请使用指针数组,效率高。但是
mytalents
中的指针指向的字符串字面量不能被修改,而yourtalents
中的值可以被修改。如果要改变字符串或为字符串输入预留空间,不要使用指向字符串字面量的指针。