定义

字符串是一个或多个字符序列

  • 字符串常量 (string constant)

    用双引号括起来的内容称为字符串字面量 (string literal) , 也叫做字符串常量 (string constant) 如:

    “I have an apple.” ( 在内存中存储时,编译器自动在末尾加入’\0’ )

  • 字符串和字符数组

    1
    2
    3
    4
    5
    char a[6]="apple";
    char a[6]={'a','p','p','l','e','\0'};//声明字符串,两句意思相同
    char a[]="apple"//也可以省略初始化声明中的大小,编译器会自动计算数组的大小

    char a[5]={'a','p','p','l','e'}//这是字符数组,不是字符串!!!(没有'\0')

在C和C++中的区别

  • 在C语言中,字符串存储在char类型数组中

    实际是一堆数组,以'/0'为结束标志

  • 在C++中,字符串为string类

    string是C++类库中的一个类,存在于名称空间using std::string中,使用时需要导入类库#include<string>

    初始化string s="aaa"string s("aaa")

字符串函数

C

头文件 #include <string.h>

strlen()

strcat()

strcmp()

strncmp()

strcpy()

strncpy()

strchr()

strrchr()

strstr()


  • strlen()

计算的是字符串str的长度,从字符的首地址开始遍历,以 '\0' 为结束标志,然后将计算的长度返回,计算的长度并不包含'\0'(最后一位下标等于长度-1)


  • strcat()

将两个字符串拼接在一起并返回前一个字符串

1
2
3
4
5
char str1[20]="Golden";
char str2[20]="View";
strcat(str1,str2);
printf("%s",str1);
运行结果: GoldenView

  • strncat()

把src所指字符串的前n个字符添加到dest所指字符串的结尾处,并覆盖dest所指字符串结尾的'\0',从而实现字符串的连接,返回指向dest的指针

函数声明:char * strncat(char *dest, const char *src, size_t n);

1
2
3
4
5
6
int n=3;
char dest[20] = "Hello";
char src[10] = "World";
strncat(dest, src, n);//n=3为src前n个字符
printf("%s\n", dest);
运行结果: HelloWor

  • strcmp()

比较两个字符串并根据比较结果返回整数。若str1=str2,则返回0;若str1<str2,则返回负数;若str1>str2,则返回正数

函数声明:strcmp(const char *s1,const char *s2);


  • strncmp()

把 str1 和 str2 进行比较,最多比较前 n 个字节,若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回正数;若s1 小于s2,则返回负数

int strncmp ( const char * str1, const char * str2, size_t n );

strcmp()和strncmp()都可以实现查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*strncmpexample*/
#include<stdio.h>
#include<string.h>
int main()
{
char str[][5]={"R2D2","C3PO","R2A6"};
int n;
puts("Looking for R2 as tromechdroids...");
for(n=0;n<3;n++)
{
if(strncmp(str[n],"R2xx",2)==0)
printf("found %s\n",str[n]);
}
return 0;
}


  • strcpy()

将一个字符串复制到另一块空间地址中 的函数,'\0'是停止拷贝的终止条件,同时会将 '\0' 也复制到目标空间

函数原型:char* strcpy(char* destination,const char* source);

strcpy 不够安全,可能导致越界

注意事项:

1.源字符必须以 ‘\0’结束

2.目标空间必须足够大,以确保能放源字符串

3.目标空间必须可变


  • strncpy()

把src所指由'\0'结束的字符串的前n个字节复制到dest所指的数组中,如果src的前n个字节不含'\0',则结果不会以'\0'结束,如果src的长度小于n个字节,则以'\0'填充dest直到复制完n个字节

函数声明:char *strncpy(char *s1, const char *s2, size_t n);

注意事项:
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串


  • strchr()

在字符串 s 中从前往后查找字符 c,返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c,则返回 NULL

函数原型:char *strchr(const char *s, int c);


  • strrchr()

在字符串 s 中从后往前查找字符 c,返回字符 c 第一次在字符串 s 中出现的位置,如果未找到字符 c,则返回 NULL

函数声明:char *strrchr(const char *s, int c);


  • strstr()

在字符串str1中查找str2,返回值为char * 类型( 返回指向 str1 中第一次出现的 str2 的指针);如果 str2 不是 str1 的一部分,则返回空指针

函数声明:char *strstr(const char *str1, const char *str2)

1
2
3
4
5
6
7
8
9
10
11
12
13
/*strstrexample*/
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
if (pch != NULL)
strncpy(pch, "sample", 6);
puts(str);
return 0;
}

函数实现:https://blog.csdn.net/m0_65601072/article/details/125901220

C++

string类型字符串支持C风格字符串的所有操作,此外还增加了更多功能:

s.empty() : 判断string是否为空

s.size() : 返回string字符个数,返回值是一个无符号整型(size_type),不能与int进行比较

s.length()

reverse(str.begin(), str.end()) : 串倒置

