字符串
一、字符串定义
字符串是以空字符( \0 )结尾的 char 类型数组。
二、在程序里定义字符串
有多种方法可以定义字符串:字符串常量、char 类型数组、指向 char 的指针。
2.1 字符串常量
用双引号括起来的内容称为字符串字面量,也叫做字符串常量。双引号中的字符和编译器自动加入末尾的 \0 字符,都作为字符串储存在内存中。
字符串常量属于静态存储类别,这说明如果在函数中使用字符串常量,该字符串只会被储存一次,在整个程序的生命期内存在。
用双引号括起来的内容被视为指向该字符串存储位置的指针。
2.2 字符串数组和初始化
定义字符串的时候,必须让编译器知道需要多少空间。
两种方法:
Ⅰ. 使用足够空间的数组存储字符串。 如 char a[50] = “alkdjfaldkfjaldkf”;
Ⅱ. 让编译器来确定数组的大小。 如:char a[] = “aldkjfaldkfalkdfj”;
第二种方法方便,但是该方法初始化的字符串不能再追加新的内容。
2.3 数组和指针
数组声明字符串:char arr[] = “arry and pointer.”;
指针声明字符串:const char * pt = “arry and pointer.”;
以上两种声明,pt 和 arr 都是该字符串的地址。在这两种情况下,带引号的字符串本身决定了预留给字符串的存储空间。但是这两种方式还是有不同。
**字符串常量存储在静态存储区中,**但是,程序在运行的时候才会为数组分配内存,所以在运行时才把字符串拷贝到数组中。这时该字符串有两个副本,一个是静态内存中的字符串字面量,另一个是存在 arr 数组中的字符串。
而指针是存储了字符串在静态存储区的位置,因此这种方式的字符串只有一个副本。
注意:arr 是地址常量,而 pt 是指针变量,因此不能进行 arr++ 这种操作,但 pt++ 却可以取出下一个位置的元素。
例1:
#include <stdio.h>
#define MSG "I'm a const string!"
int main(void)
{
char arr[] = MSG;
char * pt = MSG;
printf("address of MSG is : %p \n", MSG);
//指定字符串与 MSG 内容相同
printf("address of \"I'm a const string!\" is : %p \n", "I'm a const string!");
printf("address of pt is : %p \n", pt);
printf("address of arr is : %p \n", arr);
return 0;
}
/*输出结果:
address of MSG is : 0x400650
address of "I'm a const string!" is : 0x400650
address of pt is : 0x400650
address of arr is : 0x7ffce33adba0
*/
分析结果:
两个字符串常量的地址一样,说明相同的字符串常量只存储了一次(与编译器采取的策略有关);指针与 MSG 的地址一样,说明指针是直接使用的原字符串,arr 与 MSG 的地址不一样,说明 arr 使用的是字符串的拷贝。
字符串常量被视为一个 const 类型的数据,因此应该使用指向 const 的指针。即:const char * pt = MSG;
例2:
#include <stdio.h>
#define MSG "I'm a const string!"
int main(void)
{
char arr[] = MSG;
char * pt = MSG;
printf("pt[0] is: %s\n", pt);
printf("pt[1] is: %s\n", ++pt);
printf("arr[0] is: %s\n", arr);
/*输出结果:
pt[0] is: I'm a const string!
pt[1] is: 'm a const string!
arr[0] is: I'm a const string!
*/
printf("arr[1] is: %s\n", ++arr);
/*编译错误:
arr_pt2.c: In function ‘main’:
arr_pt2.c:12:27: error: lvalue required as increment operand
printf("arr[1] is %s\n", ++arr);
*/
return 0;
}
分析结果:
该结果说明 pt 是变量,而数组名 arr 是地址常量,但是数组的元素是变量。
2.4 指针数组
#include <stdio.h>
int main(void)
{
int i;
//声明指针数组
const char *ptarry[5] = { "aaaaaaaaaaaa", "bbbbbbbbbbbbb", "ccccccccccccccc", "dddddddddddd", "eeeeeeeeeeee" };
//声明普通数组
char arry[5][40] = { "aaaaaaaaaaaa", "bbbbbbbbbbbbb", "ccccccccccccccc", "dddddddddddd", "eeeeeeeeeeee" };
printf("%-36s %-25s\n", "ptarry", "arry");
for (i = 0; i < 5; i++)
printf("%-36s %-25s\n", ptarry[i], arry[i]);
printf("\n size of ptarry is : %zd, size of arry is %zd", sizeof(ptarry), sizeof(arry));
return 0;
}
/*运行结果
ptarry arry
aaaaaaaaaaaa aaaaaaaaaaaa
bbbbbbbbbbbbb bbbbbbbbbbbbb
ccccccccccccccc ccccccccccccccc
dddddddddddd dddddddddddd
eeeeeeeeeeee eeeeeeeeeeee
size of ptarry is : 40, size of arry is 200
*/
运行结果:
ptarry 的大小是 40字节, 而 arry 的大小是 200字节(具体大小与系统有关),因为在本系统中一个指针占 8 字节,即 64 位,所以 5 个指针占了 40 字节,而 arry 是 5 * 40 = 200 字节。
参考书籍
C Primer Plus (第六版)中文版