数组是一组相同类型元素的集合
1. 数组中存放的是一个或者多个数据,但是数组元素个数不能为0
2. 数组中存放的多个数据,类型是相同的。
一、一维数组
一维数组是最常见的 , 通常用来存放一组数据 , 一维数组是一块连续的空间 。
1.1 数组创建
一维数组创建的基本语法如下:
type arr_name [常量值];
可以使用 const int N = 100 的方式定义常量 , 然后使用N来指定数组的大小 --> int arr[N]
比如:我们现在想存储某个班级的20人的数学成绩,那我们就可以创建⼀个数组,如下:
int math[20];
//或者
const int N = 20;
int math[N];
我们也可以创建其他类型和大小的数组:
但是需要注意,数组的名字需要取得有意义先 , 方便我们记住。
char ch[8];
float f[10];
1.2 数组的初始化
数组初始化 : 数组创建的时候 , 给定一些初始值
---> 数据放在大括号中
1 . int ar3[3] = { 1,2,3,4} ---> 错误初始化,初始化项太多
2 . int arr[] ---> 如果没有指定大小和初始化,编译不过去
3 . int arr[] = {1,2,3,4,5} --> 编译成功,如果有初始化,可以不用写大小,编译器会自动根据初始化的项数来决定大小。
1.3 数组元素的访问
数组是有下标的 , 下标是从 0 开始的 , 假设数组有 n 个元素 , 最后一个元素的下标是 n-1 , 下标就相当于元素的编号 , 如下:
数组的访问提供了一个操作符 [ ] , 这个操作符叫:下标引用操作符
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << arr[3] << endl; // 4
cout << arr[8] << endl; // 9
return 0;
}
有了下标访问操作符 , 我们就可以访问到数组的元素了 。 同时我们也可以修改对应数组的数据;
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
cout << arr[3] << endl; // 4
cout << arr[8] << endl; // 9
arr[3] = 100;
cout << arr[3] << endl;
return 0;
}
如果想要具体观察调试的过程 , 需要使用的VS;
1.4 数组和sizeof
1 . sizeof (数组名) , 计算的是数组的总大小 , 单位是字节
2 . sizeof(数组名)/ sizeof(第一个元素) , 计算的是数组的元素个数。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
cout << sizeof(arr) << endl;
cout << sizeof(arr) / sizeof(arr[0]) << endl;
return 0;
}
1.5 数组元素的打印
如果想打印所有元素 , 就需要产生所有元素的下标即可 --> 可以使用for循环
注意 : 如果产生的下标超出了有效下标的范围 , 比如 : 使用负数作为下标 , 或者超出了下标的最大值 , 再使用这个下标访问元素就会造成 ---> 越界访问 。 越界访问访问的时候 , 代码编译时语法虽然每报错 , 但是运行时一定会出现问题 。
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (int i = 0; i < 10; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
优化 : 如果不知道数组的大小 , 但是需要打印全部数组元素 , 可以借助sizeof
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int s = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < s; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
还可以输入数组元素 , 然后再打印 :
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 0 };
int s = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < s; i++)
{
cin >> arr[i];
}
for (int i = 0; i < s; i++)
{
cout << arr[i] << " ";
}
cout << endl;
return 0;
}
1.6 范围for语法
在VS中 , 是支持C++11 , 但是在Dev-C++中 , 默认不支持C++11
for (类型 变量名 : 数组名)
语法 //多条语句需要加大括号
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (int e : arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
1. 上面代码中的for 就是范围 for :
意思就是 将arr 数组中的元素 , 依次放在e 变量中 ,然后打印e , 直到遍历完整个数组的元素 。
2 . 这里的e 是一个单独的变量 , 不是数组的元素 , 所以对 e 的修改 , 不会影响数组 。
3 . 慎重使用范围 for , for 是对所有的元素进行遍历的 , 但是我们在实际写题的时候 , 并不需要打印所有元素 , 这时就不能使用范围 for 了
#include <iostream>
#include <cstdio>
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 << " ";
}
cout << endl;
return 0;
}
1.7 auto关键字
auto 的主要用途是让编译器自动推导出变量的类型 , 比如:
#include <iostream>
#include <cstdio>
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;
}
VS编译器更强大一些 , 鼠标放在变量面前 , 会显示出编译器自动推导出的类型:
所以我们可以修改一下上面的代码 :
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
1.7 memset 设置数组内容
memset
函数原型如下:
void * memset ( void * ptr, int value, size_t num );
memset 是用来设置内存的 , 将内存中的值以字节为单位设置想要的内容 , 需要头文件 <cstring>
设置数组内容
不要忘记包含头文件 <cstring>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
char str[] = "Hello World!";
cout << str << endl;
memset(str,'x',6);
cout << str << endl;
cout << endl;
//如果想要在第二个字符后面开始
char str2[] = "Hello World!";
cout << str2 << endl;
memset(str2+2,'x',6);
cout << str2 << endl;
return 0;
}
注意 : int 类型的数组不能直接通过 cout << arr << end 来打印 , 需要遍历数组 !
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int arr[] = {1,2,3,4,5};
for(auto e:arr)
{
cout << e << " ";
}
cout << endl;
memset(arr,0,20);//4*5=20
for(auto e:arr)
{
cout << e << " ";
}
cout << endl;
cout << endl;
//数组的大小也可以使用sizeof计算
int arr2[] = {1,2,3,4,5};
for(auto e:arr2)
{
cout << e << " ";
}
cout << endl;
memset(arr2,0,sizeof(arr2));
for(auto e:arr2)
{
cout << e << " ";
}
return 0;
}
错误使用
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int arr[] = {1,2,3,4,5};
memset(arr,1,20);
for(auto e:arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
为啥不是1 ? 为啥不是1 ? 为啥不是1 ?
因为 memset 是以字节为单位设置的 !
因为 memset 是以字节为单位设置的 !
因为 memset 是以字节为单位设置的 !
所以当value设置为 1 或者其他非0数字时候 , 打印结果不符合预期 。
原因:memset 函数是给每个字节设置value 值 , 而一个整型元素占用 4 个字节 , 一个整型的每个字节都设置为1 , 二进制就是 : 00000001000000010000000100000001 , 转化为十进制就是16843009 ;
1.8 memcpy拷贝数组内容
在使用数组的时候 , 有时候我们需要将数组 a 的内容给数组b , 比如 :
int a[10] = { 1,2,3,4,5,6,7,8,9,10};
int b[0] = { 0 };
如何做 ? 直接赋值 ?
b = a ;
不行 !!!
1 . 语法上 : 数组名是地址 , 地址是一个常量 , 常量是不可以被修改的 ( 类似3 = 5 )
2 . 逻辑上 :是需要拷贝数组的内容 , 而不是数组的地址 。
其实C++中有一个库函数 memcpy(memory copy) 可以做数组内容的拷贝 ,memcpy是用来做内存块的拷贝的 。 需要包含<cstring>头文件。
原型如下:
void * memcpy ( void * destination, const void * source, size_t num );
#include <iostream>
#include <cstdio>
#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(auto e:b)
{
cout << e << " ";
}
cout << endl;
return 0;
}
1.9 练习
练习一:查找特定的值
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 10010;
int arr[N];
int main()
{
int n;
int x;
cin >> n;
for(int i = 0;i< n ; i++)
{
cin >> arr[i];
}
cin >> x;
int i;
for(i = 0;i < n ;i++)
{
if(arr[i] == x)
{
cout << i << endl;
break;
}
}
if(i == n)
cout << -1 << endl;
return 0;
}
1 . 有的题目要求数据从下标 0 的位置开始存放 , 但有些题目是从 下标为1的位置存放 , 所以需要仔细阅读题目 , 避免越界 。
2 . 数组开辟空间需要足够 , 避免越界 。 一般题目需要 n 个空间 , 建议开辟 n + 10 个空间 ,这样空间十分充足 , 比较保险 。
3 . 一般数组比较大的时候 , 建议将数组创建成全局数组 , 因为局部的数组太大的时候 , 会导致程序无法正确运行 。全局遍历是在内存的静态区开辟空间 , 但是局部遍历是在栈区开辟空间的 , 每个程序的栈区空间是you'xian
练习二:数组逆序重存放
#include <iostream>
#include <cstdio>
using namespace std;
int arr[110];
int main()
{
int n;
cin >> n;
for(int i = 0;i< n;i++)
{
cin >> arr[i];
}
for(int i = n - 1;i>=0 ; i--)
{
cout << arr[i] << " ";
}
return 0;
}
练习三:向量点积计算
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1010;
int a[N];
int b[N];
int main()
{
int n;
cin >> n;
for(int i = 1 ;i <= n ; i++)
{
cin >> a[i];
}
for(int i = 1 ;i <= n ; i++)
{
cin >> b[i];
}
//计算
int sum = 0;
for(int i = 1 ;i <= n ; i++)
{
sum += a[i]*b[i];
}
cout << sum << endl;
return 0;
}
a数组的内容读完后 , 才读取 b 的数据 , 我们可以边读取 b 的数据 , 边计算和 , 数组b的数据不需要特地的存储 。
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1010;
int a[N];
int main()
{
int n;
cin >> n;
for(int i = 1 ;i <= n ; i++)
{
cin >> a[i];
}
//计算
int sum = 0;
int b = 0;
for(int i = 1 ;i <= n ; i++)
{
cin >> b;
sum += a[i]*b;
}
cout << sum << endl;
return 0;
}
练习四:年龄与疾病
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 110;
int arr[N];
int n1,n2,n3,n4;
int main()
{
int n;
cin >> n;
for(int i = 0;i < n;i++)
{
cin >> arr[i];
}
//统计
for(int i = 0;i < n;i++)
{
if(arr[i] >= 0 && arr[i] <= 18)
n1++;
else if(arr[i] >= 19 && arr[i] <= 35)
n2++;
else if(arr[i] >= 36 && arr[i] <= 60)
n3++;
else
n4++;
}
printf("%.2f%%\n",n1 * 1.0 / n *100);
printf("%.2f%%\n",n2 * 1.0 / n *100);
printf("%.2f%%\n",n3 * 1.0 / n *100);
printf("%.2f%%\n",n4 * 1.0 / n *100);
return 0;
}
优化 : 我们不需要特意的创建一个数组来存储病人的年龄 , 可以在每输入一个病人的年龄的时候 就立即统计 新输入病人年龄所归属的 年龄段即可 。
#include <iostream>
#include <cstdio>
using namespace std;
int n1,n2,n3,n4;
int main()
{
int n;
cin >> n;
int age;
//统计
for(int i = 0;i < n;i++)
{
cin >> age;
if(age >= 0 && age <= 18)
n1++;
else if(age >= 19 && age <= 35)
n2++;
else if(age >= 36 && age <= 60)
n3++;
else
n4++;
}
printf("%.2f%%\n",n1 * 1.0 / n *100);
printf("%.2f%%\n",n2 * 1.0 / n *100);
printf("%.2f%%\n",n3 * 1.0 / n *100);
printf("%.2f%%\n",n4 * 1.0 / n *100);
return 0;
}
练习五:开关灯
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 5010;
int arr[N] = {0};
//1 -- 开
//0 -- 关
int main()
{
int n;
cin >> n;
//i 是人的编号
for(int i = 2;i <= n ; i++)
{
int j = 0;
//j是灯的编号
for(j = i ; j <= n ; j++)
{
if(j%i == 0)
{
if(arr[j] == 0)
arr[j] = 1;
else
arr[j] = 0;
}
}
}
//输出
for(int i = 1;i <=n ; i++)
{
if(arr[i] == 0)
cout << i << " ";
}
return 0;
}
如下 , 还可以对代码进行优化 :
练习六:小鱼比可爱
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 110;
int arr[N];
int main()
{
int n;
cin >> n;
for(int i = 0;i < n ; i++)
{
cin >> arr[i];
}
// i 表示鱼的编号
for(int i = 0; i < n ; i++)
{
int c = 0;
// j 表示第 i 条鱼前面的鱼的编号
for(int j = 0;j < i ; j++)
{
if(arr[j] < arr[i])
{
c++;
}
}
cout << c << " ";
}
return 0;
}
练习七:冒泡排序
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 30;
int arr[N];
int main()
{
int n;
cin >> n;
int i = 0;
//输入数据
for(int i = 0; i < n ; i++)
{
cin >> arr[i];
}
//排序
//i 表示趟数
for(i = 0;i < n - 1 ; i++)
{
//j 表示比较次数
for(int j = 0 ; j <= n - i - 1 ; j++)
{
if(arr[j] < arr[j+1])
{
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
//打印
for(int i = 0 ; i < n ; i++)
{
cout << arr[i] << endl;
}
return 0;
}