7 指针
7.1 指针基本概念
作用:可以通过指针间接访问内存。(简单来书指针就是一个地址)
内存编号是从0开始记录的,一般用十六进制数字表示。
可以利用指针变量保存地址。
7.2 指针变量定义和引用
指针变量定义:数据类型 * 指针变量名;
指针变量,存放的是地址。&变量名是取变量的内存地址。*指针变量名是取指针变量对应的内存中的数据。
#include <iostream>
using namespace std;
int main( )
{
//1.定义一个指针
int a = 10;
//指针定义语法:数据类型 * 指针变量名;
int * p;//创建指针变量
//让指针记录变量a的地址
p = &a;
cout << "a的地址为:" << &a << endl;
cout << "p的值为:" << p << endl;
//2.使用指针
//可以通过解引用的方式来找到指针指向的内存
//指针前加*代表解引用,找到指针指向的内存中的数据
*p = 100;//找到指针指向的内存中的数据
cout << "*p的值为" << *p << endl;
cout << "a的值" << a << endl;
}
7.3 指针所占内存空间
指针也是数据类型,那么这种数据类型占多少内存空间呢?
在32位操作系统下,不管是什么类型的指针,都是占四个字节的空间
在64为操作系统下,不管是什么类型的指针,都是占八个字节的空间
#include <iostream>
using namespace std;
int main()
{
//指针所占内存空间
//1.创建指针
int a = 10;//创建变量
int* p;//创建指针变量
p = &a;//指针和变量建立关系
//int *p=&a;
//2.查看指针变量所占内存空间大小:
//在32为操作系统下,指针都是占4个字节空间大小
//在64位操作系统下,指针都是占8个字节空间大小
cout << "sizeof(p):" << sizeof(p) << endl;//sizeof(数据类型或变量名)查看内存空间
cout << "sizeof(int *):" << sizeof(int *) << endl;
cout << "sizeof(float *):" << sizeof(float *) << endl;
cout << "sizeof(double *):" << sizeof(double *) << endl;
cout << "sizeof(char *):" << sizeof(char *) << endl;
}
7.4 空指针和野指针
7.4.1 空指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的。0-255之间的内存编号是系统占用的,不可以访问。
#include <iostream>
using namespace std;
int main()
{
//空指针
//1.空指针用于给指针变量初始化
int * p = NULL;//创建空指针
//2.空指针是不可以进行访问的:0-255之间的内存编号是系统占用的,不可以访问
//*p = 100;
cout << sizeof(p);
}
7.4.2 野指针
野指针:指针变量指向非法的内存空间
#include <iostream>
using namespace std;
int main()
{
//野指针
//在程序中,尽量避免出现野指针
int* p = (int *)0x1100;//强转为指针类型
//访问野指针报错
cout << *p;
}
空指针和野指针都不是我们申请的空间,因此不要访问
7.5 const修饰指针
const修饰指针有三种情况:
(1)const修饰指针——常量指针
例const int *p=&a;
特点:指针的指向可以修改,但是指针指向的变量的值不可以修改
int a=10;
int b=20;
const int *p=&a;
*p=20;//错误:指针指向的值不可以修改
p=&b;//正确:指针的指向可以修改
(2)const修饰常量——指针常量
例 int * const p=&a;
特点:指针的指向不可以修改,但是指针指向的变量的值可以修改
int a=10;
int b=20;
int * const p=&a;
*p=20;//正确:指针指向的值可以修改
p=&b;//错误:指针的指向不可以修改
(3)const既修饰指针又修饰常量
例 const int * const p=&a;
特点:指针的指向不可以修改,指针指向的变量的值不可以修改
int a=10;
int b=20;
int * const p=&a;
*p=20;//错误:指针指向的值不可以修改
p=&b;//错误:指针的指向不可以修改
举例:
#include <iostream>
using namespace std;
int main()
{
//const修饰的指针
int a = 10;
int b = 20;
//1.const修饰指针——常量指针:常量指针的指向可以改变,但是指针指向的数据不可以改变
const int* p1 = &a;
//*p = 100;//常量指针指向的数据不可以修改
p1 = &b;//常量指针的指向可以修改
//2.const修饰常量——指针常量:指针常量的指向不可以修改,但指针指向的数据可以修改
int* const p2 = &a;
*p2 = 100;//指针常量指向的数据可以修改
//p2 = &b;//指针常量的指向不可以修改
//3.const修饰指针和常量:指针指向的数据和指针的指向都不可以修改
}
7.6 指针和数组
作用:利用指针访问数组中元素
#include <iostream>
using namespace std;
int main()
{
//指针和数组
//1.利用指针访问数组中的元素
int arr1[] = { 1,7,4,2,8,6 };
cout << "利用数组下标访问数组中第一个元素为:" << arr1[0] << endl;//利用数组下标访问数组中的元素
int* p = arr1;//arr1为数组的首地址
cout << "利用指针访问数组中第一个元素:" << *p << endl;
p++;//让指针向后偏移四个字节(因为本身创建的是int类型的指针(4字节))
cout << "利用指针访问数组中第二个元素:" << *p << endl;
//2.利用指针遍历数组
double arr2[] = { 1.0, 2.5, 6.4, 2.4 };
double * p2 = arr2;
for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
cout << "数组arr2中的元素" << *p2 <<endl;
p2++;
}
}
7.7 指针和函数
作用:利用指针作为函数参数,可以修改实参的值
#include <iostream>
using namespace std;
void swap1(int p, int q)
{
int temp = p;
p = q;
q = temp;
}
void swap2(int *p, int *q)
{
int temp = *p;
*p = *q;
*q = temp;
}
int main()
{
//指针和函数
//1.值传递:函数中不能修改实参的值
int a = 10;
int b = 20;
swap1(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
//2.地址传递:函数体中可以修改实参的值
int a2 = 10;
int b2 = 20;
swap2(&a2, &b2);
cout << "a=" << a2 << endl;
cout << "b=" << b2 << endl;
}
7.8 指针、数组、函数
案例描述:封装一个函数,利用冒泡排序实现对整型数组的升序排序
#include <iostream>
using namespace std;
//封装一个函数,利用冒泡排序实现对整型数组的升序排序
void bubblesort(int *q,int len)//参数为数组的首地址
{
//排序结束地址
for (int i = 0; i < len; i++)//排序次数
{
int* p = q;
for (int j = 0; j < len - i-1; j++)
{
if (*p > * (p + 1))
{
int temp = *p;
*p = *(p + 1);
*(p + 1) = temp;
}
p++;
}
}
}
int main()
{
//创建数组
int arr[] = { 1,8,9,5,3,6,7,4 };
int len = sizeof(arr) / sizeof(arr[0]);
bubblesort(arr,len);
for (int i = 0; i<len; i++)
{
cout << arr[i] << endl;
}
}