文章目录
原文转帖于:https://blog.csdn.net/ksws0292756/article/details/79432329
在C++中,有2种类型
的字符串表示形式:
- C-风格字符串
- C++引入的string类
1 C-风格字符串
C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null
字符 '\0'
终止的一维字符数组。因此,1个以 null
结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 “Hello”
字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello”
的多1个
字符。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
其实,不需要把 null
字符放在字符串常量的末尾。C++ 编译器会在初始化数组时,自动把 '\0'
放在字符串的末尾。所以也可以利用下面的形式进行初始化
char greeting[] = "Hello";
以下是 C/C++ 中定义的字符串的内存表示:
C++ 中有大量的函数用来操作以 null
结尾的字符串:
序号 | 函数 | 功能 |
---|---|---|
1 | strcpy(s1,s2) | 复制字符串 s2 到字符串 s1 |
2 | strcat(s1,s2) | 连接字符串 s2 到字符串 s1 的末尾 |
3 | strlen(s1) | 返回字符串 s1 的长度 |
4 | strcmp(s1,s2) | 返回s1与s2的比较结果 |
5 | strchr(s1,ch) | 返回一个指针,指向字符串s1中字符ch的第1次 出现的位置 |
6 | strstr(s1,s2) | 返回一个指针,指向字符串s1中s2的第1次 出现的位置 |
2 C++ 中的 String 类
C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。比如:
- append() – 在字符串的末尾添加字符
- find() – 在字符串中查找字符串
- insert() – 插入字符
- length() – 返回字符串的长度
- replace() – 替换字符串
- substr() – 返回某个子字符串
- …
3 4种字符串类型
C++中的字符串一般有以下4种类型
:
string
char *
const char *
char[]
下面分别做简单介绍,并说明其中的一些区别:- string
string是一个C++类库中的一个类,它位于名称空间std中,因此必须使用using编译指令或者std::string来引用它。它包含了对字符串的各种常用操作,它较char*的优势是内容可以动态拓展,以及对字符串操作的方便快捷,用+号进行字符串的连接是最常用的操作 - char *
char* 是指向字符串的指针(其实严格来说,它是指向字符串的首个字母),你可以让它指向一串常量字符串。 - const char *
该声明指出,指针指向的是一个const char类型,即不能通过当前的指针对字符串的内容作出修改
注意这里有两个概念:
char * const
[指向字符的静态指针]
const char *
[指向静态字符的指针]
前者const修饰的是指针,代表不能改变指针
后者const修饰的是char,代表字符不能改变,但是指针可以变,也就是说该指针可以指针其他的const char。 - char[]
与char *
与许多相同点,代表字符数组,可以对应一个字符串,如
char * a="string1";
char b[]="string2";
这里a
是一个指向char变量的指针
,b
则是一个char数组(字符数组)
也就是说:
【1】char*是变量,值可以改变, char[]是常量,值不能改变!
a
是一个char型指针变量,其值(指向)可以改变;
b
是一个char型数组的名字,也是该数组首元素的地址,是常量,其值不可以改变
【2】char[]对应的内存区域总是可写,char*指向的区域有时可写,有时只读!
比如:
char * a="string1";
char b[]="string2";
gets(a); //试图将读入的字符串保存到a指向的区域,运行崩溃!
gets(b) //OK
解释: a
指向的是一个字符串常量,即指向的内存区域只读
;
b
始终指向他所代表的数组在内存中的位置,始终可写
!
注意,若改成这样gets(a)
就合法了:
char * a="string1";
char b[]="string2";
a=b; //a,b指向同一个区域
gets(a) //OK
printf("%s",b) //会出现gets(a)时输入的结果
解释: a
的值变成了是字符数组首地址,即&b[0]
,该地址指向的区域是char *
或者说 char[8]
,习惯上称该类型为字符数组
,其实也可以称之为“字符串变量”
,区域可读可写
。
总结:char *
本身是一个字符指针变量
,但是它既可以指向字符串常量,又可以指向字符串变量,指向的类型决定了对应的字符串能不能改变!
【3】char *
和char[]
的初始化操作有着根本区别:
测试代码:
char *a="Hello World";
char b[]="Hello World";
printf("%s, %d\n","Hello World", "Hello World");
printf("%s, %d %d\n", a, a, &a);
printf("%s, %d %d\n", b, b, &b);
结果:
Hello World,13457308
Hello World,13457308 2030316
Hello World,2030316 2030316
结果可见: 尽管都对应了相同的字符串,但”Hellow World”
的地址 和 a
对应的地址相同,与b
指向的地址有较大差异;&a 、&b
都是在同一内存区域,且&b==b
根据c
内存区域划分知识,我们知道,局部变量都创建在栈区
,而常量
都创建在文字常量区
,显然,a、b
都是栈区
的变量,但是a
指向了常量(字符串常量)
,b
则指向了变量(字符数组)
,指向了自己(&b==b==&b[0])
。
说明以下问题:
char * a=”string1”;是实现了3个操作:
- 声明一个char*变量(也就是声明了一个指向char的指针变量);
- 在内存中的文字常量区中开辟了一个空间存储字符串常量”string1”
- 返回这个区域的地址,作为值,赋给这个字符指针变量a
最终的结果: 指针变量a
指向了这一个字符串常量“string1”
(注意,如果这时候我们再执行:char * c=”string1”
;c==a
,实际上,只会执行上述步骤的1和3
,因为这个常量"string1"
已经在内存中创建)
char b[]=”string2”;则是实现了2个操作:
- 声明一个char的数组;
- 为该数组“赋值”,即将
”string2”
的每一个字符分别赋值给数组的每一个元素
最终的结果: “数组的值”(注意不是b的值
)等于”string2”,而不是b
指向一个字符串常量
实际上, char * a=”string1”;
的写法是不规范的!
因为a
指向了即字符常量
,一旦strcpy(a,”string2”)
就糟糕了,试图向只读的内存区域写入,程序会崩溃的!尽管VS下的编译器不会警告,但如果你使用了语法严谨的Linux下的C编译器GCC,或者在windows下使用MinGW编译器就会得到警告。
所以,我们还是应当按照”类型相同赋值”
的原则来写代码:
const char * a="string1";
保证意外赋值语句不会通过编译
另外,关于char*
和char[]
在函数参数
中还有一个特殊之处,运行下面的代码:
void fun1 ( char *p1, char p2[] ) {
printf("%s %d %d\n",p1,p1,&p1);
printf("%s %d %d\n",p2,p2,&p2);
p2="asdf"; //通过! 说明p2不是常量!
printf("%s %d %d\n",p2,p2,&p2);
}
void main(){
char a[]="Hello";
fun1(a,a);
}
运行结果:
Hello 3471628 3471332
Hello 3471628 3471336
asdf 10704764 3471336
结果出乎意料!上面结果表明p2
这时候根本就是一个指针变量
!
结论:作为函数的形式参数,两种写法完全等效的!都是指针变量!
3.1 const char*与char[]的区别:
const char * a=”string1”
char b[]=”string2”;
二者的区别在于:
a
是const char 类型
, b
是char const类型
a
是一个指针变量
,a的值(指向)是可以改变的,但a只能指向(字符串)常量,指向的区域的内容不可改变;
b
是一个指针常量
,b的值(指向)不能变;但b指向的目标(数组b在内存中的区域)的内容是可变的
作为函数声明参数
的时候,char []
是被当做char *
来处理的!两种形参声明写法完全等效!
4 字符串类型之间的转换: string、const char*、 char* 、char[]相互转换
4.1 转换表格
序号 | 源格式->目标格式 | string | char* | const char* | char[] |
---|---|---|---|---|---|
1 | string | NULL | 直接赋值 | 直接赋值 | 直接赋值 |
2 | char* | strcpy | NULL | const_cast | char*=char |
3 | const char* | c_str() | 直接赋值 | NULL | const char*=char |
4 | char[] | copy() | strncpy_s() | strncpy_s() | NULL |
4.2 总结方法
- 变成
string
,直接赋值。 char[]
变成别的,直接赋值。char*
变const char*
容易,const char*
变char*
麻烦。const_cast<char*>(const char*变量)
string
变char*
要通过const char*
中转。- 变成
char[]
。string逐个赋值
。
4.3 代码示例
【1】string
⇒ 其他类型
string
转const char*
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
std::string str = "HelloWorld!"; //初始化string类型,并具体赋值
const char* constc = nullptr; //初始化const char*类型,并赋值为空
constc= str.c_str(); //string类型转const char*类型
printf_s("%s\n", str.c_str()); //打印string类型数据 .c_str()
printf_s("%s\n", constc); //打印const char*类型数据
return 0;
}
string
转char*
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
std::string str = "HelloWorld!"; //初始化string类型,并具体赋值
char* c = nullptr; //初始化char*类型,并赋值为空
const char* constc = nullptr; //初始化const char*类型,并赋值为空
constc= str.c_str(); //string类型转const char*类型
c= const_cast<char*>(constc); //const char*类型转char*类型
printf_s("%s\n", str.c_str()); //打印string类型数据 .c_str()
printf_s("%s\n",c); //打印char*类型数据
return 0;
}
string
转char[]
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
std::string str = "HelloWorld!"; //初始化string类型,并具体赋值
char arrc[20] = {0}; //初始化char[]类型,并赋值为空
for (int i = 0; i < str.length(); i++) //string类型转char[]类型
{
arrc[i]=str[i];
}
printf_s("%s\n", str.c_str()); //打印string类型数据 .c_str()
printf_s("%s\n", arrc); //打印char[]类型数据
return 0;
}
【2】const char*
⇒ 其他类型
const char*
转string
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
const char* constc = "Hello World!"; //初始化const char* 类型,并具体赋值
std::string str; //初始化string类型
str= constc; //const char*类型转string类型
printf_s("%s\n", constc); //打印const char* 类型数据
printf_s("%s\n", str.c_str()); //打印string类型数据
return 0;
}
const char*
转char*
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
const char* constc = "Hello World!"; //初始化const char* 类型,并具体赋值
char* c = nullptr; //初始化char*类型
c= const_cast<char*>(constc); //const char*类型转char*类型
printf_s("%s\n", constc); //打印const char* 类型数据
printf_s("%s\n", c); //打印char*类型数据
return 0;
}
const char*
转char[]
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
const char* constc = "Hello World!"; //初始化const char* 类型,并具体赋值
char arrc[20] = { 0 }; //初始化char[]类型,并赋值为空
strncpy_s(arrc,constc,20); //const char*类型转char[]类型
printf_s("%s\n", constc); //打印const char* 类型数据
printf_s("%s\n", arrc); //打印char[]类型数据
return 0;
}
【3】char*
⇒ 其他类型
char*
转string
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
char* c = "HelloWorld!"; //初始化char* 类型,并具体赋值
std::string str; //初始化string类型
str= c; //char*类型转string类型
printf_s("%s\n", c); //打印char* 类型数据
printf_s("%s\n", str.c_str()); //打印string类型数据
return 0;
}
char*
转const char*
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
char* c = "HelloWorld!"; //初始化char* 类型,并具体赋值
const char* constc = nullptr; //初始化const char* 类型,并具体赋值
constc= c; //char*类型转const char* 类型
printf_s("%s\n", c); //打印char* 类型数据
printf_s("%s\n", constc); //打印const char* 类型数据
return 0;
}
char*
转char[]
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
char* c = "HelloWorld!"; //初始化char* 类型,并具体赋值
char arrc[20] = { 0 }; //初始化char[] 类型,并具体赋值
strncpy_s(arrc,c,20); //char*类型转char[] 类型
printf_s("%s\n", c); //打印char* 类型数据
printf_s("%s\n", arrc); //打印char[]类型数据
return 0;
}
【4】char[]
⇒ 其他类型
#include "stdafx.h"
#include <iostream>
int _tmain(intargc, _TCHAR* argv[])
{
char arrc[20] = "HelloWorld!";//初始化char[] 类型并具体赋值
std::string str; //初始化string
const char* constc = nullptr; //初始化const char*
char*c = nullptr; //初始化char*
str= arrc; //char[]类型转string类型
constc= arrc; //char[]类型转const char* 类型
c= arrc; //char[]类型转char*类型
printf_s("%s\n", arrc); //打印char[]类型数据
printf_s("%s\n", str.c_str()); //打印string类型数据
printf_s("%s\n", constc); //打印const char* 类型数据
printf_s("%s\n", c); //打印char*类型数据
return 0;
}