字符串常量的定义与引用

周立功教授数年之心血之作《程序设计与数据结构》 第一章为程序设计基础,本文为1.8.2 字符串常量。
>>>> 1.8.2字符串常量
字符的真正价值在于你可以将它们串在一起形成一个字符序列,即字符串常量,简称字符串。字符串常量就是使用一对双引号“”包围起来的,以空字符nul(null character,nul表示为'\0',ascii码值为0x00)结尾的连续的字符串,其长度为字符串的长度加1。既然使用空字符结束字符串,那么printf()和strcpy()都将这一点作为默认的前置条件。
注意,null和nul是不同的,null表示特殊的指针,通常定义为((void *)0),而nul是一个char,定义为\0,两者不能混用。虽然字符常量是由单引号引起来的字符序列,通常由一个字符组成,但也可以包含多个字符,比如,转义字符,在c中它们的类型是int:
printf(%d\n, sizeof(char));
printf(%d\n, sizeof('a'));
执行上述代码可以看到char的长度为1,而字符常量的长度为4。
只要在程序中使用字符串,就必须确定如何声明保存字符串的变量。如果将它声明为数组,则编译时就已经为各个字符保留了内存空间;如果将它声明为指针,则编译时完全没有为字符分配任何内存,仅在运行时分配空间。比如:
char cstr[4] = ok!;
char *pcstr = ok!;
两者的区别是,数组名cstr是常量,而指针名pcstr是变量。注意,如果在初始化指针之前就使用指针,有可能会导致运行出错,如果有以下定义:
char *pcstr;
printf(%s, *pcstr);
由于这里没有对pcstr初始化,因此其指向的内存是未知的,将会打印出奇怪的字符,于是pcstr自然也就成为了野指针。
>>>1.字符串的引用
由于ok!是一个字符串常量,因此是不可修改的。如果试图执行以下操作:
pcstr[2] = 'z';
虽然编译期可以通过,但在运行时会出错。如果以下面这样的形式赋值:
char cstr[4];
cstr = ok!;
则是非法的,因为数组变量名cstr是一个不可修改的常量指针。
如果字符数组中没有保存'\0'',它仅仅是字符常量'o'、'k'、'!',不是字符串。即:
char cstr[] = { 'o', 'k', '!'};
而“char cstr[] = ok!;”只不过是“char cstr[] = {'o', 'k', '!', '\0'};”的另一种写法,因为字符串是一种特殊的字符数组变量,所以其存储方式与数组变量一致。其中的cstr为数组变量名,表示此数组第0个元素的地址(即&cstr[0]),cstr+1表示数组第1个元素的地址(即&cstr[1]),cstr+2表示数组变量第2个元素的地址(即&cstr[2]),cstr+3表示数组变量第3个元素的地址(即&cstr[3]),其存储形式详见图1.13。
图1.13 “ok!”的存储形式
c语言中的字符串是以字符数组变量的形式处理的,具有数组的属性,所以不能赋值给整个字符数组变量,只能将字符逐个赋给字符数组变量。比如:
char cstr[4];
cstr[0] = 'o'; cstr[1] = 'k'; cstr[2] = '!'; cstr[3] = '\0';
其存储的不是字符本身,而是以ascii码存储的字符常量(即存值)。
惯用法
由于字符串常量以'\0'(ascii码值为0x00)结尾,因此可以用cstr[i]作为for循环语句的“条件部分(布尔表达式)”,检查cstr[i]是否为'\0'(cstr[i]是以*(cstr+i)形式表示的)。用于处理字符串中每一个字符的惯用法如下:
for(i = 0; cstr[i] != '\0'; i++) …
其等价于
for(i = 0; cstr[i]; i++) …
同理“while(cstr[i] != '\0')”与“while(cstr[i])”是等价的。
当然,也可以使用scanf()函数的%s格式声明符输入字符串,详见程序清单 1.37。
程序清单1.37字符串的输入与输出范例程序
1 #include
2 int main(int argc, char *argv[])
3 {
4 char cstr[10];
5
6 scanf(%s, cstr);
7 printf(%s, cstr);
8 return 0
9 }
由于cstr代表字符数组的起始地址,因此不需要在cstr前添加&运算符。但采用%s格式符输入字符串存在一种潜在危险,如果输入的字符串太长,超出了字符数组的存储极限,则程序执行错误,因此可以使用“字段宽度”来限制输入字符串的长度更安全。
由于字符串常量的类型是char的数组,则在表达式中被解读为指针。即不管字符串有多长,pcstr始终存储字符串第一个字符的地址,因此使用指向字符串的指针变量即可整体引用一个字符串。比如:
char *pcstr = ok!;
其中的pcstr是字符指针变量,其等效于
static const char t376[] = ok!;
char *pcstr = t376;
其中的t376是编译器分配的一个内部变量名,不同编译器、不同程序、甚至同一个源代码每次编译,其名字均可能不同。显然,程序员不知道这个数组的名字,即匿名数组变量。显而易见,初始化字符数组存储字符串和初始化指针指向字符串的区别在于,数组名是常量,而指针名是变量,因此字符串的绝大多数操作都是通过指针完成的。
由此可见,ok!就是“char的数组”,通过sizeof(ok!)也可以证明字符串的本质还是数组,即可用ok!作为数组变量名,详见程序清单 1.38。
程序清单1.38用字符串作为数组变量名范例程序
1 #include
2 int main(int argc, char argv *[])
3 {
4 printf(ok!占用的空间%d, sizeof(ok!)); // 输出ok!占用的空间,即4个字节
5 printf(ok!的地址%x\n, ok!);// 输出ok!的地址
6 printf(%c\n, *(ok! + 1)); //输出ok!的第1个元素,即'k'
7 printf(%c\n, ok![0]); //输出ok!的第0个元素,即'o'
8 printf(%d\n, ok![3]); //输出ok!第3个元素的值,即'\0'
9 return 0;
10 }
由于c语言允许对指针添加下标,因此程序清单 1.38(6~8)分别输出对应的元素。显然,可以利用这种方式将0~15转换为等价的16进制的字符,详见程序清单 1.39。
程序清单1.39 digit_to_charhex()转换函数范例程序
1 char digit_to_hexchar(int digit)
2 {
3 return 0123456789abcdef[digit];
4 }
当pcstr指向字符串ok!的首地址时,*pcstr表示该地址空间上的值为'o',即pcstr[0]= 'o',pcstr[1]= 'k',pcstr[2]= '!',pcstr[3]= '\0',或*pcstr='o',*(pcstr+1)='k',*(pcstr+2)='!',*(pcstr+3)= '\0'。

降低步进电机振动、噪音的解决方法
NP2301BVR 20V p通道增强模式MOSFET
ZigBee无线组网技术专利介绍
物流无人机风云再起 亿航强势突击
美国所有安全系统和智能家居设备的安装方法已趋于自行安装?
字符串常量的定义与引用
这才是手机内存不够用的原因!赶紧把微信这两大功能关了吧
智能农业灌溉系统方案
PCB多层板工艺的分类介绍
5g和4g有什么区别流量用的快吗
我国工控仪器产业自动化进程得到加速发展
华为荣耀V9比Mate9更是才貌:6GB超大运存+2K超高清屏幕+4000mAh大容量电池
只要简单接线配置,轻松将单级步进电机作为双级步进电机进行驱动
锐芯微:高灵敏度摄像机芯C2201、P2059处于小量产阶段
传苹果欲推8GB版iPhone 3GS抢占低端
地铁站内无线乘客求助系统设计方案
华为P10原型机多图曝光:正面指纹识别 机身厚度7毫米
led显示屏在报告厅中起到什么作用?
苹果新iPhone或继续使用刘海屏设计
人工智能领域已经开启全新篇章,合作共赢才是未来发展主旋律