C++ 语法基础课5 —— 字符串

1. 字符与整数的联系 —— ASCII码

  • 每个常用字符都对应一个-128~127的数字,二者之间可以相互转化
#include <iostream>
using namespace std;
int main()
{
	char c = 'a';
	cout << (int)c << endl;
	
	int a = 66;
	cout << (char)a << endl;
	return 0;
}
  • 常用ASCII值:’A’-‘Z’ 是65~90,’a’-‘z’是97-122,’0’-‘9’是48-57
  • 字符可以参与运算,运算时会将其当做整数:
#include <iostream>
using namespace std;

int main()
{
	int a = 'B' - 'A';
	int b = 'B' * 'A';
	char c = 'A' + 2;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	return 0;
}

1.1 练习1 — 统计数字和字母个数

  • 输入一行字符,统计出其中数字字符的个数,以及字母字符的个数
#include<iostream>
using namespace std;

int main()
{
    char c;
    
    int nums = 0, chars = 0;// 数字和字母个数
    while(cin >> c)// 读入字符
    {
        if(c >= '0'&&c <= '9') nums++;
        else if(c >= 'A' && c <= 'z' || c >= 'a'&& c <= 'z') chars++;
    }
    printf("numbers:%d\nchars:%d",nums,chars);
    return 0;
}

在这里插入图片描述

1.2 练习2 — 字符和数字的转换

#include<iostream>
using namespace std;

int main()
{
    char c = 'a';
    cout << (int)c << endl;
    printf("%d\n",'z'-'a');
    printf("%c\n",'a'+3);
    
    int a ='B'-'A';
    char b= 'A'+2;
    cout << a << endl;
    cout << b << endl;
    return 0;
}

在这里插入图片描述

1.3 练习3 — 查询ASCII码

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
    for(int i = 1;i < 128;i++)
    printf("%d:%c\n",i,(char)i);// 输出ASCII码以及对应字符
    return 0;
}

2. 字符数组 —— 用字符数组存储字符串

  • 字符串就是字符数组加上结束符’\0',string底层就是用字符数组实现的。存长度为L的字符串,则字符数组的长度至少为 L+1
  • 可以使用字符串来初始化字符数组,但此时要注意,每个字符串结尾会暗含一个’\0’字符,因此字符数组的长度至少要比字符串的长度多1
#include <iostream>
using namespace std;

int main()
{
	// a1不是字符串,a2和a3都是字符串,因为都有'\0'
	char a1[] = {'C', '+', '+'}; // 列表初始化,没有空字符
	char a2[] = {'C', '+', '+', '\0'}; // 列表初始化,含有显示的空字符,有\0,可以被称为字符串
	char a3[] = "C++"; // 自动添加表示字符串结尾的空字符,数组长度为4,因为有'\0'字符。
	char a4[6] = "Daniel"; // 错误,没有空间可存放空字符,方框里至少填7
	cout << a2 << endl;
	printf("%s\n",a3);
	return 0;
}

2.1 字符数组读入(fgets和getline)和输出(重点!)

  • fgets()函数能读入空格
  • cin >> str; 输入字符串时,遇到空格或者回车就会停止
  • cout << str << endl; 输出字符串时,遇到空格或者回车不会停止
  • printf(“%s\n”,str); 等价于 puts(str);puts函数输出包括换行符,printf输出不包含
#include<iostream>
using namespace std;

int main()
{
	char str[100];
	cin >> str; // 输入字符串时,遇到空格或者回车就会停止
	cout << str << endl; // 输出字符串时,遇到空格或者回车不会停止
	printf("%s\n",str);// 等价于 puts(str);puts函数后面包括换行符
	return 0;
}
  • printf(“%s\n”,str); 等价于 puts(str),但是puts函数后面包含换行符
#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
	char str[100];
	scanf("%s",str);
	// 等价于 puts(str);puts函数包括换行符
	printf("%s\n",str);
	return 0;
}
  • 读入一行字符串,包括空格,不能再使用gets函数,已经被淘汰了。以下是读入有空格的句子
  • 方式1:使用fgets()函数
