Skip to content

C风格String

字符

我们已经学过字符类型和ASCII码表,看下面的代码

c
#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;
}
1
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是一个特殊字符,代码字符串结束,哪怕数组后面里还有内容,也不会输出

1

根据我们上面学习的知识,看下面的代码

c
#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;
}
1
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
1
2
c
#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;
}
1
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>
参数: 字符数组名
返回值:字符数组的长度,整型

样例代码:

c
#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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

其时,strlen的实现很简单,看我们的代码

cpp
// 注意这里其时传递的数组的起始位置,也就是指针
// 所有不需要知道数组的长度
int mystrlen(char a[]) {
  for(int i = 0; 1 ;i++) {
    if( a[i] == '\0')
        return i;
  }
}
1
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个进行比较

样列代码

c
#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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

其时strcmp的实现很简单,我们可以写一个自己的strcmp,看它的代码:

cpp
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;

}
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要足够大,不然会错

样列代码

c
#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;
}
1
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'

样列代码

c
#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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21