20.指针-指针和数组-指针和一维数组
20.1 知识点
指针和一维数组的关系
数组在内存中是连续存储的,因此我们只要利用指针获取到数组一开始的位置,就可以通过指针的自增减获取到数组中的所有信息。
建立关系
关键点:
- 指针类型需要和数组类型一致。
int array[4] = { 1, 2, 3, 4 };
int* ptr = nullptr;
获取数组一开始的位置:
方式一:数组变量名即可表示数组的首地址。
ptr = array; cout << ptr << endl; // 000000204E6FF928
方式二:获取数组第一个元素的地址。
ptr = &array[0]; cout << ptr << endl; // 000000204E6FF928
利用指针获取数组元素
首地址便是第一个元素。
cout << *ptr << endl; // 1
指针自增减可以移动元素类型占用内存空间的单位。
cout << *++ptr << endl; // 2 cout << *++ptr << endl; // 3 cout << *++ptr << endl; // 4 cout << *--ptr << endl; // 3
还可以直接加减,但是如果没有赋值或者使用
+=
、-=
的话,指针变量是不会改变的。cout << *(ptr - 1) << endl; // 2 cout << *ptr << endl; // 3
也可以直接减
n
个单位。cout << *(ptr -= 2) << endl; // 1 cout << *(ptr += 3) << endl; // 4
一定注意,不能越界,否则得到的是非期望的值。
cout << *(ptr + 1) << endl; // -858993460
普通指针指向数组,直接用
[x]
访问元素,当成数组用。数组下标访问p[x]
本质上是语法糖,它实际上等价于*(p + x)
。只要指针p
是有效的,并且指向数组或内存块,p[x]
都是合法的操作。ptr = array; cout << ptr[0] << endl; // 1 cout << ptr[1] << endl; // 2 cout << ptr[2] << endl; // 3 cout << ptr[3] << endl; // 4
ptr
和数组的区别:- 虽然指针可以像数组一样通过下标访问,但指针和数组是不同的概念:
- 数组变量本质上是一个固定的内存地址,大小和范围是固定的。
- 指针变量则是一个可以动态更改地址的变量,它的范围取决于其指向的内存。
- 注意:如果指针没有指向有效的内存(如未初始化),使用
ptr[x]
会导致未定义行为。
int* q1 = nullptr; // cout << q1[0] << endl; // 错误:未定义行为,指针未初始化指向有效内存 int* q2; q2 = (int*)malloc(sizeof(int) * 4); // 分配了数组内存 q2[0] = 10; // 合法,操作动态分配的内存 cout << q2[0] << endl; // 10 free(q2); // 使用 free 释放之前通过 malloc 分配的内存
- 虽然指针可以像数组一样通过下标访问,但指针和数组是不同的概念:
数组名当做指针变量使用
数组名不能像刚才指针一样去改变它指向的内存地址。我们只能利用它的地址来进行计算,不能改变它的指向。
cout << *array << endl; // 1
cout << *(array + 1) << endl; // 2
cout << *(array + 2) << endl; // 3
cout << *(array + 3) << endl; // 4
利用指针遍历数组
- 注意:我们无法直接通过指针获取到数组的容量,因为指针其实只是记录了一个地址而已,通过地址并不能知道数组的容量。
int* p = array;
int* p2 = array;
for (int i = 0; i < sizeof(array) / sizeof(int); i++)
{
// 以下是多种打印数组元素的方式
// 第一种 去偏移计算
cout << *(p + i) << endl;
// 第二种 去自增
cout << *p2++ << endl;
// 第三种 把数组名当成指针用,但是不能改变数组名的指向
cout << *(array + i) << endl;
// 传统方式
cout << array[i] << endl;
}
// 输出4次1234
总结
- 指针变量类型需要和数组保持一致。
- 数组名字和数组首元素的地址都可以获取到数组开始的位置(首地址)。
- 利用指针的自增自减(加减运算)可以获取到数组中不同的元素,需要注意越界问题。
- 数组名可以用来当作指针使用,但是我们不能去改变数组指向的内容(不能对数组进行重定向)。
20.2 知识点代码
Lesson20_指针_指针和一维数组.cpp
#include <iostream>
using namespace std;
int main()
{
std::cout << "指针与一维数组\n";
#pragma region 知识点一 指针和一维数组的关系
//数组在内存中是连续存储的
//因此我们只要利用指针获取到数组一开始的位置
//就可以通过指针的自增减获取到数组中的所有信息
#pragma endregion
#pragma region 知识点二 建立关系
//关键点:
//1.指针类型需要和数组类型一致
int array[4] = { 1,2,3,4 };
int* ptr = nullptr;
//2.获取数组一开始的位置
//方式一:数组变量名即可表示数组的首地址
ptr = array;
cout << ptr << endl;//000000204E6FF928
//方式二:获取数组第一个元素的地址
ptr = &array[0];
cout << ptr << endl;//000000204E6FF928
#pragma endregion
#pragma region 知识点三 利用指针获取数组元素
//首地址便是第一个元素
cout << *ptr << endl;//1
//指针自增减可以移动 元素类型占用内存空间 个单位
cout << *++ptr << endl;//2
cout << *++ptr << endl;//3
cout << *++ptr << endl;//4
cout << *--ptr << endl;//3
//还可以直接 + - 但是如果没有赋值 或者使用+= -=的话 指针变量是不会改变的
cout << *(ptr - 1) << endl;//2
cout << *ptr << endl;//3
//也可以直接减n个单位
cout << *(ptr -= 2) << endl;//1
cout << *(ptr += 3) << endl;//4
//一定注意 不能越界 否则得到的是非期望的值
cout << *(ptr + 1) << endl;//-858993460
//普通指针指向数组 直接用[x]访问元素 当成数组用
//组下标访问 p[x] 本质上是语法糖,它实际上等价于* (p + x)。只要指针 p 是有效的,并且指向数组或内存块,p[x] 都是合法的操作。
ptr = array;
cout << ptr[0] << endl;//1
cout << ptr[1] << endl;//2
cout << ptr[2] << endl;//3
cout << ptr[3] << endl;//4
//ptr 和数组的区别
//虽然指针可以像数组一样通过下标访问,但指针和数组是不同的概念:
//数组变量本质上是一个固定的内存地址,大小和范围是固定的。
//指针变量则是一个可以动态更改地址的变量,它的范围取决于其指向的内存。
//注意:如果指针没有指向有效的内存(如未初始化),使用 ptr[x] 会导致未定义行为。
int* q1 = nullptr;
//cout << q1[0] << endl;// 错误:未定义行为,指针未初始化指向有效内存
int* q2;
q2 = (int*)malloc(sizeof(int) * 4); // 分配了数组内存
q2[0] = 10; // 合法,操作动态分配的内存
cout << q2[0] << endl;//10
free(q2);//使用 free 释放之前通过 malloc 分配的内存
#pragma endregion
#pragma region 知识点四 数组名当做指针变量使用
//数组名不能像刚才指针一样 去改变它指向的内存地址
//我们只能利用它的地址来进行计算 不能改变
cout << *array << endl;//1
cout << *(array + 1) << endl;//2
cout << *(array + 2) << endl;//3
cout << *(array + 3) << endl;//4
#pragma endregion
#pragma region 知识点五 利用指针遍历数组
//注意:我们无法直接通过指针获取到数组的容量
//因为指针其实只是记录了一个地址而已,通过地址并不能知道数组容量
int* p = array;
int* p2 = array;
for (int i = 0; i < sizeof(array) / sizeof(int); i++)
{
//以下是多种打印数组元素的方式
//第一种 去偏移计算
cout << *(p + i) << endl;
//第二种 去自增
cout << *p2++ << endl;
//第三种 把数组名当成指针用 但是不能改变数组名的指向
cout << *(array + i) << endl;
//传统方式
cout << array[i] << endl;
}
//输出4次1234
#pragma endregion
#pragma region 总结
//1.指针变量类型需要和数组保持一致
//2.数组名字和数组首元素的地址 都可以获取到数组开始的位置(首地址)
//3.利用指针的自增自减(加减运算)可以获取到数组中不同的元素,需要注意越界问题
//4.数组名可以用来当作指针使用,但是我们不能去改变数组指向的内容(不能对数组进行重定向)
#pragma endregion
}
20.3 练习题
声明一个包含 5 个整数的数组 arr 并使用指针访问数组中的每一个元素,输出它们的值
int arr[5] = { 4, 5, 6, 7, 8 };
int* p = &arr[0];
int* p2 = arr;
for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
{
cout << *p++ << endl;
cout << *(p2 + i) << endl;
}
编写一个程序,使用指针遍历一个整数数组,统计数组中大于10的元素数量,并将这些大于10的元素放置到数组的前部,其余元素保持不变
注意:不能使用额外的数组
提示:使用两个指针(首尾指针)
int array[10] = { 11, 4, 5, 12, 6, 55, 3, 77, 1, 2 };
//首部地址
int* p = array; // &array[0]
//尾部地址
int* p2 = array + 9;
//用来记录有几个数大于10
int num = 0;
//没有交叉位置 才继续循环
//地址中存储的16进制数比大小
while (p < p2)
{
//头部指针指向的值大于10
if (*p > 10)
{
num++;
p++;
}
//尾部指针指向的值大于10
else if (*p2 > 10)
{
//记录一个大于10的情况
num++;
//交换首尾地址指向空间中的值
int tmp = *p;
*p = *p2;
*p2 = tmp;
//交换完毕后
//头部往尾部移动
p++;
//尾部往头部移动
p2--;
}
//尾部指针的值 小于10的 直接往前移动即可
else
{
//尾部往头部移动
p2--;
}
}
for (int i = 0; i < 10; i++)
{
cout << array[i] << ", ";
}
cout << endl;
cout << "大于10的有" << num << "个" << endl;
输出:
11, 77, 55, 12, 6, 5, 3, 4, 1, 2,
大于10的有4个
20.4 练习题代码
Lesson20_练习题.cpp
#include <iostream>
using namespace std;
int main()
{
std::cout << "指针和一维数组练习题\n";
#pragma region 练习题一
/*声明一个包含 5 个整数的数组 arr
并使用指针访问数组中的每一个元素,输出它们的值*/
//int arr[5] = { 4,5,6,7,8 };
//int* p = &arr[0];
//int* p2 = arr;
//for (int i = 0; i < sizeof(arr)/sizeof(int); i++)
//{
// cout << *p++ << endl;
// cout << *(p2 + i) << endl;
//}
#pragma endregion
#pragma region 练习题二
/*编写一个程序,使用指针遍历一个整数数组,统计数组中大于10的元素数量,
并将这些大于10的元素放置到数组的前部,其余元素保持不变
注意:不能使用额外的数组
提示:使用两个指针(首尾指针)*/
int array[10] = { 11, 4, 5, 12, 6, 55, 3, 77, 1, 2 };
//首部地址
int* p = array;//&array[0]
//尾部地址
int* p2 = array + 9;
//用来记录有几个数大于10
int num = 0;
//没有交叉位置 才继续循环
//地址中存储的16进制数比大小
while (p < p2)
{
//头部指针指向的值大于10
if (*p > 10)
{
num++;
p++;
}
//尾部指针指向的值大于10
else if(*p2 > 10)
{
//记录一个大于10的情况
num++;
//交换首尾地址指向空间中的值
int tmp = *p;
*p = *p2;
*p2 = tmp;
//交换完毕后
//头部往尾部移动
p++;
//尾部往头部移动
p2--;
}
//尾部指针的值 小于10的 直接往前移动即可
else
{
//尾部往头部移动
p2--;
}
}
for (int i = 0; i < 10; i++)
{
cout << array[i] << ", ";
}
cout << endl;
cout << "大于10的有" << num << "个" << endl;
//11, 77, 55, 12, 6, 5, 3, 4, 1, 2,
//大于10的有4个
#pragma endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com