【35天从0开始备战蓝桥杯 -- Day3】

🫧个人主页:小年糕是糕手

💫个人专栏:《C++》《Linux》《数据结构》《C语言》

🎨你不能左右天气,但你可以改变心情;你不能改变过去,但你可以决定未来!


目录

一、数组

练习

二、范围for和auto

1°范围for

2°auto

3°练习

三、memset和memcpy

1°memset

2°memcpy

四、字符数组

1°创建与初始化

2°strlen

3°fgets

4°拓展

5°getchar

五、strcpy和strcat

1°strcpy

2°stract

练习


(最近发烧了,身体不太舒服,所以这个系列不知道还能不能按时更完,我会尽力去写的,后面身体好了会一天更两、三篇,谢谢大家的支持!)

一、数组

数组是一种相同类型元素的集合,一维数组是最常见的,他的形式如下:

一维数组是一块连续的空间,我们定义数组的时候往往都是:类型 数组名[元素个数] = {元素}

举个最简单的例子上图数组应该是int arr[5]={1,2,3,4,5},数组是有下标的,从0开始,我们在使用的时候要注意不要越界访问,这里详细的内容可以参考下面的一篇博客:

【C语言】C语言数组:像搭乐高一样构建数据王国的魔法工具-CSDN博客https://blog.csdn.net/2501_91731683/article/details/147604681这里为大家详细介绍了一维数组与二维数组的内容,下面给出一些练习:

练习

https://www.luogu.com.cn/problem/P5732

https://www.luogu.com.cn/problem/B2099

https://www.luogu.com.cn/problem/B2103

https://www.luogu.com.cn/problem/B2104

https://www.luogu.com.cn/problem/B2106

https://www.luogu.com.cn/problem/B2101

https://www.luogu.com.cn/problem/B2108

https://www.luogu.com.cn/problem/P2550

二、范围for和auto

1°范围for

打印数组的元素除了我们上篇博客介绍的三种循环外还有一种方式就是范围for,范围for是在 C++11这个标准中引入的,如果你使用的编译器默认不支持C++11,可能需要配置才能使用,配置教程可以询问AI自行操作

cpp 复制代码
for (类型 变量名 : 数组名)
语句 //多条语句需要加⼤括号 

下面我们来用范围for打印一个数组:

上面代码中的for就是范围for,代码的意思是将arr数组中的元素,依次放在e变量中,然后打印e,直到遍历完整个数组的元素。这里的e是一个单独的变量,不是数组的元素,所以对e的修改,不会影响数组。
但是对于范围 for 要谨慎使用,范围for是对数组中所有元素进行遍历的,但是我们实际在做题的 过程中,可能只需要遍历数组中指定个数的元素,这样范围 for 就不合适了。

2°auto

auto的主要用途是让编译器自动推导出变量的类型的,一般我们和范围for配合使用:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
using namespace std;
int main()
{
	auto a = 10;
	auto b = 'x';
	auto c = 7.7;
	cout << a << b << c << endl;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto  e : arr)
	{
		cout << e << " ";
	}
	return 0;
}

**上述代码中,编译器会自动识别a的类型为int,b为char,c为double,e为int,**范围 for中e前面的类型可以是auto关键字,当你不知道数组中放什么类型的时候,就可以使用auto作为类型,auto在范围for中很常,如果明确的知道数组元素的数据类型,也可以将auto换成对应的数据类型。3

3°练习

https://www.luogu.com.cn/problem/B2093

https://www.luogu.com.cn/problem/B2089

https://www.luogu.com.cn/problem/B2091

https://www.luogu.com.cn/problem/B2090

https://www.luogu.com.cn/problem/B2092

https://www.luogu.com.cn/problem/P1428

http://ybt.ssoier.cn:8088/problem_show.php?pid=2039

三、memset和memcpy

1°memset

函数需要包含头文件#include<cstring>,函数原型如下:

memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	char arr1[] = "hello world";
	cout << arr1 << endl;
	memset(arr1, 'x', 5 * sizeof(char));//数组名就是数组首元素的地址
	cout << arr1 << endl;
	
	int arr2[5] = { 1,2,3,4,5 };
	for(auto e : arr2)
	{
		cout << e << " ";
	}
	cout << endl;
	memset(arr2, 0, 5 * sizeof(int));
	for (auto e : arr2)
	{
		cout << e << " ";
	}
	return 0;
}

这里需要注意的是打印字符数组的时候可以直接cout<<arr<<endl;但是打印整型数组则不可以:

1. 字符数组 cout << arr1 能正常输出字符串

coutchar* 类型(字符数组名退化为 char*)做了特殊重载

  • 它会认为 char* 是「字符串的起始地址」,从这个地址开始逐个输出字符,直到遇到 \0(字符串结束符)为止;
  • 你代码中 arr1 = "hello world" 本身自带 \0,所以 cout << arr1 能打印完整字符串。

2. 整型数组 cout << arr2 只会输出地址

