由单引号括起来的一个字符被称作 char 型字面值,双引号括起来的零个或多个字符则构成字符串型字面值。字符串字面值的类型实际上就是由常量字符构成的数组,,编译器在每一个字符串后面添加一个空字符('\0'),因此字符串的实际长度要比他的内容多1。
如字面值 'A' 表示的就是单独字符 A ,而字符串 "A" 代表了一个包含两个字符的字符数组,分别是字母 A 和空字符。
一.常见功能
二.字符串的定义
使用标准库类型 string 声明并初始化一个字符串,需要包含头文件 string。可以初始化的方式如下:
string s1; // 初始化一个空字符串
string s2 = s1; // 初始化s2,并用s1初始化
string s3(s2); // 作用同上
string s4 = "hello world"; // 用 "hello world" 初始化 s4,除了最后的空字符外其他都拷贝到s4中
string s5("hello world"); // 作用同上
string s6(6,'a'); // 初始化s6为:aaaaaa
string s7(s6, 3); // s7 是从 s6 的下标 3 开始的字符拷贝
string s8(s6, pos, len); // s7 是从 s6 的下标 pos 开始的 len 个字符的拷贝
使用 = 的是拷贝初始化,使用 () 的是直接初始化。当初始值只有一个时,两者都可。当初始值有多个时一般来说要使用直接初始化,如上述最后一个的形式。
三.字符串输入输出问题
1、cin 使用空白字符作为一次输入的结尾,并忽略该空字符。
int main(void)
{
char line[10];
cout << "input what you want:";
cin >> line; // 可以尝试输入 "123 456"
cout << "what you input is:" << line << endl; // 只能输出 "123"
return 0;
}
/* 测试用例
input what you want:123 456
what you input is:123
*/
也就是说,这种情况下一次只能完成一个单词的输入,其后的单词都会被忽略掉。
2、使用 getline() / get() 函数完成面向行的输入
getline() / get() 函数都可以接收一行字符串输入,并以回车作为输入的结尾。区别就是 getline 会在输入结束后丢弃最后的换行符,而 get 则会在输入队列中保留最后的换行符。
1)cin.getline()
可以通过 cin.getline(line, nums, (optional)delim) 实现调用:从输入队列中获取 nums-1 个字符到 line 中,因为字符串的最后一个字符是 '\0'。如果输入的长度超出 nums-1 个,则 getline 和 get 将把余下的字符留在输入队列中,另外 getline 还会设置失效位,并关闭后面的输入(即后面的所有输入将不可用),此时可以用 cin.clear() 清除标准位就可以恢复后面的输入。
这种句点表示法表明,函数 getline() 是 istream 类的一个方法。另外需要注意的是 cin 是一个 istream 对象。cin.getline() 的第一个参数是目标数组,第二个参数是数组长度,这样来避免超越数组的边界。后面介绍通过输入对 string 赋值的时候调用方式会有区别。
cin.getline(line, nums)
int main(void)
{
char line1[10];
char line2[10];
char line3[10];
cout << "input what you want:" << endl;
cin.getline(line1, 10); // 可以尝试输入 "123 456 789" ('\n') 含有11个字符
// cin.clear();
cin.getline(line2, 10); // 不可用,直接退出
cin.getline(line3, 10); // 不可用,直接退出
cout << "what you input is:" << endl;
cout << "line1:" << line1 << endl; // 输出 "123 456 7"
cout << "line2:" << line2 << endl; // 输出 空
cout << "line3:" << line3 << endl; // 输出 空
return 0;
}
/*
input what you want:
123 456 789
what you input is:
line1:123 456 7
line2:
line3:
*/
// 使用 clear
int main(void)
{
char line1[10];
char line2[10];
char line3[10];
cout << "input what you want:" << endl;
cin.getline(line1, 10); // 可以尝试输入 "123 456 789" ('\n') 含有11个字符
cin.clear(); // 清除标志位
cin.getline(line2, 10); // 可用,输出 "89",这是上一步输入队列中的字符
cin.getline(line3, 10); // 可用,你输入啥输出啥
cout << "what you input is:" << endl;
cout << "line1:" << line1 << endl; // 输出 "123 456 7"
cout << "line2:" << line2 << endl; // 输出 空
cout << "line3:" << line3 << endl; // 输出 空
return 0;
}
/*
input what you want:
123 456 789
123
what you input is:
line1:123 456 7
line2:89
line3:123
*/
cin.getline 还有第三个参数 delim(全称应该是 delimiter,中文意思:定界符/分隔符),作用是指定用作分界符的字符(没有这个参数的版本将以换行符为分界符)。
遇到分界符后,当前字符串的输入将停止,即使还未读取最大数目的字符。因此在默认情况下,这种分界符的方式或者到达输入的指定数目都将停止读取输入。和默认情况一样 get() 将分界符留在输入队列中,而 getline() 不保留。
cin.getline(line, nums, delim),也就是以 delim 指定的字符作为一次字符串输入的结束,其后的在 nums-1 范围内的输入会保留在输入队列中作为下一个字符串的开始。
int main(void)
{
char line1[10];
char line2[10];
cout << "input what you want:" << endl;
cin.getline(line1, 10, 's'); // 可以尝试输入 "123s456" ('\n')
cin.getline(line2, 10); //
cout << "what you input is:" << endl;
cout << "line1:" << line1 << endl; // 输出 "123"
cout << "line2:" << line2 << endl; // 输出 "456"
return 0;
}
/* 测试用例
input what you want:
123s456
what you input is:
line1:123
line2:456
*/
getline 函数每次读取一行,它通过换行符来确定行尾,但不保存换行符。相反,在存储字符串时他用空字符 '\0' 来替换换行符。
2)cin.get()
调用方式类似 getline,即cin.get(line, nums, (optional)delim)
前面说过,get 函数会在输入队列中保留最后的换行符。注意是输入队列,也就是在一个 get()
函数完成输入后,会在输入缓存中保留组后的换行符,如果不做处理在下次运行 get() 时会出问题。
int main(void)
{
char line1[10];
char line2[10];
cout << "input what you want:" << endl;
cin.get(line1, 10); // 可以尝试输入 "123" ('\n'), 此时回车符将会留在输入队列中
cin.get(line2, 10); // 可以尝试输入 "456",可以发现 line1 输入完后,这步直接被“跳过了”
cout << "line1:" << line1 << endl; // 输出 "123"
cout << "line2:" << line2 << endl; // 输出空字符,由于 cin.get(line2, 10); 读入的是上一个字符输入结束时留输入队列中的回车符
return 0;
}
/* 测试用例
input what you want:
123
what you input is:
line1:123
line2:
*/
由于第一次调用后换行符留在了输入队列中,因此第二次看到第一个字符便是换行符,因此就直接结束了。如果不借助与任何帮助,get() 将不能跨过该换行符(在多个get的情况下)。可以使用下面这种方式避免这种情况:
cin.get(line2, 10).get();
\\ 或者
cin.get(line2, 10);
get();
3、数字与字符串的混合输入问题
使用 cin 输入一个整数后,最后的回车符会留在输入队列中,类似于get,这会对后续的 getline 和 get 输入产生影响,因为 getline / get 看到换行符后会认为是一个空行,然后会把空字符赋给后面的字符串,如下:
int main(void)
{
int a, b; // 输入 123 ('\n') 456 ('\n')
char s[5];
cin >> a;
cin >> b;
cin.getline(s, 5); // 得到换行符,直接赋空值
cout << a << " " << b << " " << s << endl;
}
/* 测试用例
123
456
123 456
*/
此时可以使用在后面添加 cin.get() 或者 (cin >> b).get() 的方式来解决这个问题:
int main(void)
{
int a, b; // 输入 123 ('\n') 456 ('\n')
char s[7];
cin >> a;
// cin >> b;
// cin.get();
(cin >> b).get();
cin.getline(s, 7); // 输入 "string" ('\n')
cout << a << " " << b << " " << s << endl;
}
/* 测试用例
123
456
string
123 456 string
*/
4.对 string 对象的输入方法
使用 cin<<str 的语法来将输入存储到 string 对象中与字符数组的操作是一样的。不同的是当每次读取一行而不是一个单词时使用的语法是不同的。
int main(void)
{
string str;
cout << "input what you want:" << endl;
getline(cin, str);
cout << "what you input is:" << endl;
cout << str << endl;
}
/* 测试用例
input what you want:
123 456 789
what you input is:
123 456 789
*/
注意这里的面向行的输入是 getline(cin, str)
这里没有使用句点表示法,这表明这个 getline 不是类方法。他将 cin 作为参数,指出到哪里去查找输入。另外也没有指出字符串长度的参数,因为 string 对象将根据字符串的长度自动调整自己的大小。
至于为什么字符数组和string对象的 getline 方法不一样呢,其实这是个历史问题。早期的 C++ 还没引入 string 类的时候就有 istream 类了,因此当时也就没有针对 string 对象的输入方式了,所以最后才会演变出这两种方式。
四.拼接、比较、修改、反转操作
s1+s2 // 返回 s1 和 s2 拼接后的结果。加号两边至少有一个 string 对象,不能都是字面值
s1 == s2 // 如果 s1 和 s2 中的元素完全相等则它们相等,区分大小写
s1 != s2
<, <=, >, >= // 利用字符的字典序进行比较,区分大小写
在 pos 之前插入 args 指定的字符。pos是一个下标或者迭代器。接受下标的版本返回一个指向 s 的引用;接受迭代器的版本返回一个指向第一个插入字符的迭代器 。
s.insert(pos, args)
// 在 s 的位置 0 之前插入 s2 的拷贝
s.insert(0, s2)
删除从 pos 开始的 len 个字符。如果 len 省略,则删除 pos 开始的后面所有字符。返回一个指向 s 的引用。
s.erase(pos, len)
将 s 中的字符替换为 args 指定的字符。返回一个指向 s 的引用。
s.assign(args)
将 args 追加到 s 。返回一个指向 s 的引用。args 不能是单引号字符,若是单个字符则必须用双引号表示。如,可以是 s.append("A") 但不能是 s.append('A')
s.append(args)
将 s 中范围为 range 内的字符替换为 args 指定的字符。range 或者是一个下标或长度,或者是一对指向 s 的迭代器。返回一个指向 s 的引用。
s.replace(range, args)
// 从位置 3 开始,删除 6 个字符,并插入 "aaa".删除插入的字符数量不必相等
s.replace(3, 6, "aaa")
使用 <algorithm> 头文件中的 reverse() 方法:
string s2 = "12345"; // 初始化一个字符串
reverse(s2.begin(), s2.end()); // 反转 string 定义的字符串 s2
cout << s2 << endl; // 输出 54321
五.find函数
1.正向查找
1.1 s.find(str)
string中find()返回值是字母在母串中的下标位置。
如果没有找到,那么会返回一个特别的标记npos,一般写作string::npos
。
string s, c;
int main() {
s = "apple";
c = "l";
int index = s.find(c);
if (index != string::npos)
cout << index << endl;
}
输出:
3
1.2 s.find(str,pos)
find(str,pos)是用来寻找从pos开始(包括pos处字符)匹配str的位置。
string s, c;
int main() {
s = "laaaal";
c = "l";
int index = s.find(c,3);//从字符串s下标3的位置开始寻找
if (index != string::npos)
cout << index << endl;
}
上述等价于从字符串"aal"开始找"l",省略第一个"l"。
输出结果:
5
1.4查找目标字符串在字符串出现的总次数
核心代码:index=s.find(c,index)
,index每次都会更新下一次找到的位置,如果没有找到跳出循环。
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;
}
}
llllll
ll
sum: 1 index: 0
sum: 2 index: 2
sum: 3 index: 4
3
2.逆向查找rfind()
s.rfind(str): 是从字符串右侧开始匹配str,并返回在字符串中的下标位置
string s = "apple";
cout << s.rfind("l") << endl;
这时结果是否还是跟find()查找一样,输出结果是3呢?让我们往下看。
结果显示:
3
- rfind(str,pos): 从pos开始,向前查找符合条件的字符串。
六.常用函数
1.strlen函数
原型:size_t strlen(char* str)
头文件 #include<string.h>
作用:测量字符串str的长度,返回str的长度(数值)
#include<stdio.h>
#include<string.h>
int main()
{
char str[] = "Welcom!";
int a=strlen(str);
printf("%d",a);
}
//输出结果为7
2.strcpy函数
原型: char *strcpy(char* strA,const char *strB)
头文件 #include<string.h>
作用:把字符串strB复制到字符串strA中,返回字符串strA
前提条件:字符串strA要足够大,足以容纳字符串strB(例如strA[100],strB[50],strA的字符容纳量大于strB),否则就会溢出错误。
#include<stdio.h>
#include<string.h>
int main()
{
char strA[20];
char strB[15] = "I LOVE YOU";
strcpy(strA, strB);
puts(strA);
}
3.strncpy函数
原型 :char* strncpy(char *strA,char *strB,int *n)
头文件:#include<string.h>
作用:把字符串strB前n个字符复制(拷贝)到字符串strA,返回strA
注意事项:strA的容纳量要比n大,字符串strB的容纳量也要大于n,否则会出现溢出错误。
#include<stdio.h>
#include<string.h>
int main()
{
char strA[20];//char strA[20]={0};
char strB[] = "computer";
strncpy(strA, strB,4);
strA[4] = '\0';//此时strA是没有终止符的,所以要在strA[4]加上'\0'终止,否则会出现乱码
//或者可以对strA进行初始化
puts(strA);
return 0;
}
输出:
comp
4.strcat函数
原型:char* strcat(char* strA,char* strB)
头文件:#include<string.h>
作用:把字符串strB拼接到字符串strA末尾(例如:char strA[20]="CHINA",strB[]="Chinese",strcat(char strA,char strB),返回的结果是 CHINAChinese)
注意事项: 函数的返回值是strA,其总长度是原来strA与strB的总长度,所以要对strA进行字符容纳设定,其可容纳字符必须大于strA与strB字符串的字符数总量。
#include<stdio.h>
#include<string.h>
int main()
{
char strA[50] ="Chin";//要对strA进行容纳字符数设定
char strB[] = "ese";
strcat(strA, strB);
puts(strA);
return 0;
}
输出:
Chinese
5.strncat函数
原型:char* strncat(char* strA,char* strB,int n)
头文件:#include<string.h>
作用:把字符串strB的前n个字符拼接到字符串strA的末尾。
注意事项: 函数的返回值是strA,其总长度是原来strA与strB前n个字符的总长度,所以要对strA进行字符容纳设定,其可容纳字符必须大于strA与字符串trB前n个字符的字符数总量。
#include<stdio.h>
#include<string.h>
int main()
{
char strA[20] ="hello";
char strB[] = "world";
strncat(strA, strB,3);
puts(strA);
return 0;
}
输出:
hellowor
6.strcmp函数
原型:int strcmp(char* strA,const char* strB)
头文件:#include<string.h>
作用:对字符串strA与字符串strB进行每一个字符的阿斯克码比较,直到出现不同的字符,或者到达字符串strB的末尾(即‘\0’)。
返回值:当遇到不同的字符时,如果strA此字符的阿斯克码大于strB此字符的阿斯克码,返回值是1,反之-1;如果strA与strB相等返回值即0。
//示例1:
//由于w的阿斯克码大于l,返回-1
#include<stdio.h>
#include<string.h>
int main()
{
char strA[] ="hello";
char strB[] = "hewl";
int a = strcmp(strA, strB);
printf("%d", a);
return 0;
}
//示例2
//用户输入两个字符串,进行比较,如果不同那么输出no,如果相同输出yes
#include<stdio.h>
#include<string.h>
int main()
{
char strA[20];
char strB[20];
gets(strA);//输入之后要回车
gets(strB);
if (strcmp(strA, strB) == 0)
printf("yes");
else
printf("no");
return 0;
}
7.strncmp函数
原型:int strncmp(char* strA,const char* strB,int n)
头文件:#include<string.h>
作用:将strA与strB的前n个字符进行比较,返回原理同上。
//示例:
//用户自行输入两个字符串,将第二个字符串的前n个与第一个字符串进行比较,如果相同那么输出yue,否则输出no
#include<stdio.h>
#include<string.h>
int main()
{
char strA[20];
char strB[20];
int n;
gets(strA);//输入完后要回车
gets(strB);//输入完后要回车
scanf("%d", &n);//输入一个数字n,作用表示strB的前n个字符
if (strncmp(strA, strB,n) == 0)
printf("yes");
else
printf("no");
return 0;
}
输出:
hello
hell
4
yes
8.strchr函数
原型:char* strchar(const char* str ,int a)
头文件:#include<string.h>
作用:在字符串str查找字符a。strchr函数会检索str的每一个字符,如果找到a就返回a首次出现的位置,反正返回NULL。可以应用到字符检索,查找字符。
//示例1
#include<stdio.h>
#include<string.h>
int main()
{
char str[]="Thank you for reading";
char a;
scanf("%c", &a);
printf("%x", strchr(str, a));//返回的是a在str首次出现的位置,以十六进制数输出
return 0;
}
//示例2
//用户输入一个字符串和一个字符,检测这个字符在该字符串是否出现
#include<stdio.h>
#include<string.h>
int main()
{
char str[100];
char a;
int k = 0;
gets(str);//要回车换行
scanf("%c", &a);
if (strchr(str, a))
printf("yes");
else
printf("no");
return 0;
}
完结撒花!!!