- 大纲要求
- 字符类型和字符数组
- sscanf从字符串格式化输入
- 找第一个只出现一次的字符">例题, 找第一个只出现一次的字符
- 验证子串">例题,验证子串
- 删除单词后缀">例题,删除单词后缀
- 单词的长度">例题,单词的长度
- 单词翻转">例题,单词翻转
大纲要求
•【2】字符数组与字符串的关系
•【2】字符数组的综合应用
•【2】string类定义、相关函数引用
•【3】string类的综合应用
字符类型和字符数组
// 字符类型
char c;
int a[N];
double a[N];
bool a[N];
// 字符数组
char s[N];
char s[N][N];
/*
.#...#
...#..
#.....
*/
// 界定符
'a' 字符 ' '
"a" 字符串 "abc" "" " "
a[0] = '\n';
cout << a[0];
#include <bits/stdc++.h>
using namespace std;
int main()
{
cout << sizeof ('a') << '\n';
cout << sizeof ("a") << '\n';
return 0;
}
/*
1
2
*/
字符占一个字节,“a”会增加一个字节,用来存放字符串结束符'\0',所以占2字节
// 字符串读入
#include <cstdio>
using namespace std;
char s[110];
int main()
{
scanf("%s", s);
printf("%s\n", s);
int len = strlen(s);
printf("%d\n", len);
return 0;
}
// string类
#include <iostream>
using namespace std;
int main()
{
string s;
cin >> s;
cout << s << '\n';
return 0;
}
// 读入一整行
// ab cd ed
#include <iostream>
using namespace std;
int main()
{
string s;
getline(cin, s);
cout << s << '\n';
return 0;
}
// string类的字符串处理函数
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
string s;
s = "abcdef";
cout << s << '\n';
cout << s.size() << '\n'; //输出字符串大小
cout << s.substr(2) << '\n'; //截取子串,是位置2开始往后所有
cout << s.substr(2, 3) << '\n'; //从位置2开始,截取三位
return 0;
}
// 字符串长度
char s[110];
scanf("%s", s);
int len = strlen(s); // 字符数组,对应 strlen
string s;
cin >> s;
int len = s.size(); // string,对应 .size()
// string::operator+=
#include <iostream>
#include <string>
int main ()
{
std::string name ("John");
std::string family ("Smith");
name += " K. "; // c-string
name += family; // string
name += '\n'; // character
std::cout << name;
return 0;
}
// string::substr
#include <iostream>
#include <string>
int main ()
{
std::string str="We think in generalities, but we live in details.";
// (quoting Alfred N. Whitehead)
std::string str2 = str.substr (3,5); // "think"
std::size_t pos = str.find("live"); // position of "live" in str
std::string str3 = str.substr (pos); // get from "live" to the end
std::cout << str2 << ' ' << str3 << '\n';
return 0;
}
// insert
#include<iostream>
using namespace std;
int main(){
string s="to be question";
string s2="the ";
s.insert(6, s2); // to be (the )question
cout << s << '\n';
return 0;
}
// c_str(),string 转 char*
#include<iostream>
using namespace std;
int main(){
string s("Please split this sentence into tokens");
char *cstr = new char[s.size()+1];
strcpy (cstr, s.c_str());
printf("%s\n", cstr);
return 0;
}
// 二维字符数组,如何有效读入的问题
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 110;
char s[N][N];
int n, m;
int main()
{
cin >> n >> m;
for (int i = 0; i < n; i++) scanf("%s", s[i]);
for (int i = 0; i < n; i++) printf("%s\n", s[i]);
return 0;
}
/*
.....#
####.#
###..#
##.#..
*/
// 如何是下面的写法,是容易被输入数据坑的
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%c", &s[i][j]);
// 虽然我们提前知道了每一行每一列有多少个数字,但是这种操作经常被坑
// 原因是,测试数据,可能每一行的后面有一个空格,一个我们看不见的空格
// 你的代码里,会把这个空格当成一个字符读入。然后,自然读入的数据就不准确了
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> s[i][j];
// 这样倒是可以解决问题,但这并不如上面一层循环更靠谱,尤其当数据量特别大的时候
【扩展阅读】C++中字符串的结尾标志 \0
\0是C++中字符串的结尾标志,存储在字符串的结尾,它虽然不计入串长,但要占一个字节的内存空间。在百度百科中查看\0词条,会有这样一句话:c/c++中规定字符串的结尾标志为'\0'。有人可能认为,在C语言里(C++会不同),'\0'并不是字符型,而是int型。在这里,我们姑且和百度词条作者保持一致,认为\0与'\0'是等价的。由于不同处理器的位数不同,'\0'并不一定是8位的00000000。实际上,由于不同处理器的位数不同,sizeof(int)返回的结果也都不同,而sizeof(char)返回结果一般是1,对8位机来说,一个字节由8位组成,16位机一个字节由16位组成,我们通常用的电脑通常是32位的,即一个字节由32位组成,现在已经是64位机了。CPU一般是以字节为单元进行读取的。但是一般情况下大家还是认同1Byte等于8bit的说法,因为这是构成的最小位数。
'\0'是转义字符,意思是告诉程序,这不是数字0。'\0'和0两者基本上可以通用,例如: string[i] != '\0'和string[i] != 0是一样的。不过'\0'的类型是char型,而0是int类型,所以在大多数计算机上,sizeof(0) = 4而sizeof('\0') = 1,这在特殊情况下不可通用。另外扩展一下,'\0'与'0'也是不同的,他们都是字符,但是他们的ASCII码是不同的:'\0' ASCII码值为0,'0' 也可以写成'\0x30' ASCII码值为48。
在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串。字符串总是 以'\0'作为串的结束符。因此当把一个字符串存入一个数组时,也把结束符 '\0'存入数组,并以此作为该字符串是否结束的标志。有了'\0'标志后, 就不必再用字符数组的长度来判断字符串的长度了。
'\0'就是 字符串结束标志。比如说,把一个字符串赋值给数组:char str1[] = {"Welcome!"}。实际上数组str1在内存中的实际存放情况为: 'W' 'e' 'l' 'c' 'o' 'm' 'e' '!' '\0'。这后面的'\0'是由C编译系统自动加上的。所以在用字符串赋初值时一般无须指定数组的长度, 而由系统自行处理。 把字符数组str1中的字符串拷贝到字符数组str2中。串结束标志'\0'也一同拷贝。
// ASCII码相关的东西,可以百度
// 观察大小写的规律,会相互转化
// 会数字1和字符'1'的转化
#include <bits/stdc++.h>
using namespace std;
const int N = 110;
char s[N];
int cnt[30];
int main(){
scanf("%s", s); // they are lowercase
for (int i = 0; s[i]; i++)
cnt[s[i] - 'a']++;
for (int i = 0; i < 26; i++) cout << cnt[i] << ' ';
puts("");
return 0;
}
sscanf从字符串格式化输入
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
char s[] = "Saturday March 25 1989";
char month[N], weekday[N];
int year, day;
int main(){
sscanf(s, "%s %s %d %d", weekday, month, &day, &year);
printf("%d %s %d\n", day, month, year);
return 0;
}
// CSP-J2021 T3网络连接
// 读入数据用sscanf就相当的妙
// 而我赛场上,只会用字符串,一点一点拆。。 差距显然
#include <bits/stdc++.h>
using namespace std;
int a, b, c, d, e;
char s[] = "192.168.1.1:8080";
int main(){
sscanf(s, "%d.%d.%d.%d:%d", &a, &b, &c, &d, &e);
printf("%d.%d.%d.%d:%d\n", a, b, c, d, e);
return 0;
}
例题, 找第一个只出现一次的字符
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
char s[N];
int vis[30];
int main()
{
scanf("%s", s);
int len = strlen(s);
for (int i = 0; i < len; i++)
vis[s[i] - 'a']++;
bool flag = false;
for (int i = 0; i < len; i++)
{
if (vis[s[i] - 'a'] == 1)
{
flag = true;
printf("%c\n", s[i]);
break;
}
}
if (!flag) printf("no\n");
return 0;
}
例题,验证子串
//string s;
//s.find()
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s1, s2;
cin >> s1 >> s2;
int ans = 0;
if (s1.find(s2) != -1) ans = 1;
else if (s2.find(s1) != -1) ans = -1;
if (ans == 1) cout << s2 << " is substring of " << s1 << endl;
else if (ans == -1) cout << s1 << " is substring of " << s2 << endl;
else cout << "No substring" << endl;
return 0;
}
例题,删除单词后缀
// string s;
// s.erase(len - 2)
// 使用char s[40];
// 匹配后缀成功后,利用s[len-2] = '\0'进行截断
例题,单词的长度
// 第一种方法,直接手搓
// getline(cin, s);
// 然后遍历,碰到空格算一个单词
// 要注意输出的格式
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
getline(cin, s);
bool flag = false;
for (int i = 0, len = s.size(); i < len; i++)
{
while (s[i] == ' ') i++;
if (flag) printf(",");
flag = true;
int j = i;
int cnt = 0;
while (j < len && s[j] != ' ') j++;
printf("%d", j - i);
i = j - 1;
}
puts("");
return 0;
}
// 第二种方法
// 使用while (cin >> s),更好编写
// 不过要注意一下格式控制的小技巧
// 本地调试要使用freopen
#include <bits/stdc++.h>
using namespace std;
int main()
{
//freopen("1.in", "r", stdin);
string s;
bool flag = false;
while (cin >> s){
if (flag) cout << ',';
flag = true;
int len = s.size();
cout << len;
}
puts("");
return 0;
}
例题,单词翻转
//getline(cin, s);
//比较麻烦,构造一个一个单词出来,然后翻转
//使用while (cin >> s)
//会两个点,格式错误,调不出来