#include <iostream>
using namespace std;

int main()
{
	char str[100];
	fgets(str,100,stdin);// stdin是系统定义好的变量
	cout << str << endl;
	return 0;
}

Acwing 815.打印字符串,这道题重点看

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

void print(char str[])
{
    // puts(str);// 调用函数直接打印,会输出回车
    printf("%s",str);
}

int main()
{
    char str[110];
    // 多输入回车,中间的是101
    fgets(str,101,stdin);// 在字符串最后加回车"\n",使用puts函数会输出回车,printf不会输出回车
    
    // 或者直接用getline
    cin.getline(str, 101);// getline函数和fgets函数二者选择其中一个
    print(str);
    return 0;
}
  • 方式2:使用getline函数——只适用于string类型
#include<iostream>
#include<string>
using namespace std;

int main()
{
	string str;
	getline(cin, str);// 只能是string类型
	cout << str << endl;
	return 0;

2.1.1 练习1 — 字符串输出

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
    char a1[] = {'A','B','C'};
    cout << a1 + 1 << endl;// 输出BC
    // 从A开始输出, cout << a1 << endl
    // 从B开始输出, cout << a1 + 1 << endl
    char a2[] = {"ABCDEF"};
    printf("%s\n",a2 + 2);// 输出cdef
}

2.1.2 练习2 — 字符串读入

  • 遇到空格、回车、结束符就停止读入(重难点)
  • scanf(“%s”,a)一定不要加&
  • 所有数组的名字本身就是一个指针
#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
    char s[100];
    // scanf("%s",s); 输入abc
    // cout << s << endl;// 输出abc
    cin >> s;// 同scanf
    cout << s << endl;
    return 0;
}
  • 从指定数组位置开始输入和输出数据
#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
	char s[100];
	// 读入字符串是读到空格或者回车为止。
    cin >> s+1;// 从s[1]开始读入字符串,就是从s[1]开始存入字符串abc,相配套的是cout << s+1,从s[1]开始输出字符串。
    // scanf("%s",s+1);// 不要用取地址符号&,或者scanf("%s",&s[1])也是可以的,这里也是从s[1]开始存入字符串,同上面的 cin >> s+1
    
    cout << s+1 << endl;// 从s[1]开始输出完整字符串,abc
    cout << s[1] << endl; // 数组下标从1开始,结果为a。
    // printf("%s\n",s + 1); 表示从下表1开始输出。等同于cout << s+1 <<endl
    return 0;
}

在这里插入图片描述

#include<iostream>
#include<cstdio>
using namespace std;

int main()
{
	char s[100];
	scanf("%s",s + 2);
	cin >> s + 2;
	printf("%s", s + 1);
	cout << s + 2 << endl;
	return 0;
}

2.2 字符数组的常用操作(#include<cstring>)

  • 下面几个函数需要引入头文件:#include <string.h>
  • (1) strlen(str),求字符串的长度,只计算字符串中的元素,不包括\0
  • (2) strcmp(a, b),比较两个字符串的大小,a < b 返回-1,a == b 返回0,a >
    b返回1。这里的比较方式是字典序
  • (3) strcpy(a, b),将字符串b复制给从a开始的字符数组
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
	char a[100] = "hello world!", b[100];
	cout << strlen(a) << endl;// 不包括'\0'字符
	strcpy(b, a);// 复制
	return 0;
}
  • strcpy复制函数
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
	char s1[100], s2[100];
	scanf("%s",s1);
	strcpy(s2, s1);// 读入s1复制给s2
	cout << s2 << endl;
	return 0;
}
  • strcmp 比较函数
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
	char a[100], b[100];
	scanf("%s%s",a,b);
	cout << strcmp(a,b) << endl;// 输入时两个字符串需要用空格或者回车分开
	return 0;
}
  • 遍历每一个字符
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int main()
{
	char s1[100], s2[100];
	scanf("%s",s1);
	int len = strlen(s1);// 提高效率
	for(int i = 0; i < len; i++) cout << s1[i] << endl;
	return 0;
}

