C++微基础备战蓝桥杯之数组篇10.1
【C++数组学习笔记】本文系统讲解了C++中数组的使用方法,分为一维数组、二维数组和字符数组三部分。一维数组部分详细介绍了创建初始化、元素访问、范围for循环、auto关键字、memset设置数组和memcpy拷贝数组等操作。二维数组部分讲解了创建初始化、元素访问和memset设置等知识点。字符数组部分重点介绍了字符串初始化、strlen求长度、输入输出方法(包括scanf、cin、gets、fg
#前言
uu们,我开始有点懒散了,今天开始写才发现已经9天没有学习了,~||~,言归正传,接下来高强度一点,看能不能补回来,这一篇大概写c++数组
一. ⼀维数组
数组是⼀组相同类型元素的集合;
从这个概念中我们就可以发现2个有价值的信息:
1.数组中存放的是1个或者多个数据,但是数组元素个数不能为0。
2• 数组中存放的多个数据,类型是相同的。
数组分为⼀维数组和多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。
1. ⼀维数组的创建和初始化
⼀维数组是最常⻅的,通常⽤来存放⼀组数据,⼀维数组是⼀块连续的空间。
1.1 数组创建
⼀维数组创建的基本语法如下:
type arr_name[常量值]
存放在数组的值被称为数组的元素,数组在创建的时候需要指定数组的⼤⼩和数组的元素类型。
type 指定的是数组中存放数据的类型,可以是: 定义的类型 char 、 short 、 int 、 float 等,也可以⾃ arr_name 是数组的名字,这个名字可以⾃定义,根据实际情况,起的有意义就⾏。
•[] 中的常量值是⽤来指定数组的⼤⼩的,数组的⼤⼩是根据实际的需求指定就⾏。在算法竞赛中 为了为了保证不越界访问,往往会多开辟⼀些空间,后期题⽬中会讲到。
可以使⽤ const int N = 100 的⽅式定义常量,来指定数组的⼤⼩。
例如: int arr[N] ;
⽐如:我们现在想存储某个班级的20⼈的数学成绩,那我们就可以创建⼀个数组,如下:
#include <iostream>
using namespace std;
const int N = 20;
int main()
{
int math[N];
return 0;
}
1.12.数组的初始化
有时候,数组在创建的时候,我们需要给定⼀些初始值,这种就称为初始化的。
那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将数据放在⼤括号中。
#include <iostream>
using namespace std;
int main()
{
int arr[5] = {1,2,3,4,5};//完全初始化、
int arr2[6] = {1};//不完全初始化
//错误示范
// int arr3[3] = {1,2,3,4,5}
return 0;
}
1.2. ⼀维数组元素的访问
数组是有下标的,从0开始 ,可以使用下标引用操作符来实现访问
#include <iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
//数组是有下标的,从0开始 ,可以使用下标引用操作符来实现访问
arr[3] = 4;
// 其中的arr[3]就是下标引用操作符
return 0;
}
求数组元素个数
#include <iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
cout << sizeof(arr) << endl;
//--40
//这里使用的是字节,这里的是整型,一个整型占4个字节
//则
cout << sizeof(arr) / sizeof(arr[0]) << endl;
//所有元素字节长度 / 一个元素字节长度
//得出元素个数
return 0;
}
3. ⼀维数组元素的打印
接下来,如果想要访问整个数组的内容,那怎么办呢?
只要我们产⽣数组所有元素的下标就可以了,那我们使⽤for 循环产⽣所有的下标,接下来使⽤下标访问就⾏了。
#include <iostream>
using namespace std;
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for(i = 0; i < 10; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
由打印元素个数方式可将其优化为
#include <iostream>
using namespace std;
int main()
{
int arr[5] = {0};
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for(i = 0;i < sz;i++)
{
cin >> arr[i];
}
for(i = 0; i < sz; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
4. 范围for
打印数组元素除了可以使⽤之前讲过的三种循环外,还有⼀个更⽅便的⽅式,使⽤范围for
范围for语法:
for(类型 变量名 : 数组名 )
但是范围for只能c++11支持使用
比如devC++就不能使用,那如何配置环境呢?
在devC++中,菜单中,点击:工具->编译选项,打开
勾选【编译时加入一下命令】,然后在下方的编译框中加入:
-std=c++11
其他代码块
-std=c++14
-std=c++17
-std=c++20
eg
#include <iostream>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10};
for(int e : arr)
{
e = 1;
}
for(int e : arr)
{
cout << e << " ";
}
//输出1 2 3 4 5 6 7 8 9 10
return 0;
}
范围for只能打印数组,不能更改数组
5. auto 关键字
auto 的主要⽤途是让编译器⾃动推导出变量的类型的,
⽐如:
#include <iostream>
using namespace std;
int main()
{
auto a = 3.14;
auto b = 100;
auto c = 'x';
cout << a << endl;
cout << b << endl;
cout << c << endl;
return 0;
}
调试时能看到a,b ,c ,类型
不想给其明确指定类型,或者不确定其字符类型就可以使用auto
范围for也经常使用auto类型
for(auto e : arr)
{
e = 1;
}
6. memset设置数组内容
函数原型介绍
void * memset ( void * ptr, int value, size_t num );
参数解释:
ptr --
指针:指向了要设置的内存块的起始位置
value --
要设置的值
num --
设置的字节个数
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char arr[] = "hello world";
cout << arr << endl;
//对于整型数组不能直接这样打印
memset(arr,'x',5);
//使用需要头文件 #include <cstring>
cout << arr << endl;
//打印出 xxxxx world
return 0;
}
memset 是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容,需要头⽂件
#include <cstring>
一般使用memset来设置整型数组时都设置为0,其他数字容易出错
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int arr[5] = {1,2,3,4,5};
memset(arr,0,20);
for(int e : arr)
{
cout << e << " ";
}
cout << endl;
//输出 0 0 0 0 0
return 0;
}
比如
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int arr[5] = {1,2,3,4,5};
memset(arr,1,20);
for(int e : arr)
{
cout << e << " ";
}
cout << endl;
//输出 16843009 16843009 16843009 16843009 16843009
return 0;
}
7. memcpy拷⻉数组内容
在使⽤数组的时候,有时候我们需要将数组a的内容给数组b,⽐如:
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int b[10] = {0};
怎么做呢?直接赋值是错误的
数组名是地址,地址是一个常量的值,常量不可被修改
其实C++中有⼀个库函数 memcpy 可以做数组内容的拷⻉,当然 memcpy 其实是⽤来做内存块的拷⻉ 的,当然⽤来做数组内容的拷⻉也是没问题的。
函数原型如下:
#include <cstring>
void * memcpy ( void * destination, const void * source, size_t num );
//destination -- 目标空间的起始地址
//source -- 源数据空间的起始地址
//num -- 拷贝的数据的字节个数
eg
#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 << " ";
}
//打印出1,2,3,4,5,6,7,8,9,10
return 0;
}
二. ⼆维数组
1. ⼆维数组的概念
前⾯学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果我们把⼀维数组做为数组的元 素,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称 为多维数组。
2. ⼆维数组的创建和初始化
2.1.创建
那我们如何定义⼆维数组呢?语法如下:
type arr_name[常量值1][常量值2];
例如:
int arr[3][5];
double data[2][8];
#include <iostream>
using namespace std;
int main()
{
int arr1[3][5] = {1,2};
int arr2[3][50] = {1, 2, 3, 4, 5, 6};
return 0;
}
下⾯解释⼀下上述代码中的⼀些关键信息:
• 3 表⽰数组有 3 ⾏
• 5 表⽰每⼀⾏有 5 个元素
• int 表⽰数组的每个元素是整型类型
• arr 是数组名,可以根据⾃⼰的需要指定名字
data 数组意思基本⼀致。
2.2.初始化
在创建变量或者数组的时候,给定⼀些初始值,被称为初始化。 那⼆维数组如何初始化呢?像⼀维数组⼀样,也是使⽤⼤括号初始化的。
#include <iostream>
using namespace std;
int main()
{
//不完全初始化
int arr1[3][5] = {1,2};
int arr2[3][5] = {0};
//完全初始化
int arr3[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
//按行初始化
int arr4[3][5] = {{1,2},{3,4},{5,6}};
//如果数组初始化了,数组在指定??的时候可以省略?,?不能省略列
int arr5[][5] = {1,2,3};
int arr6[][5] = {1,2,3,4,5,6,7};
int arr7[][5] = {{1,2}, {3,4}, {5,6}};
return 0;
}
2.3.二维数组下标
当我们掌握了⼆维数组的创建和初始化,那我们怎么使⽤⼆维数组呢? 比特就业课 其实⼆维数组访问也是使⽤下标的形式的,⼆维数组是有⾏和列的,只要锁定了⾏和列就能唯⼀锁定 数组中的⼀个元素。
C/C++规定,⼆维数组的⾏是从 0 开始的,列也是从 0 开始的,如下所⽰:
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
eg
#include <iostream>
using namespace std;
int main()
{
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
cout << arr[2][4] << endl;
//输出7
return 0;
}
3. ⼆维数组的元素的访问
#include <iostream>
using namespace std;
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
//输出
//1 2 3 4 5
//2 3 4 5 6
//3 4 5 6 7
return 0;
}
4. memset设置⼆维数组
memset 是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。 下⾯演⽰两个例⼦,使⽤ memset 来设置⼆维数组的内容
#include<iostream>
#include <cstring>
using namespace std;
int main()
{
char arr[10][10];
memset(arr, 'x', sizeof(arr));
//将二维整型数组中每个字节都设置为x
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
return 0;
}
memset 在⼆维数组中的⽤法同⼀维数组,同样也需要注意避免给整型赋⾮ 0 值
三. 字符数组
数组的元素如果是字符类型,这种数组就是字符数组,字符数组可以是⼀维数组,可以是⼆维数组 (多维数组)。 接下来主要讨论⼀维的字符数组。
char arr1[5]; //二维数组
char arr2[3][5];//二维数组
C语⾔中使⽤双引号括起来⼀串字符表⽰字符串,这种⽅式虽然在C++中也是⽀持的,但是⼀般我们 会将这种字符串称为C语⾔⻛格的字符串。如果需要将⼀个C语⾔⻛格的字符串存储起来,就可以是 字符数组。
1. 字符数组的初始化
char a[10]; //字符数组的创建
字符数组的创建同⼀维数组的创建就不再赘述,但是字符串数的初始化有2种⽅式,如下:
//式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'};
2. strlen求字符串⻓度
字符数组中存放的着字符串,这个字符数组有⾃⼰的⻓度,也就是数组的元素个数,这个可以使⽤sizeof 计算,那数组中存放的字符串的⻓度是多少?怎么来计算呢?其实C/C++中有⼀个库函数 叫: strlen ,可以求字符串的⻓度,其实统计的就是字符串中 \0 之前的字符个数。 strlen 需要 的头⽂件是<cstring> 。
size_t strlen ( const char * str );
//str - 指针,存放的是字符串的起始地址,
//从这个地址开始计算字符串的长度
eg
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char arr[10] = "abcdef";
//a b c d e f \ 0 0 0 0
int n = strlen(arr);
cout << n << endl;
int sz = sizeof(arr) / sizeof(arr[0]);
// 10 1
cout << sz << endl;
//输出 6 10
}
3. 字符数组的输⼊
3.1.输⼊没有空格字符串
3.11使⽤scanf函数和字符数组来实现:
其头文件#include <cstdio>
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[10];
//输入 --abcdef
scanf("%s", arr);
//输出
printf("%s\n", arr);
//---输出abcdef
return 0;
}
3.12也可以使用cin和cout
但是他们只能使用于不带空格的字符串
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[10];
cin >> arr;
cout << arr;
//输入abcdef
//输出abcdef
return 0;
}
那如果输出带空格的字符串应该用什么呢?
scanf
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[20];
scanf("%s",arr);
printf("%s\n",arr);
//输入 abc def
//输出 abc
return 0;
}
当输⼊"abcdef"的时候,实际上scanf只读取了abc就结束了,也就是相当于遇到空格就结束了。
这⾥特别说⼀下占位符 %s ,它其实不能简单地等同于字符串。它的规则是,从当前第⼀个 ⾮空⽩字符开始读起,直到遇到空⽩字符(即空格、换⾏符、制表符等)为⽌。 因为 %s 的读取不会包含空⽩字符,所以⽆法⽤来读取多个单词,除⾮多个 这也意味着, %s ⼀起使⽤。 scanf() 不适合读取可能包含空格的字符串,⽐如书名或歌曲名。另外有⼀ 个细节注意⼀下, scanf() 遇到 %s 占位符,会在字符串变量末尾存储⼀个 \0 字符。
同时 scanf() 将字符串读⼊字符数组时,不会检测字符串是否超过了数组⻓度。所以,储存字符串 时,很可能会超过数组的边界,导致预想不到的结果。为了防⽌这种情况,使⽤ %s 占位符时,可以 指定读⼊字符串的最⻓⻓度,即写成%[m]s,其中的 [m] 是⼀个整数,表⽰读取字符串的最⼤⻓度,后⾯的字符将被丢弃。
cin cout
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[20];
cin >> arr;
cout << arr << endl;
//输入abc def
//输出abc
return 0;
}
结果也是⼀样,没有任何区别。
其实cin在读取⼀个字符串的时候,在遇到空⽩字符的时候,就认为字符串结束了,不再继续 往后读取剩余的字符,同时将已经读取到的字符串末尾加上\0,直接存储起来。
1.13.解决办法
1.14gets和fgets
char * gets ( char * str );
char * fgets ( char * str, int num, FILE * stream );
eg
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[20];
gets(arr);
cout << arr;
//输入abc edf
//输出abc edf
return 0;
}
gets是怎么运行工作的呢
gets 是从第⼀个字符开始读取,⼀直读取到 \n 停⽌,但是不会读取 \n ,也就是读取到的内容 中没有包含 \n ,但是会在读取到的内容后⾃动加上 \0 。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[10] = {0};
fgets(arr, sizeof(arr), stdin);
printf("%s\n", arr);
return 0;
}
注:即使这里标的是20个数,但fgets最多读取19个数
fgets 也是从第⼀个字符开始读取,最多读取 num-1 个字符,最后⼀个位置留给 \0 ,如果num 的⻓度是远⼤于输⼊的字符串⻓度,就会⼀直读取到 \n 停⽌,并且会读取 \n ,将 \n 作 为读取到内容的⼀部分,同时在读取到的内容后⾃动加上 \0 。
注:
在DevC++中使⽤gets函数,确实没有报错,但是在其他的IDE上,⽐如:VS2022上直接报 错,不允许使⽤gets函数。 所以在代码中还是慎⽤gets函数。
当然C语⾔中使⽤ scanf 函数其实也能做到读取带有空格的字符串,只是不常⻅⽽已。⽅式就是 将 "%s" 改成 "%[^\n]s" ,其中在 % 和 s 之间加上了 [^\n] ,意思是⼀直读取,直到遇到\n ,这样即使遇到空格也就不会结束了。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[10] = "xxxxxxxx";
scanf("%[^\n]s", arr);
printf("%s\n", arr);
//输入abc def
//输出abc def
return 0;
}
getchar
使⽤ getchar 逐个字符的读取,也是可以读取⼀个字符串的。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[20];
int ch = 0;
int i = 0;
while((ch = getchar()) != '\n')
{
arr[i] = ch;
i++;
}
arr[i] = '\0';
//必须有一个'\0',不然程序会崩
cout <<arr;
//输入abc def
//输出abc def
return 0;
}
如果不想在结尾输入'\0',也可以在开始时初始化数组
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char arr[20] ={0};
int ch = 0;
int i = 0;
while((ch = getchar()) != '\n')
{
arr[i] = ch;
i++;
}
cout <<arr;
//输入abc def
//输出abc def
return 0;
}
4. 字符数组的输出
其实前面已经使用得差不多了,总结以下
1. C语⾔中可以在 printf 函数中使⽤ %s 占位符的⽅式,打印字符数组中的字符串。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
char a[] = "hello world";
cout << a << endl;
printf("%s\n", a);
// 输出 hello world
// hello world
return 0;
}
2. C++中使⽤ cout ,可以直接打印字符数组中的字符串内容。
#include <iostream>
using namespace std;
int main()
{
char a[] = "hello world";
int i = 0;
while (a[i] != '\0')
{
cout << a[i];
i++;
}
cout << endl;
//输出 hello world
return 0;
}
3.也可以采⽤循环的⽅式逐个字符打印字符串的内容。
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char a[] = "hello world";
int i = 0;
for (i = 0; i < strlen(a); i++)
{
cout << a[i];
}
cout << endl;
//输出 hello world
return 0;
}
如果字符数组里没有'\0',不能构成字符串,又该如何打印呢?
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char arr[] = {'a','b','c','d','e','f'};
int sz = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for(i = 0;i < sz; i++)
{
cout << arr[i];
}
return 0;
}
5. strcpy和strcat
5.1.strcpy
使⽤字符数组可以存放字符串,但是字符数组能否直接赋值呢?
比如
char arr1[] = "abcdef";
char arr2[20] = {0};
arr2 = arr1;
//这样这节赋值可以吗?
就⾏整型数组中,我们说的过⼀样,这⾥也是不⾏的。那么如何将arr1中的字符串,拷⻉到arr2中呢? 其实C/C++中有⼀个库函数叫strcpy,可以完成。
char * strcpy ( char * destination, const char * source );
//destination - 是目标空间的地址
//source - 是源头空间的地址
//需要的头文件 <cstring>
eg
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
char arr1[] = "abcdef";
char arr2[20] = {0};
strcpy(arr2, arr1);
printf("%s\n", arr2);
//输出abcdef
return 0;
}
5.2.strcat
有时候我们需要在⼀个字符的末尾再追加⼀个字符串,那字符数组能直接追加吗?
⽐如:
char arr1[20] = "hello ";
char arr2[] = "world";
arr1 += arr2;//这样也是不行的
那怎么办呢?C/C++中有⼀个库函数叫 strcat,可以完成
char * strcat ( char * destination, const char * source );
//destination - 是目标空间的地址
//source - 是源头空间的地址
//需要的头文件<cstring>
eg
#include <cstdio>
#include <cstring>
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
//输出hello world
return 0;
}
除了上⾯的两个字符串相关函数外,其实C/C++中还提供了⼀些其他的函数,有兴趣的同学可以拓展学 习:https://legacy.cplusplus.com/reference/cstring/
更多推荐
所有评论(0)