字符数组:
char 类型的数组,用来存储多个字符(代表字符串),由于char占的内存比较小(1个字节),所以存储多维数组的时候建议使用,比较省内存。
- char类型是存储不了中文的
- 中文占2个字节
字符数组声明:
字符数组声明就是简单的数组声明
char c[100];//一维数组
char c1[10][10];//二维数组
char c2[10][10][10];//三维数组
字符数组初始化:
C/C++标准库中的字符串处理函数(如
strcpy
、strlen
、printf
等)均依赖\0
来判断字符串的结束。若字符串未以\0
结尾,这些函数会继续读取内存,直到遇到随机内存中的\0
,可能导致程序崩溃或数据错误。
需要注意的字符数组存储数据的时候需要添加 '\0' 代表字符串的结束
- 由于需要存储'\0' 所以数组能存储的数据个数需要-1,留一个位置
- 未以
\0
结尾的字符数组可能被误认为字符串,导致函数越界访问内存。- 初始化时如果你没给'\0'系统会自动添加
初始化的三种方式:
- 使用字符串进行初始化: "内容"
- 使用大括号+单个字符的方式初始化: {'字符1','字符2','字符3','字符4'.....}
- 使用大括号+字符串的方式初始化:{“字符串”}
#include<iostream>
using namespace std;
int main()
{
//字符串的结束标志为'\0',所以数组要多开一个空间存放'\0'
//存放满数据,三种初始化方式相同
char a[10]="123456789";//只能存放9个数,第十个存放'\0'
char b[10]={'1','2','3','4','5','6','7','8','9'};
char c[10]={"123456789"};
char d[]="12345";//自动添加\0
//或者末尾手动直接添加\0
char d[10]={'1','2','3','4','5','6','7','8','9','\0'};
return 0;
}
数据不够时使用'\0'填充:
#include<iostream>
using namespace std;
int main()
{
//未存放满数据,会用'\0'补齐
char e[10]="12345";
for(int i=0;i<10;i++)
{
if(e[i]=='\0') cout<<"\\0"<<endl;
else cout<<e[i]<<endl;
}
return 0;
}
memset()初始化:
头文件:#include<cstring>函数:
memset(数组,值,数组大小);
- 第一个参数:数组名
- 第二个参数:任何字符
- 第三个参数:获取数组的内存大小 sizeof(数组名)
- 初始化是按照字节进行初始化,所以要获取数组内存
- 如果你只初始化了数组的一部分,其他未初始化的部分为可能为SOH,所以使用的时候尽量进行数据全覆盖(但最好留一个位置存储\0)
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char c[10];
memset(c,'A',sizeof(c)-1);//留一个\0的位置
for(int i=0;i<10;i++)
{
if(c[i]=='\0') cout<<"\\0"<<endl;
else cout<<c[i]<<endl;
}
cout<<c[9]<<endl;
return 0;
}
fill()初始化:
头文件:#include<algorithm>函数:
fill(起点,终点,值);
- char arr[10];
- 起点为:arr 终点:arr+9 9为数组长度留一个\0
- 第一个参数:数组的起始位置 可以使用+num 进行后移
- 第二个参数:数组的终点位置 也可以移动结束位置
- 第三个参数:可以为任和的值
- 如果你只初始化了数组的一部分,其他未初始化的部分为可能为SOH,所以使用的时候尽量进行数据全覆盖(但最好留一个位置存储\0)
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
char c[10];
fill(c,c+9,'A');//留一个\0的位置
for(int i=0;i<10;i++)
{
if(c[i]=='\0') cout<<"\\0"<<endl;
else cout<<c[i]<<endl;
}
cout<<c[9]<<endl;
return 0;
}
字符数组赋值:
- 使用数组[下标]=进行单个字符赋值
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
char c[10]="123";
c[0]='A';//赋值
c[8]='D';//赋值
for(int i=0;i<10;i++)
{
if(c[i]=='\0') cout<<"\\0"<<endl;
else cout<<c[i]<<endl;
}
return 0;
}
使用for循环进行赋值
#include<iostream>
using namespace std;
int main()
{
char c[10]="123";
int i=0;
for(char c1='0';c1<'9';c1++,i++){//循环进行赋值
c[i]=c1;
}
for(int i=0;i<10;i++)
{
if(c[i]=='\0') cout<<"\\0"<<endl;
else cout<<c[i]<<endl;
}
return 0;
}
不能使用=进行数组和数组间的赋值,因为数组名是一个地址
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char c[10];
char d[10]="456";
c=d;//报错,不能用=进行赋值
c="123456";//报错,也不能用字符串去进行赋值
return 0;
}
获取长度
字符数组长度:
由于char类型只占一个字节,直接使用sizeof(数组名)就是数组长度。
#include<iostream>
using namespace std;
int main()
{
char c[10]="123";
cout<<"字符数组长度:"<<sizeof(c);
return 0;
}
字符串长度:
由于\0代表结束,使用循环直接读到\0停止即可获取字符串长度
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
char c[10]="123";
int num=0;
for(;c[num]!='\0';num++){}//读取字符长度
cout<<num;
return 0;
}
使用系统函数获取字符串长度
- 头文件#include<ctsring>
- strlen(字符数组名)
- 可以获取到第一个'\0'前的元素个数
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char c[10]="123";
cout<<strlen(c)<<endl;//获取字符串长度
return 0;
}
字符数组的输入和输出:
字符数组输入:
使用方法 | 说明 |
---|---|
cin>>字符数组名 | 不能读取空格(空格和回车代表结束) |
cin.getline(字符数组名,字符个数) 读取一行数据 | 可以读取空格 |
cin.get() | 读取一个字符 |
scanf("%s",字符数组名) | C语言方法头文件#include<cstdio>不能读取空格 |
fgets(字符数组名,字符个数,stdin) | C语言方法头文件#include<cstdio>可以读取空格 |
字符数组的输出:
使用方法 | 说明 |
---|---|
cout<<字符数组名 | 直接输出字符串 |
printf("%s",字符数组名) | C语言方法头文件#include<cstdio>直接输出字符串 |
puts(字符数组名) | C语言方法头文件#include<cstdio>直接输出字符串 |
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
char a[10];
//C语言方式的读取和输出(不能读取空格)
scanf("%s",a);//输入
printf("%s\n",a); //输出
//C语言方式读取一行(可以读取空格)
char b[10];
fgets(b,9,stdin);//输入
puts(b);//输出
//C++输入和输出(不能读取空格)
cin>>b;
cout<<b<<endl;
//C++读取一行(可以读取空格)
cin.getline(b,9);//读取一行
cout<<b<<endl;
return 0;
}
字符数组常用函数:
头文件:#include<cstring>
函数名 | 函数的功能 |
---|---|
strlen(S1) | 获取字符串长度,获取第一个''\0'之前的数据长度 |
strcpy(S1,S2) | 把S2复制到S1中 |
strcat(S1,S2) | 把S2连接到S1 |
strcmp(S1,S2) | 比较两者的大小 相同返回0 |
strchr(S1,ch) | 返回一个指针,指向S1中字符出现的位置 |
strstr(S1,S2) | 返回一个指针,指向字符串S1中S2第一次出现的位置 |
memcpy(A,B,size) | 把数组B中的Size个字符复制给A |
strcpy(s1,s2)复制:
- 将s2复制给s1,需要确保s1的容量大于等于s2的容量
- 不能正确处理重叠的字符串。如果源字符串和目标字符串重叠,strcpy()的行为是未定义的。
- 它不检查目标缓冲区的大小,如果源字符串比目标缓冲区长,可能会覆盖缓冲区并导致缓冲区溢出。这可能导致安全漏洞和其他问题。
- 它不能正确处理源字符串中的空字符。如果源字符串包含空字符,strcpy()会在该点停止复制,即使源字符串中还有其他字符。
当S1容量小于S2时,编译器会对S1进行扩容(Dev-C++-5.11)(但不建议这样使用)
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//strlen 获取'\0'之前的数据长度
char a[10]="123456";
char b[5]={};//b的容量小于a
strcpy(b,a);//但还是复制成功了
for(auto p:b)//遍历数组
{
cout<<p<<endl;
}
cout<<"b字符串的长度"<<strlen(b)<<endl;
cout<<b[6]<<endl;
return 0;
}
实现一个strcpy()
//size为s1数组长度
void Strcpy(char s1[],char s2[],int size){
if(size-1<strlen(s2)) cout<<"s1容量不够"<<endl;
else{
for(int i=0;i<strlen(s2);i++) s1[i]=s2[i];//复制
for(int i=strlen(s2);i<size;i++) s1[i]='\0';//其他数据置为'\0'
}
}
memcpy(A,B,size)复制个数
memcpy(A,B,size):把数组B中的Size个字符复制给A
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a[10]="123456";
char b[20]="789459";
memcpy(b,a,5);//把a中的5个数据复制b中
for(auto i:b)
{
cout<<i<<endl;
}
return 0;
}
实现memcpy()
//length s1的数组长度 size为复制的个数
void Memcpy(char s1[],char s2[],int length,int size){
if(length-1<size) cout<<"s1容量不足"<<endl;
else if(strlen(s2)<size) cout<<"元素个数大于s2的长度"<<endl;
else{
for(int i=0;i<size);i++) s1[i]=s2[i];//复制
for(int i=size;i<length;i++) s1[i]='\0';//其他数据置为'\0'
}
}
strcat(s1,s2)拼接:
strcat(s1,s2):把S2连接到S1
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//strlen 获取'\0'之前的数据长度
char a[10]="123456";
char b[20]="789456";
cout<<strcat(b,a)<<endl;
return 0;
}
实现Strcat()
//size为s1的数组长度
void Strcat(char s1[],char s2[],int size){
int length=strlen(s2)+strlen(s1);//获取复制后的总长度
if(size-1<length) cout<<"s1容量不够"<<endl;
else{
for(int i=strlen(s1);i<length;i++) s1[i]=s2[i];//复制
for(int i=length;i<size;i++) s1[i]='\0';//其他数据置为'\0'
}
}
strcmp(s1,s2)比较:
从第一个元素开始根据ASCLL值比较两者的大小
- s1==s2 返回0
- s1>s2返回1
- s1<s2返回2
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
//strlen 获取'\0'之前的数据长度
char a[10]="123456";
char b[20]="789456";
cout<<strcmp(a,b)<<endl;//输出-1
cout<<strcmp(b,a)<<endl;//输出1
return 0;
}
实现strcmp()
int Strcmp(char s1[],char s2[])
{
//获取小的数据长度
int length=min(strlen(s1),strlen(s2));
//开始比较
for(int i=0;i<length;i++){
if(s1[i]>s2[i]) return 1;
else if(s1[i]<s2[i]) return -1;
}
//当数据都相等时,需要判断长度
if(strlen(s1)==strlen(s2)) return 0;
else if(strlen(s1)>strlen(s2)) return 1;
else return -1;
}
strcahr(s1,ch)查找字符
strcahr(s1,ch):查找字符,返回一个指针(char*),指向S1中字符第一次出现的位置
- 找到返回第一次出现的位置
- 没找到返回 nullptr
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a[10]="ab1cdef";
char * p;
p=strchr(a,'1');//返回的是第一次出现的位置
cout<<*p<<endl;//输出的是当前位置的值
cout<<p<<endl;//输出的是字符串
//获取字符在字符串中的位置,可以通过计算指针与原始字符串指针的差值来得到。
//输出所处的位置
cout<<p-a+1<<endl;
//输出之后的数据
cout<<p+1<<endl;
return 0;
}
实现strchr()
char *Strchr(char c[],char c1){
char * p=c;//指向第一个元素
while(*p!='\0'){
if(*p==c1) return p;
p++;
}
return nullptr;
}
strstr(s1,s2)查找字符串:
strstr(S1,S2)返回一个指针,指向字符串S1中S2第一次出现的位置,没找到返回nullptr
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a[10]="ab1cdef";
char b[20]="cdef";
char * p;
p=strstr(a,b);//返回的是第一次出现的位置
//获取字符在字符串中的位置,可以通过计算指针与原始字符串指针的差值来得到。
//输出所处的位置
cout<<p-a+1<<endl;
return 0;
}
实现strstr()
char* Strstr(char c[],char c1[]){
char *p=c;
if(strlen(c1)>strlen(c)) return nullptr;
for(int i=0;i<=strlen(c)-strlen(c1);i++){
bool b=true;//表示是否匹配成功
for(int j=i,k=0;j<i+strlen(c1)&&k<strlen(c1);j++,k++){
if(c[j]!=c1[k]) {
b=false;
break;
}
}
if(b) return p+i;
}
return nullptr;
}
string字符串:
C++ 标准库提供了 string 类类型,string是一个类,固定占用28个字节,string没有'\0'
- 头文件:#include<string>
- 关键词:string
- 内部也是由char数组实现的
- 但可以自动扩容
string声明:
把string 当作正常的数据类型使用即可
- 格式 string 变量名
string str;//正常创建即可
string初始化:
直接使用 " "对字符串进行初始化
string str="ssssssssss";//初始化
string赋值:
字符串和字符串之间可以用 = 进行赋值
string s1="abcdefghijklmnopq";
string s2=s1;//可以使用=进行赋值
string数据访问:
使用数组的方式进行访问: 字符串名[下标] 进行字符的修改和访问
string s1="ABCDEFGHIJKL";
cout<<s1[0];//输出第一个字符
s1[0]='K';//修改你一个字符
string字符串拼接:
使用 + 进行拼接
- 可以拼接字符
- 也可以拼接字符串
string s1="ABCDE";
s1+='C'; //拼接字符
string s2="KKKKKKKK";
s1+=s2;//拼接字符串
s1+="PPPPPPP";
cout<<s1<<endl;
string中的函数:
函数名 | 描述 | |
---|---|---|
size() length() | 返回字符串长度 | cout<<str.size()/length(); |
empty() | 判断是否为空 | cout<<str.empty(); |
operator[] | 使用[ ]访问字符串中指定位置的字符。 | cout<<str[1]; |
find() | 查找子字符串在字符串中的位置。 string::nops 代表查找失败 | cout<<str.find("abc"); |
rfind() | 从后往前查找子字符串在字符串中的位置 | cout<<str.rfind("abc"); |
at() | 访问字符串中指定位置的字符(带边界检查) | std::cout << str.at(0); |
substr() | 返回从指定位置开始的子字符串。 | string sub = str.substr(0, 5); |
append() | 在字符串末尾添加内容。 | str.append(" more"); |
insert() | 在指定位置插入内容。 | str.insert(pos, "inserted"); |
erase() | 删除指定位置的字符或子字符串。 | str.erase(pos, length); |
clear() | 清空字符串。 | str.clear(); |
compare() | 比较两个字符串。(按照ASCLL比较,从头开始比较,直到那个数比较大即可退出) | int result = str.compare("other"); |
c_str() | 返回 C 风格的字符串(以 null 结尾) | const char* cstr = str.c_str(); |
string数据类型转换:
string和int:
说明 | 使用方法 |
---|---|
string 转 int | std::stoi()函数 |
int 转 string | to_string() 函数 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
//string 转 int
string a="123456";
int b=stoi(a);
cout<<b<<endl;
//int 转 string
int num = 123;
string str = to_string(num);
cout << str;
return 0;
}
函数的实现:
//string 转 int
int string_int(string s){ //字符串转数字 小于2e9
int num=0;
//拆解累加
for(int i=0;i<s.size();i++) num=num*10+(s[i]-'0');
return num;
}
//int 转 string
string int_string(int n){
//拆解逆转
string str;
while(n!=0){
str+='0'+n%10;
n/=10;
}
string s1;
for(int i=str.size()-1;i>=0;i--)s1+=str[i];//逆转拼接
return s1 ;
}
char数组和int:
说明 | 使用方法 |
---|---|
char数组 转 int | 使用#include <cstdlib>下的 std::atoi()函数 |
int 转 char数组 | 使用 #include<cstdlib>下的 std::char itoa(int value, char* string, int radix); radix为进制数 |
#include <iostream>
#include <cstdlib>
using namespace std;
int main() {
//char数组 转 int 类型
char str[] = "456";
int num = std::atoi(str);
std::cout << "num = " << num;
////int类型 转 char数组
int a=123456789;
char c[20];
itoa(a,c,10);
cout<<c<<endl;
return 0;
}
函数的实现:
//char 转 int
int char_int(char c[]){//结果在int范围内
int num=0;
//拆解累加
for(int i=0;i<strlen(c);i++) num=num*10+(c[i]-'0');
return num;
}
//int 转 char*
//radix的范围为2-10 超过十的就不判断了
void int_char(int num,char c[],int radix,int length){
//首先先用strig先存储数据,看一下结果的长度
string s;
while(num!=0){
s+='0'+num%radix;
num/=radix;
}
if(s.size()<=length-1){ //数据可以放得下,把数据放入
int j=0;//c数组下标
for(int i=s.size())-1;i>=0;i--,j++) c[j]=s[i];
for(int i=j;j<length;j++) c[i]='\0';//把剩余位置都设置为\0
}
else{
cout<<"数组容量不够"<<endl;
}
}
string输入和输出
字符串输入:
使用方法 | 说明 |
---|---|
cin>>字符串名 | 不能读取空格(空格和回车代表结束) |
getline(cin,字符串名) 读取一行数据 | 可以读取空格 |
getline (istream& is, string& str, char delim); 读到delim截止
getline (istream& is, string& str);
字符串输出:
使用方法 | 说明 |
---|---|
cout<<字符串名 | 直接输出字符串 |
使用循环进行输出 | 访问每一个数据 |
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
cin>>s;//读取不带空格的数据
cout<<s<<endl;
//读取带空格的数据
getline(cin,s);//读取一行数据
string s1;
getline(cin,s1,'p');//读取一行读到p停止
cout<<s<<endl<<s1<<endl;
return 0;
}
C++处理带空格的字符串:
当我们要处理带空格的字符串的时候是有很多种方法解决的
- 字符数组的读取方法
- 字符串的读取方法
字符数组的读取方法:
使用方法 | 说明 |
---|---|
cin.getline(字符数组名,字符个数) 读取一行数据 | 可以读取空格 |
cin.get() | 读取一个字符(可读取空格) |
fgets(字符数组名,字符个数,stdin) | C语言方法头文件#include<cstdio>可以读取空格 |
需要注意的是 使用过cin后 \n 没有被cin读取,所以还会残留在输入流中,需要将 \n 读取掉再读取一行
单独读取一行:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
char a[50];
fgets(a,sizeof(a),stdin);//需要指定数据长度,更安全
cout<<a<<endl;
return 0;
}
连续输入读取:
//连续输入和读取多行
#include<iostream>
#include<cstdio>
#include<cstdlib> //char数组转int 的头文件
using namespace std;
int main()
{
char n[50];//创建一个字符串
fgets(n,sizeof(n),stdin);//读取需要输入的字符串个数
int N=atoi(n);//转换为数字 为数据的行数
while(N--)
{
gets(n);//输入字符串
cout<<n<<endl; //输出字符串
}
return 0;
}
处理cin输入问题:
//连续输入和读取多行
#include<iostream>
#include<cstdio>
#include<cstdlib> //char数组转int 的头文件
using namespace std;
int main()
{
char n[50];//创建一个字符串
int N=0;
cin>>N//读取行数
cin.get();//读取掉 \n
//后面就能正常读取一行数据了
while(N--)
{
gets(n);//输入字符串
cout<<n<<endl; //输出字符串
}
return 0;
}
字符串的读取方式:
使用getline函数读取一行带空格的数据
getline (istream& is, string& str, char delim); 读到delim截止
getline (istream& is, string& str);
单独读取一行:
//读取一行数据
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
getline(cin,s);//读取一行数据
cout<<s<<endl;
return 0;
}
连续输入读取:
//输入和输出多行数据时
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s;
getline(cin,s);//输入读取的个数
int N=stoi(s);//转换为整数
while(N--)
{
getline(cin,s);
cout<<s<<"--------------"<<endl;
}
return 0;
}
处理cin输入问题:
//当使用cin输入数据时,一定cin读取的那行的回车符号先去除掉
#include<iostream>
#include<string>
using namespace std;
int main()
{
int N=0;
string s;
cin>>N;
//把这行全部读取完 ,不然cin这行的\n 会被留在输入流中的 getline()读取
getline(cin,s);
//或者使用cin.get() 读取掉这个回车符
while(N--)
{
getline(cin,s);
cout<<s<<"--------------"<<endl;
}
return 0;
}