coutint* 类型(整型数组名退化为 int*)没有特殊重载:

  • 它会把 int* 当成普通的「内存地址」处理,直接输出数组首元素的内存地址(十六进制);

  • 如果你强行写 cout << arr2 << endl;,运行后会看到一串数字(比如 0x61fe00),而不是数组内容。
    总结:

  • cout << 数组名 的行为由数组类型决定:字符数组名退化为 char*cout 会打印字符串;整型数组名退化为 int*cout 只打印地址;

  • 要输出整型数组内容,必须通过循环(范围 for / 普通 for)逐个遍历元素;

  • memset 依赖的是「内存地址」,所以对字符 / 整型数组都能生效(但需注意按字节赋值的特性)。

我们来看下面一段代码:

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
	int arr[] = { 1,2,3,4,5 };
	memset(arr, 1, 4 * sizeof(int));
	for (auto e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

我的预想的是将这个数组里的元素全部改为1,但是当我们运行这段代码:

这很明显是不符合我们预期的,那到底是为什么呢?

从上面打印结果可以看出,当value设置为1或者其他非0的数字时,打印结果不符合预期。 主要原因是 `memset` 函数是给每个字节设置 value 值,而一个整型元素占用4个字节,一个整型的每个字节都被设置为1,二进制就是:`00000001 00000001 00000001 00000001`,转换成十进制就是:`16843009`,因此结果是不符合预期的。如下图所示:

2°memcpy

函数需要包含头文件#include<cstring>,函数原型如下:

在使用数组的时候,有时候我们需要将数组a的内容给数组b,我们不能直接b = a,这时候我们就可以使用memcpy了,memcpy可以做数组内容的拷贝,当然memcpy其实是用来做内存块的拷贝的,当然用来做数组内容的拷贝也是没问题的。

cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
	int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int b[10] = { 0 };
	memcpy(b, a, 10 * sizeof(int));
	for (int e : b)
	{
		cout << e << " ";
	}
	return 0;
}

四、字符数组

首先先来说一个结论,cout在输出的时候整型数组不可以直接输出,但是字符数组可以:

1°创建与初始化

C语言中使用双引号括起来一串字符表示字符串,这种方式虽然在C++中也是支持的,但是一般我们会将这种字符串称为C语言风格的字符串。如果需要将一个C语言风格的字符串存储起来,就可以使用字符数组。

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
	//⽅式1 
	char ch1[10] = "abcdef";
	char ch2[] = "abcdef";//如果数组初始化的时候,数组的⼤⼩可以省略不写,数组⼤⼩会根据初始化内                                             
                          //容来确定
	//⽅式2 
	char ch3[10] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	char ch4[] = { 'a', 'b', 'c', 'd', 'e', 'f' };

	return 0;
}

如果调试看一下ch2和ch4数组的内容,我们会明显的发现,数组ch2中多一个'\0'字符,这是因为字符串的末尾其实隐藏一个'\0'字符,这个'\0'是字符串的结束标志,在打印字符串的时候遇到'\0',打印结束。('\0'是字符串结束的标志)

2°strlen

字符数组中存放的着字符串,这个字符数组有自己的长度,也就是数组的元素个数,这个可以使用sizeof计算,那数组中存放的字符串的长度是多少?怎么来计算呢?

其实C/C++中有一个库函数叫:strlen,可以求字符串的长度,其实统计的就是字符串中'\0'之前的字符个数。strlen需要的头文件是<cstring>

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = { 'a','b','c','d','e','f' };
	cout << strlen(arr1) << endl;//6
	cout << strlen(arr2) << endl;//随机数
	return 0;
}

这里arr2没有\0也就没有结束的标志,所有输出的会是一个随机值:

我们要注意他与sizeof的区别,sizeof算出的是一个数组的大小,单位是字节,strlen算出的是一个数组\0前的元素个数

这里补充一下假如我们假如想跳过一个字符去打印和输出可以进行如下的操作:

cpp 复制代码
#include <iostream>
using namespace std;
int main()
{
	char arr[20] = { 0 };
	//输⼊ 
	cin >> arr + 1;//arr表⽰数组的起始位置,+1意思是跳过⼀个元素,就是第⼆个元素的位置 
	//可以通过调试观察⼀下arr的内容 
	cout << arr + 1;
	return 0;
}

3°fgets

**一般输入的时候我们都会采用scanf和cin但是他们都不太好处理有空格的时候,例如:假如我们要输出abd eg,这里cin和scanf只会读取到abd,遇到占位符就会停止读取,**这时候我们就可以用函数fgets去读取完整的字符串

