一维数组概念
一维数组用来存放一组同类型数据,在内存中是一块连续的空间
数组创建
语法:
type arr_name[常量值];1)type:数组元素类型,char/short/int/float等2)arr_name:数组名,自定义3)[]内必须是常量,代表数组大小
4)可以用const int N = 100;定义常量,再写int arr[N];int math[20]; // const int N = 20; int math1[N]; char ch[8]; double score[10];数组初始化
用大括号
{}给数组赋初始值//完全初始化,数据依次填入数组 int arr1[5] = { 1,2,3,4,5 }; //不完全初始化,第一个元素是1,剩下自动补0 int arr2[6] = { 1 }; // 错误,初始化元素数量超过数组大小 int arr3[3] = { 1,2,3,4,5,6 }; //编译报错数组元素访问
数组下标从 0 开始
- 如果数组有n个元素,下标范围:0 ~ n-1
- 使用数组名[下标]访问元素,[]叫下标引用操作符
- 越界访问:下标小于 0 或者 >= 数组长度,编译不会报错,但运行时会出错
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; cout << arr[7] << endl; //8 cout << arr[3] << endl; //4数组和 sizeof
sizeof(数组名):得到数组总字节大小
- sizeof(数组名)/sizeof(数组[0]):计算数组元素个数
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; cout << sizeof(arr) << endl; // int占4个字节,10个元素=40个字节 cout << sizeof(arr) / sizeof(int) << endl; // // 总的字节数除以一个元素的字节数等于元素个数 40/4=10- 循环打印全部数组元素
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //循环遍历所有下标 for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { cout << arr[i] << " "; } cout << endl; //1 2 3 4 5 6 7 8 9 10范围 for(C++11)
遍历数组更简便的写法,自动获取数组每个元素,不用管理下标
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //范围 for for (auto x : arr) { cout << x << " "; } cout << endl; //1 2 3 4 5 6 7 8 9 10总结
- 数组内存连续,下标从 0 开始
- 定义数组方括号内必须是常量
- 不完全初始化,未赋值元素默认是 0
- 不能越界访问数组
sizeof(arr)/sizeof(arr[0])求数组长度- 遍历数组两种方式:普通 for 循环(按下标)、范围 for 循环
一维数组进阶
知识点:范围 for、auto、memset、memcpy
范围 for(C++11 新特性)
作用:自动遍历数组全部元素,无需手动管理下标,代码更加简洁。
只能从头到尾完整遍历,无法只遍历其中一部分。- 需要编译器开启 C++11 支持。
- 语法
for(类型 变量名 : 数组名) { //语句;多条语句加大括号 } 1)注意:这里的 e 是数组元素的副本,修改 e 不会改变原数组。int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; //范围 for for (auto e : arr) { cout << e << " "; } cout << endl; //1 2 3 4 5 6 7 8 9 10auto 关键字
- auto:让编译器自动推导变量类型,无需手动指定类型。
auto a = 3.14; auto b = 100; auto c = 'x'; cout << typeid(a).name() << endl; //double cout << typeid(b).name() << endl; //int cout << typeid(c).name() << endl; //char1)需要头文件 <typeinfo>。
memset 设置数组内容
头文件:#include <cstring>
- 函数原型:
void * memset ( void * ptr, int value, size_t num );参数说明:
1)ptr:要设置的内存起始地址
2)value:要填充的值(按字节填充)
3)num:一共填充多少个字节char str[] = "hello world"; memset(str, 'x', 6); cout << str << endl; //xxxxxxworld cout << "-------------------" << endl; int arr[] = { 1,2,3,4,5,6 }; memset(arr, 0, sizeof(arr)); //全部置0 for (auto e : arr) { cout << e << " "; } cout << endl; //0 0 0 0 0 0- memset 适合:char 数组、int 数组清 0、置 - 1
不适合给 int 数组赋值普通正数- 错误用法:想用 memset 把 int 数组全部设为 1
错误用法:想用 memset 把 int 数组全部设为 1原理:memset 是逐字节赋值
int 占 4 字节,每个字节写 0x01,最终一个 int 值变成0x01010101,
十进制是 16843009,不是 1!memcpy 拷贝数组内容
头文件:#include <cstring>
- 作用:内存拷贝,把一块内存原样复制到另一块内存
不能直接写 b = a; 拷贝数组!数组名不能直接赋值- 函数原型:
void * memcpy ( void * destination, const void * source, size_t num );参数说明:
1)destination:目标内存起始地址
2)source:源内存起始地址
3)num:拷贝多少字节int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; int b[10] = { 0 }; memcpy(b, a, sizeof(a)); for (auto e : b) { cout << e << " "; } cout << endl; //1,2,3,4,5,6,7,8,9,10a)注意:拷贝字节数,要匹配数组类型,double 数组就用sizeof(double)计算
总结
- 易错点:
1)数组不能直接b=a复制;要用 memcpy 或者循环逐个赋值
2)memset 是字节级别操作,这是竞赛高频坑点
3)范围 for 不能只遍历数组前 n 个元素,这种场景要用普通 for
题单
数组逆序存放
- 思路:
1)方法一(原地交换,推荐竞赛写法):
把数组第 i 个和第 n-1-i 个交换,只需要循环到数组中间位置
2)方法二(简单好理解):
读入数组后,从最后一个下标往前遍历输出,不需要改动数组本身- https://www.luogu.com.cn/problem/B2089
- 方法1
1)
2)
3)const int N = 105; int arr[N]; int main() { int n; cin >> n; for (int i = 0; i < n; i++) { cin >> arr[i]; } //原地逆序: i从0 到数组中间 for (int i = 0; i < n / 2; i++) { int j = n - 1 - i; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } for (int i = 0; i < n; i++) { if (i != 0) { cout << " "; } cout << arr[i]; } return 0; }- 方法2
1)const int N = 105; int arr[N]; int main() { int n = 0; cin >> n; for (int i = 0; i < n; i++) { cin >> arr[i]; } //逆序输出:从最后一个元素 i = n-1 一直到 0 for (int i = n - 1; i >= 0; i--) { if (i != n-1) { cout << " "; } cout << arr[i]; } return 0; }