字符数组和字符串
字符数组:
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的容量小于astrcpy(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;//输出-1cout<<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 转 intstring a="123456";int b=stoi(a);cout<<b<<endl;//int 转 stringint 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;
}