C风格String
字符
我们已经学过字符类型和ASCII码表,看下面的代码
#include <cstdio>
int main(){
char ch;//定义一个字符类型
ch = 'a';
// int(char) 把char类型转成对应的int
// 或者说把char当前int
cout << int(ch) << endl; // 按十进制输出
cout << int('a') << endl; // 按十进制输出
int b = ch;
cout << b<< endl; // 按十进制输出
cout << 'b' - 'a' << endl;// 按十进制输出
//把65当成char类型输出
cout << char(65) << endl;
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们可以看到字符和整数有一定的关系(具体看变量-字符这一节)
本质上来说字符也是一种数字。
字符数组
我们把由字符组成的数组称为字符数组. 字符数组就是C风格的字符串.
通过上面我们,加上我们学过的数组知识,字符数组有两种初始化方法:
- 定义时使用
{}
符号来初始化char s[] = {'h','e','l','l','o','\0'}; // 注意这里的 '\0' 它其实就是数字0, // '\0' 表示字符串结束了 // 也就是说遇到了'\0'后就可以认为字符串结束了
1
2
3
4 - 定义时使用双引号
""
来初始化char s[] = "hello";
1- 会给字符数组的最后自动添加
\0
字符 - 不指定长度
char a[]="xxx"
,那么初始化后,数组a的大小就是"xxx"
的长度+1(因为自动添加\0
) - 指定长度
char a[100]="xxx"
,那么a的前四个元素是xxx\0
,后面的未知
- 会给字符数组的最后自动添加
\0
是一个特殊字符,代码字符串结束,哪怕数组后面里还有内容,也不会输出
根据我们上面学习的知识,看下面的代码
#include <cstdio>
char s1[10] = {0}; //申请一个字符类型的数组
char s2[12] = {'h','e','l','l','o',' ','w','o','r','l','d','!'};
char s3[13] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0'};
char s4[] = "hello world!";
char s5[100] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0','h','e','l','l','o',' ','w','o','r','l','d','!'};
char s6[] = "hello world!\0hello world";
char s7[1000] = "hello world!\0hello world";
int main(){
cout << s1 << endl; // 输出空
cout << s2 << endl; // hello world 或者hello world+乱码
cout << s3 << endl;// hello world
cout << s4 << endl;// hello world 不指定数组长度
cout << s5 << endl;// hello world 中间有\0字符
cout << s6 << endl;// hello world 中间有\0字符
cout << s7 << endl;// hello world 指定长度
// sizeof 返回里面的数据所点字节大的小
// 可以使用sizeof(a)/sizeof(a[0]) 得到数组所占的内容的大小
cout << sizof(s4) /sizeof(s4[0]) << endl;
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
字符串的读取与输出
abc def
ghi
2
#include <cstdio>
char s1[100],s2[100],s3[100];
int main{
cin >> s1; //从s1下标0 开始写入
cin >> s2+1;//从s2下标1 开始写入
cin >> s3+1;//从s3下标1 开始写入
//s3 + 1 == &s3[1],这里是指针的知识
// &s3[1]就是s3[1]这个元素在内存里的位置
cout << "s1 = " << s1 << endl;
cout << "s2 = " << s2+1 << endl;
cout << "s3 = " << s3+1 << endl;
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
我们发现:
- 在读取字符串的过程中遇到空格,换行等不可见字符就会停止
- 把读取的字符串从给定的地址开始存入
s1
是数字名,代表数组的起始地址s2+1
就是&s2[1]
,相当于下标1的地址
字符串操作
在c风格的字符串,如果我们想对字符串进行某些操作,如:比较,复制,拼接,得到长度等.我们基本上要使用标准库提供给我们的函数来完成这此操作.
常用的函数
函数 | 作用 |
---|---|
int strlen(char a[]) | 求字符串的长度 |
int strcmp(char a[]) | 字符串的字典序比较 |
char * strcat(char a[],char b[]) | 字符串拼接 |
char * strcpy(char a[],char b[]) | 字符串拷贝 |
char * strncpy(char a[],char b[],n) | 字符串拷贝 |
更新的函数请参考:标准库头文件 <cstring>
- cppreference.com
得到字符串长度
函数:int strlen(char a[])
头文件:<cstring>
参数: 字符数组名
返回值:字符数组的长度,整型
样例代码:
#include <cstdio>
#include <cstring>
char s3[13] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0'};
char s4[] = "hello world!";
char s5[] = "hello world!\0hello world";
int main(){
cout << "strlen(s3) = " << strlen(s3) << endl; //12
cout << "strlen(s4) = " << strlen(s4) << endl; //12
cout << "strlen(s5) = " << strlen(s5) << endl; //12 想一想为什么
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
其时,strlen
的实现很简单,看我们的代码
// 注意这里其时传递的数组的起始位置,也就是指针
// 所有不需要知道数组的长度
int mystrlen(char a[]) {
for(int i = 0; 1 ;i++) {
if( a[i] == '\0')
return i;
}
}
2
3
4
5
6
7
8
原理: 直到遇到字符串结尾符'\0'为止
字符串比较
数组是不能比较的,所以c风格的字符串也是不能比较的.我们要使用strcmp函数
函数:int strcmp(char a[],char b[])
头文件:<cstring>
参数: 两个要比较大小的字符数组名
返回值:bool型
strcmp(s1,s2) 按字典比较s1,s2,如果s1<s2
输出负数,s1>s2
输出正数,相等输出0
函数:bool strcmp(char a[],char b[],n)
把a,b的前n个进行比较
样列代码
#include <cstdio>
#include <cstring>
char s3[13] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0'};
char s4[] = "hello world!";
char s5[] = "hello world!\0hello world";
char a[] = "abc";
char b[] = "bc";
int main(){
cout << "stcmp(s3,s4) = " << strcmp(s3,s4) << endl; //0
cout << "stcmp(s4,s5) = " << strcmp(s4,s5) << endl; //0
cout << "strcmp(a,b) = " << strcmp(a,b) << endl; //-1 想一想为什么
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
其时strcmp
的实现很简单,我们可以写一个自己的strcmp
,看它的代码:
int mystrcmp(char a[],char b[]) {
int la = strlen(a);
int lb = strlen(b);
//得到两个长度之间比较小的那个
int l = la;
if(l > lb) l = lb;
for(int i =0;i<l;i++) {
if(a[i] > b[i]) return 1;
if(a[i] < b[i]) return -1;
}
//到这里了,说明前面l长度内的字符都一样长
if( la == lb ) return 0;
//前面的l长度的字符都一样,这个时候只能看长度了
if(la < lb ) return -1;
//这里只能 la > lb
return 1;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
字符串拼接
我们不能直接使用s1+s2,我们要用strcat函数
函数:char * strcat(char a[],char b[])
头文件:<cstring>
参数: 两个字符数组名
返回值:a的起始地址
作用:将b复制到a字符串的后面,a要足够大,不然会错函数:char * strcat(char a[],char b[],n)
头文件:<cstring>
参数: 两个字符数组名
返回值:a的起始地址
作用:将b的前n个字符复制到a字符串的后面,a要足够大,不然会错
样列代码
#include <cstdio>
#include <cstring>
char s3[13] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0'};
char s4[100] = "hello world!";
char s6[100] = "hello world!\0hello world";
char a[] = "abc";
char b[] = "bc";
char c[] = "abcd";
int main(){
// printf("stcmp(s3,a):%d\n",strcat(s3,s4)); //wrong
printf("strcat(s4,a):%s\n",strcat(s4,a));
strcat(s6,a);
printf("strcat(s6,a):%s\n",s6); //猜一猜输出什么
strncat(s6,a,2);
printf("strcat(s6,a):%s\n",s6); //猜一猜输出什么
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
赋值与拷贝
s1 = s2,s1[]= s2
这样写都是错误的
函数:char * strcpy(char a[],char b[])
头文件:<cstring>
参数: 两个字符数组名
返回值:a的起始地址
作用:将b的所有字符复制到a起始后面,a要足够大,不然会错函数:char * strcpy(char a[],char b[],n)
头文件:<cstring>
参数: 两个字符数组名
返回值:a的起始地址
作用:将b的前n个字符复制到a起始后面,a要足够大,不然会错,不会在末尾加'\0'
样列代码
#include <cstdio>
#include <cstring>
char s3[13] = {'h','e','l','l','o',' ','w','o','r','l','d','!','\0'};
char s4[100] = "hello world!";
char s6[100] = "hello world!\0hello world";
char a[] = "abc";
char b[] = "bc";
char c[] = "abcd";
int main(){
printf("strcpy(s4,a):%s\n",strcpy(s4,a));
strcpy(s6,a);
printf("strcpy(s6,a):%s\n",s6); //猜一猜输出什么
strncpy(s6,a,2);
printf("strcpy(s6,a):%s\n",s6); //猜一猜输出什么
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21