指针
指针即内存地址!
指针即内存地址!
指针即内存地址!
一:内存地址(虚拟内存)
(1)程序对内存地址进行编号[0,4G] (本质上是一个整数)
(2)保存一个地址需要4字节的空间
(3)sizeof(指针) == 4
seziof(char *) == 4字节
seziof(short *) == 4字节
seziof(int *) == 4字节
seziof(float *) == 4字节
seziof(double *) == 4字节
任何指针求seziof都是4个字节
二:指针变量
如果需要保存地址,就需要有变量
变量:标识内存区域中的一个地址
指针变量:能够保存地址
- 指针变量的定义
数据类型 * 变量名;
int * p; //int * 是一个整体,表示类型为指针类型,int表示指针变量保存的是整数类型数据的地址
int *p1,p2; //p1是 int * 类型 ,p2是int类型
int *p3,*p4;//p3和p4都是 int * 类型
- 指针变量的初始化
(1)野指针:未初始化的指针变量称为 野指针(非常危险)
注意:
在编程过程中,一定要杜绝 野指针
如果对野指针取 * 运算,可能会得到意想不到的数据,也可能直接导致程序崩溃
(2)空指针:保存NULL的指针变量称为空指针
注意:
空指针不能取 * 运算
所以经常用 指针变量!=NULL 来判断是否可以进行*运算
如果定义的指针变量暂时不知道存储哪个地址,可以初始化为NULL(空指针), 代表内存0地址
一般用NULL来判断一个指针是否指向有效的内存
判断指针类型是否可以进行 * 运算:
if(指针变量 != NULL){
*指针变量
}
- 指针变量的操作
(1)对于任何变量都可以进行& (取地址运算符)
(2)对于指针变量而言,可以进行* (取值运算符)
int n = 10;
int *p = &n; //指针变量保存的是 &n ,n变量的内存地址
*p == *(&n) == n
*p = 119; //相当于 n=119;
int m = 20;
p = &m; //改变了指针变量p的值
p = xxx; //是对指针变量赋值 改变指针的指向
*p = yyy; //是对指针变量所保存的内存地址里那个内存数据的赋值
注意:连续在一起的运算符*& 和 &* 是可以相互抵消的 。
(3)[ ] 下标运算符
int arr[10];
arr[i] == *(arr+i) == *(i+arr) == i[arr]
&arr[0] == &(*(arr+0)) == &(*arr) == arr
arr[0] == *(arr+0) == *arr
数组名,代表 数组首元素的地址
&arr 和 arr ,显示的地址是一样的,但是类型不一样
int arr[10];
arr + 1; //偏移了4个字节 arr首元素的地址 每+1 偏移了一个元素的内存地址
&arr + 1; //偏移了40个字节 &arr数组的地址 每+1 偏移了整个数组的内存地
(4)+ - 指针加减法
指针 + 1 :其实是加了一个“单位”长度的字节数 单位的字节数取决于指针的类型
char * 单位: 1字节
short * 2字节
int * 4字节
float * 4字节
double * 8字节
(5)*p++ 和 (*p)++
*p++ 表达式的结果是 *p 的结果,然后 p=p+1
(*p)++ 表达式的结果是 *p 的结果,然后 *p=*p+1
(6)形参:int arr [ ] 或 int arr [n] 实际上都相当于 int *arr
void func(int arr[]){ //在函数内部获取不到数组长度,所以必须通过参数传进来
sizeof(arr) == 4
}
//数组名在传递过程中,退化为一个指针,所以数组在传递时需要传递数组的长度
(7)万能指针:void *
void的作用:
① 函数返回值类型 表示函数没有返回值
② 函数参数列表 表示函数不能接收任何参数
③ void * 万能指针
不同类型的指针之间,如果进行赋值,会报警告
任何类型的指针(地址)都可以赋值给 void * 指针变量
任何类型的指针都可以有 void * 相互转换且不报警告
- 指针的功能
C语言函数的传参方式是值传递的方式
(实参的值赋值给形参,修改形参的值并不影响实参的值)
C语言函数传递内存地址,在函数里面通过修改该内存地址里面的数据达到修改实参的目的
int n = 110; //声明一个变量 分配内存 内存中的数据为110 用n标识
int *p = &n; //声明一个指针变量 分配内存 内存中存储的数据为 变量n的地址
*p = 1; // *p 取得 *(&n) n 修改n的值为1
int m = 119;
p = &m; //修改p变量的值
*p = 9527; // *p *(&m) m 修改m的值为9527
int x = 0x12345678;
char *p = (char *)&x; // 强制转换 x的类型变为char
利用指针来交换两数的值:
//不要指针,只交换形参字节的值 根本就不影响实参
void swap_0(int a,int b){
int t = a;
a = b;
b = t;
}
//正确 交换了*pa和*pb的值 ,实参的值改变
void swap_1(int *pa,int *pb){
int t = *pa;
*pa = *pb;
*pb = t;
}
//交换了pa和pb的值 pa和pb所保存的那两个地址里面的数据没有交换过
void swap_2(int *pa,int *pb){
int *p = pa;
pa = pb;
pb = p;
}
//*p是野指针 非常危险
void swap_3(int *pa,int *pb){
int *p; // int *p = *pa; 虽然只是警告 但是意义是完全不同的
*p = *pa;
*pa = *pb;
*pb = *p;
}