参数 含义
str 字符数组 / 字符指针,用来存储读取到的字符串(最终会自动加 \0
num 最大读取字符数(实际最多读 num-1 个字符 ,留 1 个位置给 \0
stream 读取来源:- 从控制台输入:写 stdin(标准输入)- 从文件读取:写文件指针(比如 fp

1. gets 函数读取规则

gets 是从第一个字符开始读取,一直读取到 \n 停止,但是不会读取 \n,也就是读取到的内容中没有包含 \n,但是会在读取到的内容后自动加上 \0


2. fgets 函数读取规则

fgets 也是从第一个字符开始读取,最多读取 num-1 个字符,最后一个位置留给 \0,如果 num 的长度是远大于输入的字符串长度,就会一直读取到 \n 停止,并且会读取 \n,将 \n 作为读取到内容的一部分,同时在读取到的内容后自动加上 \0

cpp 复制代码
#include<iostream>
int main()
{
	char arr[10] = { 0 };
	gets(arr);
	printf("%s\n", arr);
	return 0;
}

这里从标准输入(控制台)读取字符串,存入arr数组,但是需要注意C++11中取消了gets,所以大家了解一下就好了,下面我们来重点看fgets:

上述两个程序,同样运行起来后,在控制台窗口中输入:abc def,按回车,方案1和方案2中arr数组的内容中差异如下:

  • fgets 核心用法:fgets(数组名, 数组长度, stdin)(控制台输入),num 填数组长度即可;
  • 必做操作:读取控制台输入后,一定要删掉 \n(用 strcspn 或手动遍历);
  • 核心优势:有长度限制,安全不溢出,支持读取带空格的字符串,替代 gets 的首选。

4°拓展

当然 C 语言中使用 scanf 函数其实也能做到读取带有空格的字符串,只是不常见而已。方式就是将 "% s" 改成 "%[^\n] s",其中在 % 和 s 之间加上了 [^\n],意思是一直读取,直到遇到 \n,这样即使遇到空格也就不会结束了。

这种方式读取,不会将 \n 读取进来,但是在读取到的字符串末尾加上 \0。

5°getchar

之前我们介绍过getchar,我们也可以用getchar来读取一个字符串,具体操作如下:

cpp 复制代码
#include<iostream>
using namespace std;
int main()
{
	char arr[10] = { 0 };
	int ch = 0;
	int i = 0;
	while ((ch = getchar()) != '\n')
	{
		arr[i] = ch;
		i++;
	}
	cout << arr << endl;

	return 0;
}

字符数组输出方式非常多,这里就不作阐述了,大家可以直接用cout<<arr<<endl,这种最暴力的方式

五、strcpy和strcat

上次我们讨论过了整型数组不可以使用一个数组对另一个数组直接赋值,那使用字符数组可以存放字符串,但是字符数组能否直接赋值呢?

cpp 复制代码
char arr1[] = "abcdef";
char arr2[20] = { 0 };
arr2 = arr1;//这样这节赋值可以吗 

整型数组中,我们说的过不可以,这里也是不行的。那么如何将arr1中的字符串,拷贝到arr2中呢?其实C/C++中有一个库函数叫strcpy,可以完成:

1°strcpy

函数需要包含头文件<cstring>,函数原型如下:

cpp 复制代码
#include<iostream>
#include<cstring>
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);
	printf("%s\n", arr2);
	return 0;
}

大家可以简单理解:strcpy(a1,a2),这里a2放的是我们想要拷贝的字符串,a1是我们想要拷贝到的地方

2°stract

有时候我们需要在一个字符的末尾再追加一个字符串,那字符数组能直接追加吗?

cpp 复制代码
char arr1[20] = "hello ";
char arr2[] = "world";
arr1 += arr2;//这样也是不⾏的

那怎么办呢?C/C++中有⼀个库函数叫strcat,可以完成,函数需要头文件<cstring>,函数原型如下:

cpp 复制代码
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strcat(arr1, arr2);
	cout << arr1 << endl;
	return 0;
}

这里我们下一篇博客中会将string会让这种操作变得更加简单,这里大家可以简单理解为:stract(a1,a2),我们想将a2拷贝一份粘贴到a1上

练习

https://www.luogu.com.cn/problem/P5733

https://www.luogu.com.cn/problem/B2109

https://ybt.ssoier.cn/problem_show.php?pid=1139

https://www.luogu.com.cn/problem/B2111

https://www.luogu.com.cn/problem/B2113

https://www.luogu.com.cn/problem/B2118

https://www.luogu.com.cn/problem/B2110


相关推荐
Pu_Nine_93 小时前
企业级 Axios 配置实战:从基础到完整封装
前端·ajax·axios·网络请求·企业级
低调小一3 小时前
OpenClaw 模型配置与火山 Coding Plan 支持清单(实践笔记)
java·前端·笔记·openclaw
vx-bot5556663 小时前
企业微信ipad协议的增量同步算法与差量更新机制
算法·企业微信·ipad
xuxie993 小时前
Next 13 sqlite3 查找、网页
java·数据库·oracle
悦心无谓3 小时前
C++负载均衡式在线OJ测试报告
开发语言·c++·selenium·测试工具·负载均衡·编程语言·后端开发
不想写代码的星星3 小时前
C++引用的“三重门”:左值、右值、万能引用,你真的懂了吗?
c++
毛骗导演3 小时前
万字解析 OpenClaw 源码架构-消息渠道集成简介
前端·架构
kyriewen3 小时前
别再直接 git push 了!这个"魔法"参数让你的代码质量翻倍
前端·git·命令行
小温冲冲3 小时前
Qt进阶:高级渲染与界面定制完全指南(新手友好版)
c++·qt
꯭ 瞎꯭扯꯭蛋꯭3 小时前
3万字80道Java基础经典面试题总结
java·开发语言