山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省
如在printf函数中输出一个字符串。这些字符串都是以直接形式(字面形式)给出的,在一对双撇号中包含若干个合法的字符。使用字符串的更加灵活方便的方法——通过指针引用字符串。
字符串的引用方式
在C程序中,字符串是存放在字符数组中的。想引用一个字符串,可以用以下两种方法。
( 1 )用字符数组存放一个字符串,可以通过数组名和下标引用字符串中一个字符,也可以通过数组名和格式声明“% s”输出该字符串。
例题1:
定义一个字符数组,在其中存放字符串" I love China !”,输出该字符串和第8个字符。
解题思路:
定义字符数组string,对它初始化,由于在初始化时字符的个数是确定的,因此可不必指定数组的长度。用数组名string和输出格式%s可以输出整个字符串。用数组名和下标可以引用任一数组元素。
编写程序:
运行结果:
程序分析:
在定义字符数组string时未指定长度,由于对它初始化,因此它的长度是确定的,长度应为14,其中13个字节存放" I love China ! "13个字符,最后一个字节存放字符串结束符' \0 '。数组名string代表字符数组首元素的地址。题目要求输出该字符串第8个字符,由于数组元素的序号从0起算,所以应当输出string [ 7 ],它代表数组中序号7的元素的值(它的值是字母C)。实际上string [ 7 ]就是* ( string + 7 ),string + 7是一个地址,它指向字符“C”。
( 2 )用字符指针变量指向一个字符串常量,通过字符指针变量引用字符串常量。
例题2:
通过字符指针变量输出一个字符串。
解题思路:
可以不定义字符数组,只定义一个字符指针变量,用它指向字符串常量中的字符。通过字符指针变量输出该字符串。
编写程序:
运行结果:
I love China!
程序分析:
在程序中没有定义字符数组,只定义了一个char*型的指针变量(字符指针变量)string,用字符串常量" I love China !”对它初始化。C语言对字符串常量是按字符数组处理的,在内存中开辟了一个字符数组用来存放该字符串常量,但是这个字符数组是没有名字的,因此不能通过数组名来引用,只能通过指针变量来引用。
对字符指针变量string初始化,实际上是把字符串第1个元素的地址(即存放字符串的字符数组的首元素地址)赋给指针变量string,使string指向字符串的第1个字符,由于字符串常量“Ilove China !”已由系统分配在内存中连续的14个字节中,因此,string就指向了该字符串的第一个字符。在不致引起误解的情况下,为了简便,有时也可说string指向字符串" I love China !”,但应当理解为“指向字符串的第1个字符”。
说明:有人误认为string是一个字符串变量,以为在定义时把“I love China !”这几个字符赋给该字符串变量,这是不对的。在C语言中只有字符变量,没有字符串变量。
分析定义string的行:
char * string = " I love China !”;
等价于下面两行:
char * string ;
string = " I love China ! ";
注意:string被定义为一个指针变量,基类型为字符型。请注意它只能指向一个字符类型数据,而不能同时指向多个字符数据,更不是把“Ilove China ! "这些字符存放到string中(指针变量只能存放地址),也不是把字符串赋给* string。只是把" I love China !”的第1个字符的地址赋给指针变量string。
不要认为上述定义行等价于
char * string ;
* string = " I love China !”;
可以对指针变量进行再赋值,如:
string = " I am a student , " ;
把字符串" I am a student .”的第一个字符的地址赋给指针变量string。此后string就指向" I am a student .”的第一个字符,不再指向" I love China !”的第一个字符了,因此不能再通过string引用字符串" I love China !”。
可以通过字符指针变量输出它所指向的字符串,如:
printf ( " % s\n " , string );
% s是输出字符串时所用的格式符,在输出项中给出字符指针变量名string,则系统会输出string所指向的字符串第1个字符,然后自动使string加1,使之指向下一个字符,再输出该字符…如此直到遇到字符串结束标志 \0 为止。注意,在内存中,字符串的最后被自动加了一个\0 ,因此在输出时能确定输出的字符到何时结束。可以看到,用%s可以对一个字符串进行整体的输入输出。
对字符串中字符的存取,可以用下标方法,也可以用指针方法。
例题3:
将字符串a复制为字符串b,然后输出字符串b。
解题思路:
定义两个字符数组a和b,用“I am a student .”对a数组初始化。将a数组中的字符逐个复制到b数组中。可以用不同的方法引用并输出字符数组元素,今用地址法算出各元素的值。
编写程序:
运行结果:
程序分析:
程序中a和b都定义为字符数组,今通过地址访问其数组元素。在for语句中,先检查a [ i ]是否为 \0 ( a [ i ]是以* ( a + i )形式表示的)。如果不等于 \0 ,表示字符串尚未处理完,就将a [ i ]的值赋给b [ i ],即复制一个字符。在for循环中将a串中的有效字符全部复制给了b数组。最后还应将\0复制过去,作为字符串结束标志。故有
* ( b + i ) =' \0 ';
在第2个for循环中输出b数组中的元素,在printf函数中用下标法表示一个数组元素(即一个字符)。也可以用输出a数组的方法输出b数组。用以下一行代替程序的10 ~13行。
printf ( " string b is : % s\n " , b ) ;
程序中用逐个字符输出的方法只是为了表示可以用不同的方法输出字符串。
也可以用另一种方法,用指针变量访问字符串。通过改变指针变量的值使它指向字符串中的不同字符。
例题4:
用指针变量来处理例3问题。
解题思路:
定义两个指针变量p1和p2,分别指向字符数组a和b。改变指针变量pl和p2的值,使它们顺序指向数组中的各元素,进行对应元素的复制。
编写程序:
运行结果:
程序分析:
p1和p2是指向字符型数据的指针变量。先使p1和p2分别指向字符串a和b的第1个字符。*p1最初的值是字母' I '。赋值语句“* p2 = * p1;”的作用是将字符' I ' ( a串中第1个字符)赋给p2所指向的元素,即b[ 0 ]。然后p1和p2分别加1,分别指向其下面的一个元素,直到*p1的值为'\0'止。
注意,p1和p2的值是不断在改变的,在for语句中的p1 ++和p2++使pl和p2同步移动。