这个问题是C++基础问题中相当折腾人的一个,死记硬背解决不了根本问题,记住还是要忘,需要仔细研究其本质。
这两种方式就是数组和指针的方式:1
2char a[6] = "abcde";
char *b = "abcde";
第一行声明了并初始化了一个char数组,第二行是声明char指针b,指向了常量字符串。其中a是数组的首地址,a和b的地址一定不同。
千万不能说数组名是指针,可以用sizeof来否定:1
2char a[]="abcde";
cout<<sizeof(a)<<endl;
如果a是个指针,那么结果是4,但结果是6.
数组不能被直接复制,所以当数组名作为函数参数的时候,要么就是数组的引用,要么就是指向第一个元素的指针,他们的值是相等的。当你对一个数组做&的时候,他提取的是指向数组的指针,然后仍然可以隐式转换成指向第一个元素的指针,而且它们的值是相等的。
这样的代码是错的:1
2char a[6] = "abcde";
a[6] = "asdfge";
只有声明里才能用a[6]
,这就好比int a[6]={1,2,3,4,5,6};
,但不能再用a[6]={5,6,7,8,9,0};
。应该用a[0]='A';
这样的代码是正确的:1
2
3char a[]="abcde";
char *b;
b = a;
b是指针变量,指向了数组的首地址。
这样是错的:1
2
3char *a="abcde"; 或者 char a[]="abcde";
char b[6];
b = a;
实际上是上一种情况的相反,报错error: incompatible types in assignment of 'char*' to 'char [6]'
因为不存在一个隐式转换使得 char 被转换成 char[]。这个问题比较关键,我们可以把数组名b理解成一个常量指针,它不能指向其他地址,但指向的字符串可以改变。但是注意只是这么理解而已,数组名并不真的是常量指针。同样的,b++;
也是错的。
从另一个角度来看,*数组名做函数参数时会退化为指针,这里没有退化为指针的条件,所以b不能当指针变量用。
这样也是错的:1
2char a[6];
a = "abcde";
a是数组的首地址,怎么把字符串常量赋给它?
再看这种情况:1
2
3char *a, *b;
a = "abcde";
b = "abcde";
a和b的值不一定相同,也就是不一定是同一个地址,这取决于编译器的行为。
对于char指针和数组,以下操作都是可行的。1
2
3
4
5
6
7
8
9
10
11const char* p="abcd"; //在常量区,应当加const,否则编译器会报警
// char p[]="abcd"; // 在stack
cout<<p<<endl; // abcd
cout<<&(*p)<<endl; //abcd
cout<<*p<<endl; // a
cout<<&p<<endl; // 0x62fe9c
cout<<p+2<<endl; //cd
cout<<*(p+2)<<endl; //c
cout<<*p+2<<endl; //99
cout<<p[2]<<endl; //c
但下面操作仅适用于char数组,不能用于指针,指针指向的是常量:1
//p[0]='A';
对于数组char p[]="abcd";
,可以使用p[2]
,这是因为数组名在这里退化为指针,p转为指向数组首元素的char*
类型。也就是说指针本身就可以用[],反而是数组名需要先转换为指针才能用[]。看下面的例子:1
2
3
4
5
6int b[5] = {1,2,3,4,5};
int *f=b;
cout<<f[2]<<endl; // 3
f[2]=0;
cout<<f[2]<<endl; // 0
cout<<b[2]<<endl; // 0
对于常量字符串,都可以用数组下标,这种做法比较少见:1
cout<<"abcd"[2]; //c