2.2.1 练习1 — 字符串(char数组)长度strlen()

  • char 数组求长度用strlen函数, int 数组用siezof(a)/sizeof(a[0]), string类型用size()函数
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int main()
{
	// 第一种方法
    char s[100];
    scanf("%s",s);
    cout << strlen(s) << endl;// 长度
    return 0// 第二种方法
    char s[100];
    scanf("%s",s);
    
    int len = 0
    for(int i = 0; s[i] ;i++) len++;// s[i]表示不等于零的情况下,i++
    
    cout << len << endl;
}

2.2.2 练习2 — 字符串比较strcmp()

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int main()
{
    char s1[100],s2[100];
    scanf("%s%s",s1,s2);   
    cout << strcmp(s1,s2) << endl;// 字符串的比较
    return 0;
}

2.2.3 练习3 — 字符串复制strcpy()

#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

int main()
{
    char s1[100],s2[100];
    scanf("%s",s1);  
    strcpy(s2,s1);  
    cout << s2 << endl;//字符串复制  
    return 0;
}

2.2.4 练字4 — 遍历字符数组中字符strlen()

#include<iostream>
#include<string.h>
using namespace std;

int main()
{
	char a[100] = "hello world!";
	// for(int i = 0;i < strlen(a);i++) cout << a[i] << endl;// 这种写法效率低
	for(int i = 0, len = strlen(a);i < len; i++) cout << a[i] << endl;
	return 0;
}

2.3 练习1 —— Acwing 772.只出现一次的字符

Acwing 772.只出现一次的字符

  • 题目要求:给定一个只包含小写字母的字符串,请你找到第一个仅出现一次的字符。如果没有,输出“no”。

  • 思路:如何读入字符串?如何遍历字符串中每个字符?如何统计每个字符出现的次数?

  • 如何统计字母出现的次数:开一个cnt[26]数组

  • 方法1

#include<iostream>
#include<cstdio>
#include<cstring>// 字符串的函数
using namespace std;

int cnt[26] = {0};// 存储每个字母出现的次数
char str[100010];// 存储字符串

int main()
{
    cin >> str;
    // str[i]里面都是小写字母,小写字母 - 'a'结果是整数,0-25分别表示a-z,'a'在做运算时都是整数运算
    for(int i = 0;i < strlen(str);i ++) cnt[str[i] - 'a'] ++;// cnt[]++表示对当前数组元素进行自增操作,元素值+1。数组加上下标就是变量
    // strlen每次进行循环都会重新执行一遍,延长执行的时间
    
    for(int i = 0; i < strlen(str);i ++)
        if(cnt[str[i] - 'a'] == 1)// 判断cnt[]中哪一个的元素值为1
        {
            cout << str[i] << endl;// 只出现一次则输出字符
            return 0;
        }
    
    puts("no");// 没有则输出no
    return 0;
}

方法2:使用len = strlen(str),可以缩短运行时间

#include<iostream>
#include<cstdio>
#include<cstring>// 字符串的函数
using namespace std;

int cnt[26] = {0};// 存储每个字母出现的次数
char str[100010];// 存储字符串

int main()
{
    cin >> str;
    int len = strlen(str);
    // str[i]里面都是小写字母,小写字母 - 'a'结果是整数,0-25分别表示a-z,'a'在做运算时都是整数运算
    for(int i = 0;i < len;i ++) cnt[str[i] - 'a'] ++;// cnt[]++表示对当前数组元素进行自增操作,元素值+1。数组加上下标就是变量
    // strlen每次进行循环都会重新执行一遍,延长执行的时间
    
    for(int i = 0; i < len;i ++)
        if(cnt[str[i] - 'a'] == 1)// 判断cnt[]中哪一个的元素值为1
        {
            cout << str[i] << endl;
            return 0;
        }
    
    puts("no");
    return 0;
}
  • 方法3:不求str的长度,条件用str[i],表示遇到’\0’就停止。字符串结尾是\0
