指针
内存地址:
声明变量 这个变量其实代表一块内存区域
操作变量 其实操作的是这片内存区域里存储的值
对于变量可以进行取址(&)运算,取得这个变量所代表的内存地址
对于取址运算符(&) 操作数只有一个,且只能是左值
%p 可以输出一个地址 地址:一个编号 一个十六进制的整数
内存地址即指针
指针变量 可以 保存 内存地址
4G虚拟内存:
参考一张图 https://blog.csdn.net/Dthinking/article/details/86309863
指针类型
数据类型 * 指针类型
数据类型 * 变量; 指针变量
指针变量 用于存储 内存地址用的
操作符 *
取值运算符
*(内存地址) 取内存地址中保存的数据
*指针变量 取指针变量保存的那个地址里面的数据
操作符 &
取地址运算符
*&x == x 相互抵销
int x = 10;
int *p = &x;
p == &x
*p == *(&x) == x == 10
*p = 100; //相当于改变了x的值
int y = 10;
p = &y; //指针变量保存了y的地址
*p = 110; //改变的是y的值
栈内存 从大往小使用
堆内存 从小往大使用
地址+1 本质上加了一个单位长度(数据类型的长度)的地址内存
地址本身虽然只是一个十六进制的整数,但其实地址自带类型
char c = ‘a’;
char *pc = &c;
short s = 30;
short *ps = &s;
指针类型 数据类型 * 是一个整体 表示的是地址的类型
char c = ‘a’;
char *pc = &c;
int x = 1;
int *px = &x;
指针变量的定义:
数据类型 * 标识符;
int iAge;
char cSex;
long lDistance;
指针变量的初始化:
int x = 1;
int *px = &x;
int *px = NULL;
NULL:
表示一个特殊的内存地址 0
这个0地址 保存的是代码
代码区的数据只读
一般来说指针初始化都为NULL
野指针:
一个指针变量没有初始化 指针里面的值为垃圾值 因为存储在指针变量里
所以看作一个内存地址
如果对该指针进行取*操作,将发生难以预测的后果 (灾难性的)
所以在编程过程中一定要避免野指针
悬空指针:
NULL
对于悬空指针不能进行取操作,一旦取,必然是核心已转储 段错误
所以一般在对指针进行取*操作前,都要对指针进行悬空判断
if(p != NULL){
*p
}
& (单目运算符)取址运算符 要求 &左值
取得变量的地址
(双目运算符)按位与
*取值运算符
指针的应用
1.作为函数的参数
2.作为函数的返回值(静态局部变量 全局变量 形参的值(指针))
注意:函数中不能返回局部变量的地址 因为局部变量地址在函数调用之后会被回收
void * : 万能指针
万能指针变量 可以 保存任何类型的内存地址
注意: void *指针 不能 进行 取 * 操作
指针和数组:
数组名是数组元素的首地址
数组中第一个元素的地址
数组在作为函数的参数传递时,其实是传递的是数组元素的首地址
在函数中,数组名已经退化成一个指针
[]下标运算符:
arr[i] == *(arr+i)
数组下标为什么从0开始? 因为第一个元素的偏移量为0
数组名: 是一个不可以修改的"指针" 数组名不能作为左值
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;
*p++ ==> 先取 *p 然后再 p++
(*p)++ ==> 先取 *p 然后把这个值再增加1
在函数的形参列表中: int arr[10] arr不是数组 本质上是 int *arr