s1.append(s2) : 在s1末尾添加字符串s2

s.push_back(‘ ‘) : 在s末尾添加单个字符

s1.find(s2) : 在s1中查找s2位置

s1.rfind(s2) : 在s1中逆向查找s2位置

s1.insert(n,s2) : 在s1位置n处插入字符串s2

s1.replace(n1,n2,s2) : 将s1中位置n1到n2间的字符串替换为s2

s.substr(n,m) : 返回位置n处长度为m的子字符串

s1+s2 : 返回s1和s2连接后的结果

s1==s2,s1!=s2 : 返回s1和s2是否相等

<,<=,>,>= : 比较字符串大小


  • s.size()

s.size()函数返回值的实际类型是string::size_type,该类型是一个无符号整型数。在表达式中混用unsigned intint可能产生意想不到的结果

例如s.size()-3,由于s.size()返回无符号数,故当s.size()<3时,s.size()-3依旧是正数,而非负数

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1="abcd";
cout<<s1.size()-3<<endl;
string s2="ab";
cout<<s2.size()-3<<endl;
return 0;
}

故在将s.size()int作加减或比较,应尽量先将其转换成int


  • s.append()

1
2
3
4
5
6
7
8
9
10
11
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s ="hello ";
const char* c ="shuomc here";
s.append(c,6);
cout << s << endl;
return 0;
}
1
hello shuomc

  • s.push_back()

在s末尾插入单个字符

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s ="hello ";
s.push_back('@');
cout << s << endl;
return 0;
}
1
hello @

  • s.find()

string中find()返回值是字母在母串中的下标位置
如果没有找到,那么会返回一个特别的标记npos,一般写作string::npos

返回的是首字母的下标

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>
using namespace std;
string s, c;
int main()
{
s = "apple";
c = "l";
int index = s.find(c);
if (index != string::npos)
cout << index << endl;
return 0;
}
1
3

s.find(str,pos)

用来寻找从pos开始(包括pos处字符)匹配str的位置

返回的是首字母的下标

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <string>
using namespace std;
string s, c;
int main()
{
s = "appleapple";
c = "l";
int index = s.find(c,4);//从字符串s下标4的位置开始寻找
if (index != string::npos)
cout << index << endl;
return 0;
}
1
8

s.find_first_of(str) 和 s.find_last_of(str)

找到目标字符在字符串中第一次出现和最后一次出现的位置

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>
using namespace std;
string s, c;
int main()
{
s = "laaaal";
c = "l";
cout << "first index:" << s.find_first_of(c) << endl;
cout << "last index:" << s.find_last_of(c) << endl;
return 0;
}
1
2
first index:0
last index:5

index=s.find(c,index)

查找目标字符串在字符串出现的总次数,index每次都会更新下一次找到的位置,如果没有找到跳出循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <string>
using namespace std;
string s, c;
int main()
{
while (cin >> s >> c)
{
int index = 0;//用来存储不断更新最新找到的位置
int sum = 0;//累加出现的次数
while ((index = s.find(c,index)) != string::npos)
{
cout << "sum: " << sum+1 << " index: " << index <<endl;
index += c.length();//上一次s中与c完全匹配的字符应跳过,不再比较
sum++;
}
cout << sum << endl;
}
return 0;
}
1
2
3
4
5
6
llllll
ll
sum: 1 index: 0
sum: 2 index: 2
sum: 3 index: 4
3

  • s.rfind()

s.rfind(str) 从字符串右侧开始匹配str,并返回在字符串中的下标位置

s.rfind(str,pos) 从pos开始,向前查找符合条件的字符串


  • s.replace()

替换字符串

用法一

从起始位置pos开始长度为len的字符

replace (size_t pos, size_t len, const string& str);

1
2
3
4
5
6
7
8
9
10
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str("hello world");
str.replace(6,5,"girl."); //当前字符串从下标6开始的五个字符替换为"girl."
cout<<str<<endl;
return 0;
}
1
2
hello girl.

用法二

用重复n次的c字符替换从指定位置的内容

replace (const_iterator i1, const_iterator i2, size_t n, char c);

1
2
3
4
5
6
7
8
9
10
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str("hello world");
str.replace(6,5,3,'@'); //当前字符串从下标6开始的五个字符替换为3个@
cout<<str<<endl;
return 0;
}
1
2
hello @@@

其它用法详见

https://blog.csdn.net/qq_40239482/article/details/105193493


  • s.substr()

返回位置n处长度为m的子字符串 ( 截断 )

1
2
3
4
5
6
7
8
9
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str1 = "abcdefg";
string str2 = str1.substr(1,4);
cout << str2 << endl;
return 0;
}
1
2
bcde


  • s.insert()

将 s1 插在 s[pos] 处

s.insert( size_t pos,string s1 )

1
2
3
4
5
6
7
8
9
10
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s = "shuomc";
string s1 = "114514";
s.insert(1,s1);
cout<<s<<endl;
return 0;
}
1
s114514huomc