#include<iostream>
#include<cstdio>
#include<cstring>// 字符串的函数
using namespace std;

int cnt[26] = {0};// 存储每个字母出现的次数
char str[100010];// 存储字符串

int main()
{
    cin >> str;
    
    // str[i]里面都是小写字母,小写字母 - 'a'结果是整数,0-25分别表示a-z,'a'在做运算时都是整数运算
    for(int i = 0;str[i];i ++) cnt[str[i] - 'a'] ++;// cnt[]++表示对当前数组元素进行自增操作,元素值+1。数组加上下标就是变量。等价于 cnt[] += 1    
    for(int i = 0;str[i];i ++)
        if(cnt[str[i] - 'a'] == 1)// 判断cnt[]中哪一个的元素值为1
        {
            cout << str[i] << endl;
            return 0;
        }
    
    puts("no");
    return 0;
}

2.4 练习2 —— Acwing 769.替换字符

Acwing 769.替换字符

  • 把一个字符串中特定的字符全部用给定的字符替换,得到一个新的字符串

难点

  • scanf(“\n%c”, &c);读入要替换的字符,读入字符不会自动过滤掉前面的回车\n,会读入回车。需要在前面加\n
#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
    char str[31];
    scanf("%s",str);// 读入到回车或者'\0'就结束了
    
    char c;// 读入要替换的字符
    scanf("\n%c", &c);// 读入要替换的字符,读入字符不会自动过滤掉前面的回车\n,会读入回车。需要在前面加\n,过滤回车。cin 没有这个问题
    
    for(int i = 0;str[i];i++)
        if(str[i] == c)
           str[i] = '#';
    
    puts(str);
    return 0;
}

3. 标准库类型 string —— 用string来存储字符串

  • 可变长的字符序列,比字符数组更加好用。需要引入头文件:#include <cstring>

3.1 定义和初始化

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

int main()
{
	string s1; // 默认初始化,s1是一个空字符串
	string s2 = s1; // s2是s1的副本
	string s3 = "hiya";// s3是该字符串字面值的副本
	string s4(10, 'C'); // s4内容是ccccccccccc
	return 0;
}

3.2 string 的操作

3.2.1 string的读入和输出(重点)

#include<iostream>
#include<string>
using namespace std;

int main()
{
	string s1,s2;
	cin >> s1 >> s2;// 读入
	// scanf("%s",&s1);是错误的写法,不能用scanf读入字符串
	cout << s1 << ' ' << s2 << endl;
	// 输出可以用printf, 
	printf("%s\n",s1.c_str());// c_str()是成员函数,返回的是存储字符串s1的字符数组的首地址,打印出的结果是字符数组。cin输入abc,打印出来的也是abc
	// 输出也可以用puts
	puts(s1.c_str());
	return 0;
}
  • 注意:不能用printf直接输出string,需要写成:printf(“%s”, s.c_str())

3.2.2 string读入一行使用getline(重点!)

  • 如果输入是:abc cde abd,使用 cin >> s,则输出是abc,使用 getline(cin, s)则 输出是abc cde abd。
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	string s1;
	getline(cin, s1);// string读入一行
	// cin >> s1; // 表示读入第一个字符串
	// cin.getline(s2, 1000);// 字符串使用cin读入一行
	cout << s1 << endl;
	return 0;
}

3.2.3 string的empty和size(求长度)函数

  • 注意size是无符号整数,因此 s.size() <= -1一定成立。
  • empty()返回的是bool值
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	string s1, s2 = "abc";
	cout << s1.empty() << endl;// empty返回的是布尔值
	cout << s2.empty() << endl;
	cout << s2.size() << endl;
	return 0;
}

在这里插入图片描述

3.2.4 string的比较

  • 支持 > < >= <= == !=等所有比较操作,按字典序进行比较

3.2.5 string对象赋值

