C++字符串和字符数组

本文介绍了C++中两种字符串表示形式,即C-风格字符串和C++引入的string类。详细阐述了char[]、char*、const char*、string四种字符串类型的特点、区别,如char*和char[]在值的可变性、初始化操作等方面的差异。还提及了四种字符串类型之间的相互转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在C++中,有两种类型的字符串表示形式:

C-风格字符串
C++引入的string类

C-风格字符串

C 风格的字符串起源于C语言,并在C++中继续得到支持。字符串实际上是使用null字符‘\0’终止的一维字符数组。
下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

其实,不需要把null字符放在字符串常量的末尾。C++编译器会在初始化数组时,自动把‘\0’放在字符串的末尾。

char greeting[] = "Hello";

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的第一次出现的位置
  6. strstr(s1,s2); //返回一个指针,指向字符串s1中s2的第一次出现的位置

C++引入的string类

C++ 标准库提供了 string 类类型,支持上述所有的操作,另外还增加了其他更多的功能。比如:
append() – 在字符串的末尾添加字符
find() – 在字符串中查找字符串
insert() – 插入字符
length() – 返回字符串的长度
replace() – 替换字符串
substr() – 返回某个子字符串
……

4种字符串类型

C++中的字符串一般有以下四种类型:

  1. char[]
    代表字符数组,可以对应一个字符串,如
    char a[]=“astring”; //一个char数组(字符数组)

  2. char*
    char* 是指向字符串的指针(其实严格来说,它是指向字符串的首个字母),你可以让它指向一串常量字符串。

  3. const char*
    该声明指出,指针指向的是一个const char类型,即不能通过当前的指针对字符串的内容作出修改。

注意这里有两个概念:
char * const p1; //指向字符的静态指针,修饰指针p1,代表指针不能改变
const char * p2; //指向静态字符的指针,修饰char,代表字符不能改变,p2可以指向其他const char

  1. string
    string是一个C++类库中的一个类,它位于名称空间std中,因此必须使用using编译指令或者std::string来引用它。它包含了对字符串的各种常用操作,它较char*的优势是内容可以动态拓展,以及对字符串操作的方便快捷,用+号进行字符串的连接是最常用的操作。

提供示例:

#include<iostream>
#include <string>
using namespace std;

int main()
{
	char arr1[] = "abcd";  //arr1指向自身地址 
    char arr2[] = "abcd";
    const char arr3[] = "abcd";  //arr3指向自身地址
    const char arr4[] = "abcd";
    cout << (arr1 == &arr1[0]) << endl; // 结果是true,输出1,arr1表示的是字符数组的首地址
    cout << (arr1 == arr2) << endl;  //返回false,判断地址
    cout << (arr3 == arr4) << endl;  //返回false,判断地址
    // 正确比较字符数组中的字符串的值是否相等,可以使用strcmp函数,一样则返回0
    if(strcmp(str1,str2) == 0)
        cout<< "str1 = str2 : true" << endl << endl;
    else
        cout<< "str1 = str2 : false" <<endl << endl;

 
    char* arr5 = "abcd";  //arr5指向常量地址
    char* arr6 = "abcd";
    const char* arr7 = "abcd";  //arr5指向常量地址
    const char* arr8 = "abcd";
    cout << (arr5 == arr6) << endl;  //返回true,判断值
    cout << (arr7 == arr8) << endl;  //返回true,判断值
    

    string str1 = "abcd";
    string str2 = "abcd";
    cout << (str1 == str2) << endl;//返回true,判断值


    //用指向字符数组的数组名输出,输出为首地址
    //用指向字符串的字符指针,输出为数据
	//用string声明的字符串变量名,输出为数据
    
    return 0;
}

char *和char[]的不同点:

char * a="string1";  
char b[]="string2";  
  1. char*是变量,值可以改变,char[]是常量,值不能改变!
    a是一个char型指针变量,其值(指向)可以改变;
    b是一个char型数组的名字,也是该数组首元素的地址,是常量,其值不可以改变。

  2. char[]对应的内存区域总是可写,char*指向的区域有时可写,有时只读。

char * a="string1";
char b[]="string2";
gets(a); //试图将读入的字符串保存到a指向的区域,运行崩溃! 
gets(b) //OK

解释: a指向的是一个字符串常量,即指向的内存区域只读;b始终指向他所代表的数组在内存中的位置,始终可写!

char * a="string1";
char b[]="string2";
a=b; //a,b指向同一个区域
gets(a) //OK
printf("%s",b) //会出现gets(a)时输入的结果

解释: a的值变成了是字符数组首地址,即&b[0],即该类型为字符数组,区域可读可写。

总结:char *本身是一个字符指针变量,但是它既可以指向字符串常量,又可以指向字符串变量,指向的类型决定了对应的字符串能不能改变!

  1. char * 和char[]的初始化操作有着根本区别:
char *a = "Hello World";
char b[] = "Hello World";

printf("%s, %d\n","Hello World", "Hello World"); //Hello World,13457308
printf("%s, %d %d\n", a, a, &a); //Hello World,13457308  2030316
printf("%s, %d %d\n", b, b, &b); //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个操作
(1) 声明一个char
变量(也就是声明了一个指向char的指针变量);
(2) 在内存中的文字常量区中开辟了一个空间存储字符串常量”string1”
(3) 返回这个区域的地址,作为值,赋给这个字符指针变量a
最终的结果:指针变量a指向了这一个字符串常量“string1”(注意,如果这时候我们再执行:char * c=”string1”;则,c==a,实际上,只会执行上述步骤的1和3,因为这个常量已经在内存中创建)。

char b[] = “string2”; //实现了2个操作
(1) 声明一个char 的数组,
(2) 为该数组“赋值”,即将”string2”的每一个字符分别赋值给数组的每一个对应元素
最终的结果:“数组的值”(注意不是b的值,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); //Hello 3471628 3471332
    printf("%s %d %d\n", p2, p2, &p2); //Hello 3471628 3471336
    p2="asdf"; //通过! 说明p2不是常量! 
    printf("%s %d %d\n", p2, p2, &p2); //asdf 10704764 3471336
}
void main(){
    char a[]="Hello";
    fun1(a,a);
}

结果出乎意料!上面结果表明p2这时候根本就是一个指针变量!
结论是:作为函数的形式参数,两种写法完全等效的!都是指针变量!

  1. const char * 和char[]的区别:
const char * a=”string1”; //a是const char 类型
char b[]=”string2”; //b是char const类型

a是一个指针变量,a的值(指向)是可以改变的,但a只能指向(字符串)常量,指向的区域的内容不可改变;
b是一个指针常量,b的值(指向)不能变;但b指向的目标(数组b在内存中的区域)的内容是可变的。
作为函数的声明的参数的时候,char []是被当做char *来处理的!两种形参声明写法完全等效!

字符串类型之间的转换: string、const char*、 char* 、char[]相互转换

  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;
}
  1. 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;
}
  1. 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;
}
  1. 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值