目录
1、关于c语言中的字符串
(1)c语言中字符串与字符指针
(2)字符串结尾
2、关于c++中的字符串string
(1)从本质上了解string
(2)两种语言间字符串的转换与关联
(3)关于字符串中的'\0'
为了方便对字符串进行操作与弥补c语言对字符串操控的不足,c++推出了string类,并且随着c++不断发展,string类完全可以当做一个容器(STL的vector容器等)进行使用(此处不进步展开)。那么c++中的string与c语言的字符串又有那些联系与区别:
char* str="hello!";
本质上:字符指针str指向字符串首(也就是首元素的地址),c语言中的字符串存储于全局区(具体来讲是全局区中的常量区),那么问题来了,在c语言中指向的字符串可以改变吗?
答:在c语言中可以改变(为了指针操控地址的方便),但是修改的是其副体,本体不能修改!
char* str="hello!";//只在常量区中有本体
*str='a';//编译通过,但运行时错误
char str1[]={"hellow!"};//在常量区中开辟空间,但是在栈区有其副本
*str1='b';//运行通过
上述代码改变了首元素的值。
C++从声明上规范了字符串不可以改变,通过指针常量严格限制对指针修改,因此在C++中声明字符串前必须加const,如下:
const char* str1="hello";
char* str2="hello";//error,因为变量存储于常量区,其值不可以改变
*str1='a';//error,指针常量中,指针指向的内容不可以改变
因此可以得出结论:C++中的字符串才是真正意义上的字符串,C语言中的字符串并非严格意义上的字符串。
有人好奇,为什么仅仅通过一个字符指针指向字符串的首元素就可以知道整个字符串的值,因为字符串在物理结构内存中连续存储,且以'\0'结尾。
我们可以通过以下方式进行遍历字符串中的每一个元素:
const char* str="hello";
while(*str!='\0')
{
printf("%c\n",*str);
}
因此进行字符串拷贝时,一定不要忘记'\0'也需要占一个字节空间,空间需要扩充一个字节:
const char* str="hello";
char* str1=(char*)malloc(strlen(str)+1);
于是有人发问,同样可以存储字符串的字符数组是否也是以'\0'结尾?
答:分情况!常规字符数组(第(1)种情况)通过数组的数目可以知道整个字符串的值,因此完全没有必要这样做另外字符数组是在栈区开辟空间,并不是在常量区!
(1)char ch2[]={'h','e','l','l','o'};//该形式不是以'\0'结尾
(2)char ch1[]="hhhfjkkk";//该形式以'\0'结尾
我们可以通过以下例子来进一步来证明我们的猜想与结论:
(1)第一种情况:
char ch[] = { 'h','e','l','l','o' };
cout << sizeof(ch) << endl;
if (ch[5]=='\0')
{
cout << "the string end is \\0" << endl;
}
else
{
cout << "the string end is not \\0" << endl;
}
输出如下:
(2)第二种情况:
然后所有的字符数组都不需要'\0'结尾吗?事实上不是这样的,我们看以下例子:
char ch1[80] = "123abcdEFG*&"; // 该字符数组仍然是以'\0'结尾
for (int j = 0; ch1[j] != '\0'; j++)
{
cout << ch1[j] << endl;
}
从输出结果可以看出,可见以该形式进行初始化的字符数组仍然是以'\0'结尾,原因如C语言中的字符串一样,如果没有该结尾标志符,那么无法确定该字符数组的长度(尾元素)
string其实是c++中标准库的一个类,不过该类确实很“聪明”与“灵活”,既可以当做一个类来使用,也可以当做一个容器来使用(begin(),end()……等模板容器中的东西几乎都快要使用,想玩,自己亲自写代码去体会一下,哈哈哈)。
那么问题来了,c++中的string类是否也是以'\0'结尾?
答:是的,这一点继承了C语言的风格!
我们来看以下例子:
string str1("hello world!");
if (str1[str1.size()] == '\0')
{
cout << "该字符串以\\0结尾" << endl;
}
输出如下:
我们可以通过string的成员函数获取字符串的首地址:c_str();注意:该首地址是一个指针常量,指向的内容不可以改变。
string str1("hello world!");
const char* str2 = str1.c_str();//注意必须是const,否则报错
面对const,令人比较棘手,因为我们无法进行修改指针对应的内容,而有时候我们又必须进行修改该内容,那么我们应该怎么办?例如以下函数:
//转为小写字母
string toLowerCase(string s)
因此我们需要建立一个char* str指向s[0],并且建立一个临时字符串,如下所示:
//转为小写字母
string toLowerCase(string s)
{
string tmp;
if (s.empty())
{
return NULL;
}
char* str = &s[0];
while (*str!='\0')
{
if (*str<='Z'&&*str>='A')
{
*str = *str + 32;
}
tmp.push_back(*str);
str++;
}
return tmp;
}
我们看以下例子:
string str1("hello\0 world!");
cout << str1 << endl;
那么输出为什么呢?hello呢还是hello\0 world!?
因为遇到'\0'自动忽略后面的字符,那么问题来了,str1的字符长度(不包含'\0')又为多少呢?
string str1("hello\0 world!");
cout << str1.length() << endl;
cout << strlen(str1.c_str()) << endl;
由以上输出可知,字符串的长度并不包括'\0'。
谢谢你的支持!