string s1(10, ‘c’), s2;		// s1的内容是 cccccccccc;s2是一个空字符串
s1 = s2;					// 赋值:用s2的副本替换s1的副本
							// 此时s1和s2都是空字符串

3.2.6 两个string对象相加

string s1 = “hello,, s2 = “world\n”;
string s3 = s1 + s2;					// s3的内容是 hello, world\n
s1 += s2;								// s1 = s1 + s2

3.2.7 字面值和string对象相加

  • 做加法运算时,字面值和字符都会被转化成string对象,因此直接相加就是将这些字面值串联起来
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	string s1 = "hello", s2 = "world";		// 在s1和s2中都没有标点符号
	string s3 = s1 + ", " + s2 + '\n';
	cout << s3 <<endl;
	return 0;
}
  • 当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符的两侧的运算对象至少有一个是string
string s4 = s1 + ",";	// 正确:把一个string对象和有一个字面值相加
string s5 = "hello" + ","; // 错误:两个运算对象都不是string
string s6 = s1 + "," + "world";  // 正确,每个加法运算都有一个运算符是string。s1 + ","结果是string类型
string s7 = "hello" + "," + s2;  // 错误:不能把字面值直接相加,运算是从左到右进行的。先计算"hello" + ","得到字符串,不是string类型

3.3 处理string对象中的字符(重点!)

3.3.1 数组长度(char-strlen&string-size)+引用&

  • 可以将string对象当成字符数组来处理
  • char字符数组长度用strlen()
  • string字符串长度使用size()
#include<iostream>
#include<string.h>
using namespace std;

int main()
{
	// char a[100] = "hello world!";
	// for(int i = 0;i < strlen(a);i++) cout << a[i] << endl; 
	string s = "hello world";
	for(int i = 0;i < s.size();i ++) cout << s[i] << ' ';
	return 0;
}

在这里插入图片描述

  • 或者使用基于范围的for语句
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	string s = "hello world";
	for(char c : s) cout << c << endl;// c++的范围遍历,char 表示每一个字符数组元素的类型,s表示字符串,c顺次遍历s[0],s[1],...
	cout << endl;
	cout << s << endl;
	
	for(char &c : s) c = 'a';// 改变c的同时改变s的值,加了&表示c等价于字符串s
	cout << s << endl;
	return 0;
}

在这里插入图片描述

int main()
{
	string s = "hello world";
	for(char c : s)
	{
		c = 'a';
	}

	// 等价于下面的操作
	for(int i = 0; i < s.size();i ++)
	{
		char c = str[i];
		c = 'a';
	}
}
  • 加引用符号&
int main()
{
	string s = "hello world";
	for(char &c : s)
	{
		c = 'a';
	}

	// 等价于下面的操作
	for(int i = 0; i < s.size();i ++)
	{
		char &c = str[i];// 加引用符号&后,c和str完全相同
		c = 'a';
	}
}

3.3.1 auto语法

  • auto让编译器自己猜数据类型
#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	string s = "hello world";
	for(auto c : s) cout << c << endl;// c++的范围遍历,char 表示每一个字符数组元素的类型,s表示字符串,c顺次遍历s[0],s[1],...
	return 0;	
}

3.3.2 练习1 —— Acwing 767. 信息加密

Acwing 767.信息加密

  • 密码翻译,输入一个只包含小写字母的字符串,将其中的每个字母替换成它的后继字母,如果原字母是’z’,则替换成’a’。
  • 思考:读入包括空格的字符串(使用getline函数)
#include<iostream>
using namespace std;

int main()
{
    string s;
    getline(cin, s);// 读入有空格的字符串
    
    for(auto &c : s)
    {
        if(c >= 'a' && c <= 'z') c = 'a' + (c - 'a' + 1) % 26;// 后面表示新的偏移量
        else if(c >= 'A' && c <= 'Z') c = 'A' + (c - 'A' + 1) % 26;
    }
    
    cout << s << endl;
    return 0;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2021 Nqq

你的鼓励是我学习的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值