一、字符串常量默认类型是const char *,不是右值,有地址
在C++11之前字符串常量默认类型是char *,C++11后改为const char *。
首先C++不允许给指针直接分配右值的。
数字6是整型字面量,是一个右值,不可取地址,故报错,但"AAAA"作为字符串字面量却可以直接赋值给const char*指针,由此可见"AAAA"并不是一个右值,而是在内存中有实实在在的位置的。
#include <iostream>
using namespace std;
int main() {
const char *p="AAAA";//不报错
const int *p1=&6;//报错
}
另外C++字符串常量也是有字符串池的概念,对于同一个字符串常量,所有指针都指向该字符串,辅助证明:
#include <iostream>
using namespace std;
int main() {
const char *p="AAAA";//不报错
char p1[]="AAAA";//不报错
const char *p2="AAAA";//不报错
cout<<(void *)p<<endl;//和p2地址一样
cout<<(void *)p1<<endl;//和p与p2地址均不同
cout<<(void *)p2<<endl;//和p地址一样
cout<<&"AAAA"<<endl;//不用多说
//const int *p1=&6;//报错
}
字符串常量是位于静态存储区的,全局唯一。
p和p2的地址一样,但p1的地址却不同,可以理解为C++将静态存储区的字符串拷贝到栈上,专门给字符数组单独复制一份。
二、不要修改字符串常量,不要delete字符串常量指针
#include <iostream>
using namespace std;
int main() {
const char *p="AAAA";//不报错
char p1[]="AAAA";//不报错
const char *p2="AAAA";//不报错
char *p3=const_cast<char *>(p);
*p3='a';//修改字符串常量
*p1='a';//修改字符数组
delete p;
}
通过指针修改静态存储区的字符串常量和释放指向字符串常量的指针会导致程序异常退出,但通过字符数组却不会。
三、string类的使用
string类和字符数组是一样的,string内部有一个指针用于管理字符串常量的副本,和静态存储区的是两个东西。
只不过string和字符数组存储和使用字符串相比更加方便。
#include <iostream>
using namespace std;
int main() {
const char *p="AAAA";
string s1("AAAA");
s1[0]='B';
cout<<(void *)p<<endl;//两者地址不同
cout<<(void *)s1.c_str()<<endl;
((char *)s1.c_str())[1]='B';
cout<<s1<<endl;//结果为:"BBAA"
}
四、如何使用字符串
如果在整个程序期间都不会改变就使用const char* ,反之使用string类。区分字符串常量、字符数组、string类的使用。