【嵌入式C语言系列】指针

指针

初始化指针变量

指针是一个值为内存地址的变量。
正如char类型变量的值是字符,int类型变量的值是整数,指针变量的值是地址。

创建指针变量,首先要声明指针变量的类型。

int *pi; // pi 是指向 int 类型变量的指针
char *str; // str 是指向 char 类型变量的指针
float *pf, *pg; // pf, pg 都是只想 float 类型变量的指针
// 定义的同时进行初始化
int a = 5; int *p = &a;
// 先定义后初始化
int a = 5; 
int *p;
p=&a;
// 把指针初始化为NULL
int *p=NULL; 
int *q=0;

类型说明符表明了指针所指向对象的类型,解引用符号*表明声明的变量是一个指针。int *pi声明的意思是pi是一个指针,*pi是int类型,如图 5.3.4 所示。
在这里插入图片描述

访问指针所指向的存储空间

  • C语言中提供了地址运算符&来表示变量的地址。其一般形式为:
 int a = 5;
 int *p = &a; 
 int b = 10; 
 p = &b; // 修改指针指向
  • &变量名;

  • C语言中提供了*来定义指针变量和访问指针变量指向的内存存储空间 在定义变量的时候 * 是一个类型说明符,说明定义的这个变量是一个指针变量

int *p=NULL; // 定义指针变量
  • 在不是定义变量的时候 *是一个操作符,代表访问指针所指向存储空间
int a = 5; 
int *p = &a; 
printf("a = %d", *p); // 访问指针变量

指针与数组

前面提到可以使用地址运算符&获取变量所在的地址,而在数组中同样可以使用取地址运算符获取数组成员中任意成员的地址,例如:

int week[7] = {1, 2, 3, 4, 5, 6, 7};
int *pw;
pw = &week[2];
printf("week is: %d", *pw);

输出的结果是:week is 3

指针与函数

形参

指针在函数中的使用最简单的是作为函数的形参,比如:

int sum(int *pdata)
{
	int i = 0;
	int temp = 0;
	for(i=0;i<10;i++) 
	{
		temp = temp + (*pdata);
		pdata++;
	}
	return temp;
}
  1. 指针pdata是作为函数的形参存在,指向一个储存int类型变量的地址;
  2. 指针pdata++,语句执行后,pdata指向的地址自增的不是1,而是int类型所占的大小,加入pdata最初的值是0,int类型占2个字节,那么pdata++;语句执行后,pdata的值就变成了2,而不是1,而*pdata的值是地址2所在的值,不是地址1所在的值;
  3. 这个函数有个危险,即函数实现的是从pdata最初指向的地址开始往后的10个int类型变量的和,假如我们这样使用:
int data[5] = {1, 2, 3, -1, -2};
int x = sum(data);

可以看到数组data的数组名即数组的首地址作为参数输入到函数sum里,而数组的大小只有5个int,函数sum计算的却是10个数的和,因而就会出现地址溢出,得不到正确的结果甚至于程序跑飞。为了避免这个问题,通常的解决方法是加一个数量形参:

int sum(int *pdata, int length)
{
	int i = 0;
	int temp = 0;
	for(i=0;i<length;i++) 
	{
		temp = temp + (*pdata);
		pdata++; }
		return temp;
	}
x = sum(data, 5);

或者给出指针范围:

int sum(int *pStart, int *pEnd)
{
	int i = 0;
	int temp = 0;
	int length = (pEnd - pStart)/2; // 假设一个 int 占 2 个字节
	
	for(i=0;i<length;i++) 
	{
		temp = temp + (*pdata);
		pdata++; }
		return temp;
	}
	x = sum(data, &data[4]);

函数指针

typedef void (*pFunction)(void);

*表明pFunction是一个指针变量,其次前面的void表示这个指针变量返回一个void
类型的值,最后括号里面的void表明这个函数指针的形参是void类型的。

函数指针调用函数:

int max(int a, int b)
{
	return ((a>b)?a:b);
}

int main(void) 
{
	int (*pfun)(int, int);
	int a=-1, b=2, c=0;
	
	pfun = max;
	c=pfun(a, b);
	printf("max: %d", c);
	return 0; 
	/// 输出结果为2
}

指针与硬件地址

指针与硬件地址的联系在volatile用法章节的例子中惊鸿一现,没有详细介绍,下面做详细说明。比如在STM32F103ZET6中内部SRAM的基地址是0x20000000,我们想对这片空间的前256个字节写入数据,就可以使用指针指向这个基地址,然后开始写:

volatile unsigned char *pData = (volatile unsigned char *)(0x20000000);

int main(void)
{
int i = 0;
for(i=0; i<256; i++) 
{
	pData[i] = i+10; 
}
return 0; 
}

指针应用的基本原则:

  • 首先必须要指定指针的类型;
  • 如果是普通指针变量,非函数形参或者函数指针,必须要给指针变量指定地址,避免成为一个“野指针”;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
宋宝华嵌入式 C/C++语言精华文章集锦 C/C+语言 struct 深层探索 ............................................................................2 C++中 extern "C"含义深层探索........................................................................7 C 语言高效编程的几招...............................................................................11 想成为嵌入式程序员应知道的 0x10 个基本问题 .........................................................15 C 语言嵌入式系统编程修炼...........................................................................22 C 语言嵌入式系统编程修炼之一:背景篇 ............................................................22 C 语言嵌入式系统编程修炼之二:软件架构篇 ........................................................24 C 语言嵌入式系统编程修炼之三:内存操作 ..........................................................30 C 语言嵌入式系统编程修炼之四:屏幕操作 ..........................................................36 C 语言嵌入式系统编程修炼之五:键盘操作 ..........................................................43 C 语言嵌入式系统编程修炼之六:性能优化 ..........................................................46 C/C++语言 void 及 void 指针深层探索 .................................................................50 C/C++语言可变参数表深层探索 .......................................................................54 C/C++数组名与指针区别深层探索 .....................................................................60 C/C++程序员应聘常见面试题深入剖析(1) ..............................................................62 C/C++程序员应聘常见面试题深入剖析(2) ..............................................................67 一道著名外企面试题的抽丝剥茧 ......................................................................74 C/C++结构体的一个高级特性――指定成员的位数 .......................................................78 C/C++中的近指令、远指针和巨指针 ...................................................................80 从两道经典试题谈 C/C++中联合体(union)的使用 ......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ................................................................83 基于 ARM 的嵌入式 Linux 移植真实体验(1)――基本概念 ...........................................83 基于 ARM 的嵌入式 Linux 移植真实体验(2)――BootLoader .........................................96 基于 ARM 的嵌入式 Linux 移植真实体验(3)――操作系统 ..........................................111 基于 ARM 的嵌入式 Linux 移植真实体验(4)――设备驱动 ..........................................120 基于 ARM 的嵌入式 Linux 移植真实体验(5)――应用实例 ..........................................135 深入浅出 Linux 设备驱动编程 .......................................................................144 1.Linux 内核模块..............................................................................144 2.字符设备驱动程序 ...........................................................................146 3.设备驱动中的并发控制 .......................................................................151 4.设备的阻塞与非阻塞操作 .....................................................................157

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值