记录每次学习的过程,总结学习的内容,希望能给到自己和别人帮助。
嵌入式学习-C语言-指针
指针存在的意义:间接操作内存。
指针变量的定义和使用
● 指针也是一种数据类型,指针变量也是一种变量
● 指针变量指向谁,就把谁的地址赋值给指针变量
int a =10;
int * p1 = &a;
printf("两个的地址,p1= %p,&a=%p\n",p1,&a);
//指向的内存,就是值
printf("两个的内存,*p1 =%d,a=%d\n",*p1,a);
/**
* 变量中: p1 跟 &a 同样 是存地址
* 取值中: *p1 跟 a 同样,存值
*/
const修饰指针变量
只影响指针或者指针常量,不影响a自己操作修改
使用场景:例如有些数据只能看不能修改
○ 从左往右看,跳过类型,看修饰哪个字符
■ 如果是*, 说明指针指向的内存不能改变
■ 如果是指针变量,说明指针的指向不能改变,指针的值不能修改
//当const修饰 * 的时候,p不能间接修改a的值 //const int * p = &a;
//当const修饰 p 的时候,p不能改变地址,还可以通过p来修改a的值 //int * const p = &a;
//当const都修饰的时候,p不能改变地址,也不能通过*p间接修改a的值 //const int * const p = &a
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int * p = &a;
*p = 50;
p = &b;
//当const修饰 * 的时候,*p不能间接修改a的值
const int * p1 = &a;
//*p1 = 50; //不能通过*p1间接修改a的值,编译会报错
p1 = &b;
//当const修饰 p 的时候,p不能改变地址,还可以通过*p来修改a的值
int * const p2 = &a;
*p2 = 50;
//p2 = &b;//不能改变p的地址,编译会报错
//当const都修饰的时候,p不能改变地址,也不能通过*p间接修改a的值
const int * const p3 = &a;
//*p3 = 50;//不能通过*p间接修改a的值,编译会报错
//p3 = &b;//不能改变p的地址,编译会报错
return 0;
}
指针大小
● 使用sizeof()测量指针的大小,得到的总是:4或8
● sizeof()测的是指针变量指向存储地址的大小
○ 在32位平台,所有的指针(地址)都是32位(4字节)
○ 在64位平台,所有的指针(地址)都是64位(8字节)
问题:警告,返回值和打印的占位符类型不匹配
优化方式:修改接收类型
指针步长
● 指针步长指的是通过指针进行递增或递减操作时,指针所指向的内存地址相对于当前地址的偏移量。
● 指针的步长取决于所指向的数据类型。
○ 指针加n等于指针地址加上 n 个 sizeof(type) 的长度
○ 指针减n等于指针地址减去 n 个 sizeof(type) 的长度
char 1个字节 8位
int 4个字节 32位
double 8个字节 64位
多级指针
野指针
● 指针变量也是变量,是变量就可以任意赋值
● 任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针
○ 此指针指向的区域是未知(操作系统不允许操作此指针指向的内存区域)
● 野指针不会直接引发错误,操作野指针指向的内存区域才会出问题
● 为了标志某个指针变量没有任何指向,可赋值为NULL
○ NULL是一个值为0的宏常量
指针与函数(重点)
通过传址到函数中操作可以直接修改到原先的变量值
函数参数传值
● 传值是指将参数的值拷贝一份传递给函数,函数内部对该参数的修改不会影响到原来的变量
函数参数传址
● 传址是指将参数的地址传递给函数,函数内部可以通过该地址来访问原变量,并对其进行修改。
函数指针
函数名是函数的入口地址
用变量保存这个 入口地址,就是函数指针
间接调用函数
● 函数指针:它是指针,指向函数的指针
● 函数指针变量的定义,其中返回值、形参列表需要和指向的函数匹配
返回值 (*函数指针变量)(形参列表);
例如有个函数是 void func(int a,int b){}
那么函数的指针就是 void(*p)(int,int)=func;
这时候就能使用p来间接调用func函数
回调函数(重点)
● 函数指针变量做函数参数,这个函数指针变量指向的函数就是回调函数
● 回调函数可以增加函数的通用性
○ 在不改变原函数的前提下,增加新功能
凡心所向,素履以往,生如逆旅,一苇以航。