在s[pos]处插入n个字符

1
2
3
4
5
6
7
8
9
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s = "shuomc";
s.insert(1,3,'@');
cout<<s<<endl;
return 0;
}
1
s@@@huomc

  • reverse(str.begin(), str.end())

1
2
3
4
5
6
7
8
9
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str = "shuomc";
reverse(str.begin(), str.end())
cout << str << endl;
return 0;
}
1
2
cmouhs


读取和输入

C

  • gets()

    从stdin流中读取字符串,直至接受到换行符EOF时停止,并将读取的结果存放在buffer指针所指向的字符数组中。换行符不作为读取串的内容,读取的换行符被转换为'\0'空字符,并由此来结束字符串。

    因为本函数可以无限读取(不安全),易发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,破坏一个或多个不相关变量的值。


  • fgets()

    函数声明:char *fgets(char *restrict str, int size, FILE *restrict stream) // (“容器的地址”, “容器的大小”, “从哪里读取”)

    从第三个参数指定的流中读取最多第二个参数大小的字符到第一个参数指定的容器地址中。在这个过程中,在还没读取够第二个参数指定大小的字符前,读取到换行符'\n'或者需要读取的流中已经没有数据了。则提前结束,并把已经读取到的字符存储进第一个参数指定的容器地址中。

    使用例

    1
    2
    char a[100] = {0};
    fgets(a, 100, stdin);

    注意事项1

    fgets()函数的最大读取大小是其“第二个参数减1”,这是由于字符串是以'\0'为结束符的,fgets()为了保证输入内容的字符串格式,当输入的数据大小超过了第二个参数指定的大小的时候fgets()会仅仅读取前面的“第二个参数减1”个字符,而预留1个字符的空间来存储字符串结束符'\0'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdio.h>
    int main(void)
    {
    char a[10] = {0};
    printf("你的输入:");
    fgets(a, 4, stdin);
    printf("%s\n", a);
    return 0;
    }

    运行结果:


    注意事项2

    fgets()函数的眼里,换行符'\n'也是它要读取的一个普通字符而已。在读取键盘输入的时候会把最后输入的回车符也存进数组里面,即把'\n'也存进数组里面,而又由于字符串本身会是以'\0'结尾的。所以在输入字符个数没有超过第二个参数指定大小之前,fgets()存储进的是n+2位。最后面会多出一个'\n'和一个'\0'

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <stdio.h>
    int main(void)
    {
    char a[10] = {0};
    printf("你的输入:");
    fgets(a, 10, stdin);
    printf("%s\n", a);
    for(int i=0; i<10; i++)
    {
    if(a[i] == '\n')
    printf("a[%d]是换行符'\\n'\n", i);
    if(a[i] == '\0')
    printf("a[%d]是字符串结束符'\\0'\n", i);
    }
    return 0;
    }

    运行结果


    注意事项3

    fgets()函数只负责读取,并不会事先清空参数1指向的地址内存。读取到的字节会覆盖原地址储存,但没有覆盖到的内容还是保持原样。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <stdio.h>
    int main(void)
    {
    char a[10] = {'1','1','1','1','1','1','1','1','1','1'};
    printf("你的输入:");
    fgets(a, 10, stdin);
    printf("输出:%s\n", a);
    printf("实际存储\n");
    for(int i=0; i<11; i++)
    {
    if(a[i]!='\0' && a[i]!='\n')
    printf("a[%d]:%c\n",i,a[i]);
    if(a[i] == '\n' || a[i] == '\0')
    printf("a[%d]:'\\%c'\n", i, a[i]=='\n'?'n':'0');
    }
    return 0;
    }

    运行结果


  • getchar()

    字符输入函数,没有参数,从输入缓冲区里面读取一个字符(一个流或标准输入)

    输入的字符被存放在键盘缓冲区中,直到按回车为止( ‘\n’ 也放在缓冲区中),键入回车之后,getchar() 才开始从缓冲区每次读取一个字符,getchar ()的返回值是输入的字符的 ASCII 码,若遇到文件结尾则返回EOF (-1),如果在按回车之前输入了不止一个字符,其他字符会保留在键盘缓冲区中,等待后续 getchar() 调用读取。也就是说,后续的 getchar() 调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才开始等待。

    注意:getchar()读取每个字符包括制表符、空格、换行符,而scanf()在读取时会跳过制表符、空格、换行符。

    常使用 getchar()吸收缓冲区的字符


  • scanf()

    scanf无法输入空格、tab和回车

    最后的换行会遗留在缓冲区中,需要使用gerchar()将缓冲区的Enter吃掉


C++

  • cin

cin读取字符串,会将'\n'作为字符串的切割符,读取完成,会自己主动将'\n'转换成'\0',假设遇到文件结束,那么也将返回false


  • getline

getline(cin,字符串名字),getline()接收一个字符串,包括空格与tab键