3. 字符指针
我们已经知道, 字符串常量是由双引号括起来的字符序列, 例如:
"a string"
就是一个字符串常量, 该字符串中因为字符a后面还有一个空格字符, 所以它由8
个字符序列组成。在程序中如出现字符串常量C 编译程序就给字符串常量按排一
存贮区域, 这个区域是静态的, 在整个程序运行的过程中始终占用, 平时所讲的
字符串常量的长度是指该字符串的字符个数, 但在按排存贮区域时, C 编译程序
还自动给该字符串序列的末尾加上一个空字符'\0', 用来标志字符串的结束, 因
此一个字符串常量所占的存贮区域的字节数总比它的字符个数多一个字节。
Turbo C中操作一个字符串常量的方法有:
(1). 把字符串常量存放在一个字符数组之中, 例如:
char s[]="a string";
数组s共有9个元素所组成, 其中s[8]中的内容是'\0'。实际上, 在字符数组定义
的过程中, 编译程序直接把字符串复写到数组中, 即对数组s初始化。
(2). 用字符指针指向字符串, 然后通过字符指针来访问字符串存贮区域。
当字符串常量在表达式中出现时, 根据数组的类型转换规则, 它被转换成字符指
针。因此, 若我们定义了一字符指针cp:
char *cp;
于是可用:
cp="a string";
使cp指向字符串常量中的第0号字符a, 如图7.所示。
cp
┏━━━┓ ┏━┳━┳━┳━┳━┳━┳━┳━┳━┓
┃ ─╂─→ ┃a ┃ ┃s ┃t ┃r ┃i ┃n ┃g ┃\0┃
┗━━━┛ ┗━┻━┻━┻━┻━┻━┻━┻━┻━┛
图7.
以后我们可通过cp来访问这一存贮区域, 如*cp或cp[0]就是字符a, 而cp[i]或
*(cp+i)就相当于字符串的第i号字符, 但企图通过指针来修改字符串常量的行为
是没有意义的。
4. 指针数组
因为指针是变量, 因此可设想用指向同一数据类型的指针来构成一个数组,
这就是指针数组。数组中的每个元素都是指针变量, 根据数组的定义, 指针数组
中每个元素都为指向同一数据类型的指针。指针数组的定义格式为:
类型标识 *数组名[整型常量表达式];
例如:
int *a[10];
定义了一个指针数组, 数组中的每个元素都是指向整型量的指针, 该数组由10个
元素组成, 即a[0], a[1], a[2], ..., a[9], 它们均为指针变量。a为该指针数
组名, 和数组一样, a是常量, 不能对它进行增量运算。a为指针数组元素a[0]的
地址, a+i为a[i]的地址, *a就是a[0], *(a+i)就是a[i]。
为什么要定义和使用指针数组呢? 主要是由于指针数组对处理字符串提供了
更大的方便和灵活, 使用二维数组对处理长度不等的正文效率低, 而指针数组由
于其中每个元素都为指针变量, 因此通过地址运算来操作正文行是十分方便的。
指针数组和一般数组一样, 允许指针数组在定义时初始化, 但由于指针数组
的每个元素是指针变量, 它只能存放地址, 所以对指向字符串的指针数组在说明
赋初值时, 是把存放字符串的首地址赋给指针数组的对应元素, 例如下面是一个
书写函数month_name(n), 此函数返回一个指向包含第n月名字的字符指针( 关于
函数, 第6节将专门介绍)。
例2: 打印1月至12月的月名:
char *month_name(int n)
{
static char *name[]={
"Illegal month",
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
return((n<1||n>12)?name[0]:name[n]);
}
main()
{
int i;
for(i=0; i<13; i++)
printf("%s\n", month_name(i));