1.字符指针能够指向一个字符串。
我们能够用字符串常量对字符指针进行初始化。
比如,有说明语句:
char *str = "This is a string.";
是对字符指针进行初始化。此时,字符指针指向的是一个字符串常量的首地址,即指向字符串的首地址。
这里要注意字符指针与字符数组之间的差别。比如,有说明语句:
char string[ ]="This is a string.";
此时。string是字符数组,它存放了一个字符串。
字符指针str与字符数组string的差别是:str是一个变量。能够改变str使它指向不同的字符串,但不能改变str所指的字符串常量。string是一个数组,能够改变数组中保存的内容。
2.实例:
char *str, *str1="This is another string.";
char string[100]="This is a string.";
则在程序中,能够使用例如以下语句:
str++; /* 指针str加1 */
str = "This is a NEW string."; /* 使指针指向新的字符串常量 */
str = str1; /* 改变指针str的指向 */
strcpy( string, "This is a NEW string.") /* 改变字符串的的内容 */
strcat( string, str) /* 进行串连接操作 */
在程序中,不能进行例如以下操作:
string++; /* 不能对数组名进行++运算 */
string = "This is a NEW string."; /* 错误的串操作 */
string = str1; /* 对数组名不能进行赋值 */
strcat(str, "This is a NEW string.") /* 不能在str的后面进行串连接 */
strcpy(str, string) /* 不能向str进行串复制 */
3.其他说明:
1) 以字符串形式出现的。编译器都会为该字符串自己主动加入一个0作为结束符,如在代码中写:"abc",那么编译器帮你存储的是"abc\0"
2) "abc"是常量吗?答案是有时是,有时不是。
不是常量的情况:"abc"作为字符数组初始值的时候就不是。如
char str[] = "abc";
由于定义的是一个字符数组,所以就相当于定义了一些空间来存放"abc"。而又由于字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为 char str[3] = {'a','b','c'};又依据上面的总结1,所以char str[] = "abc";的终于结果是 char str[4] = {'a','b','c','\0'};
做一下扩展。假设char str[] = "abc";是在函数内部写的话。那么这里的"abc\0"由于不是常量,所以应该被放在栈上。
是常量的情况: 把"abc"赋给一个字符指针变量时,如
char* ptr = "abc";
由于定义的是一个普通指针。并未定义空间来存放"abc"。所以编译器得帮我们找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器最合适的选择。所以虽然ptr的类型不是const char*,而且ptr[0] = 'x';也能编译通过,可是执行ptr[0] = 'x';就会发生执行时异常,由于这个语句试图去改动程序常量区中的东西。
记得哪本书中以前说过char* ptr = "abc";这样的写法原来在c++标准中是不同意的。可是由于这样的写法在c中实在是太多了。为了兼容c。不同意也得同意。尽管同意,
可是建议的写法应该是const char* ptr = "abc";这样假设后面写ptr[0] = 'x'的话编译器就不会让它编译通过,也就避免了上面说的执行时异常。
又扩展一下。假设char* ptr = "abc";写在函数体内,那么尽管这里的"abc\0"被
放在常量区中,可是ptr本身仅仅是一个普通的指针变量,所以ptr是被放在栈上的, 仅仅只是是它所指向的东西被放在常量区罢了。
3) 数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。
如char s1[3]和char s2[4],s1的类型就是char[3]。s2的类型就是char[4],
也就是说虽然s1和s2都是字符数组,但两者的类型却是不同的。
4) 字符串常量的类型能够理解为对应字符常量数组的类型。
如"abcdef"的类型就能够看成是const char[7]
5) sizeof是用来求类型的字节数的。
如int a;那么不管sizeof(int)或者是sizeof(a)都是等于4。由于sizeof(a)事实上就是sizeof(type of a)
6) 对于函数參数列表中的以数组类型书写的形式參数,编译器把其解释为普通的指针类型,如对于void func(char sa[100],int ia[20],char *p)
则sa的类型为char*,ia的类型为int*,p的类型为char*
7) 依据上面的总结,来实战一下:
对于char str[] = "abcdef";就有sizeof(str) == 7,由于str的类型是char[7],
也有sizeof("abcdef") == 7,由于"abcdef"的类型是const char[7]。
对于char *ptr = "abcdef";就有sizeof(ptr) == 4。由于ptr的类型是char*。
对于char str2[10] = "abcdef";就有sizeof(str2) == 10,由于str2的类型是char[10]。
对于void func(char sa[100],int ia[20],char *p);
就有sizeof(sa) == sizeof(ia) == sizeof(p) == 4。
由于sa的类型是char*,ia的类型是int*。p的类型是char*。
4.差别:
(1)字符数组由若干个元素组成。每一个元素中存放字符串的一个字符。而字符指针变量中存放的是字符串的首地址。
(2)初始化方式不同。对字符数组初始化要用static存储类别,在编译时进行。
而对字符指针变量初始化不必加static,在实际运行时进行。
(3)赋值方式不同。对字符数组不能总体赋值,仅仅能转化成份量。对单个元素进行。
而字符指针变量赋值可总体进行。
比如:
char s[10]。
s= \"C++\";/*错。s是常量,怎能被赋值*/
(4)在定义一个字符数组时,编译时即已分配内存单元。有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,但该指针变量详细指向哪个字符串,并不知道,即指针变量存放的地址不确定。比如:
char a[10];
char *p;
scanf(\"%s\",s);/*正确*/
scanf(\"%s\",p);/*很危急,p的值动态*/
(5)字符指针变量的值能够改变,字符数组名是一个常量,不能改变。
比如。有简单程序:
#include <stdio.h>
int main()
{
char *s = "china man";
s+= 6;
printf("%s\n",s);
getchar();
return 0;
}
执行结果:man