C语言关键技术 - 指针:长处、应用场景、面试题

使用指针编程有以下长处

(1)提高程式的编译效率和执行速度。【结构体指针变量】
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。【被调函数改主调函数的值。见程序Pointer】
(3)能够实现动态的存储分配。【malloc】
(4)便于表示各种数据结构,编写高质量的程式。【静态循环队列】
(5)直接与硬件打交道的指针的存在,对内存等良好的操作性以及执行之速度快,是嵌入式开发唯有的高级语言,是嵌入式产品首选。

常见的错误

1 没有初始化NULL,指针没有指向一块合法的内存
2访问指针空间超出定义范围造成指针越界
3.
pa = arr_val[0];
pa+=1; //addr增加4
par = arr_val;
par++; //addr增加8

应用场景

结构体指针变量

通过自定义数据类型,函数指针,仍然能够实现很多类似于类的操作**【 见代码StructuretoClss】**

另外通过将数据和函数指针打包,在通过指针传递,是实现驱动层实接口切换的重要基础,有着重要的实践意义**(待看)**

结构体作用

组织对象属性、传参简洁、内存对齐提升CPU访问速度
为函数传参。比普通结构体变量效率高节约内存。问题:为什么?地址只占4字节,如果是普通变量拷贝的话就占用更大了。
问题:怎么查看一个函数的栈空间大小?

结构体封装底层硬件寄存器

基于位域,联合体,结构体,可以实现另一种位操作,这对于封装底层硬件寄存器具有重要意义
【见代码StructureToRegister(Union Bitfield) 】

回调函数

利用函数指针变量。在一般嵌入式软件的开发中并不常见,但对许多重要的实现如异步回调,驱动模块,使用函数指针就可以利用简单的方式实现很多应用。
通过函数指针实现回调:

typedef int (*pfunc)(int, int);
int func_add(int a, int b){return a+b;}
int main(void)
{
pfunc *func_ptr;
*(volatile uint32_t *)0x20001000 = 0x01a23131;
func_ptr = func_add;
printf(“%d\n”, func_ptr(1, 2));
}

强制类型转换

基于指针的强制转换,在协议解析,数据存储管理中高效快捷的解决了数据解析的问题,但是在处理过程中涉及的数据对齐,大小端,是常见且十分易错的问题,如上面arr字符数组,通过__align(4)强制定义为4字节对齐是必要的,这里可以保证后续转换成int指针访问时,不会触发非对齐访问异常,如果没有强制定义,char默认是1字节对齐的,当然这并不就是一定触发异常(由整个内存的布局决定arr的地址,也与实际使用的空间是否支持非对齐访问有关,如部分SDRAM使用非对齐访问时,会触发异常), 这就导致可能增减其它变量,就可能触发这种异常,而出异常的地方往往和添加的变量毫无关系,而且代码在某些平台运行正常,切换平台后触发异常,这种隐蔽的现象是嵌入式中很难查找解决的问题
static __align(4) char arr[8] = {0x12, 0x23, 0x34, 0x45, 0x56, 0x12, 0x24, 0x53};
ptr = (int *)&arr[4];

通过强制转换给特定的物理地址访问

利用指针强制转测试芯片的大小端模式

或者用联合体避免对指针的滥用
int data = 0x12345678;
short *pdata = (short *)&data;
if(*pdata = 0x5678)
printf(“%s\n”, “小端模式”);
else
printf(“%s\n”, “大端模式”);

typedef union
{
char c;
short s;
int i;
}UNION_VAL;
UNION_VAL val;
int main(void)
{
printf(“addr:0x%x, 0x%x, 0x%x\n”, (int)(&(val.c)), (int)(&(val.s)), (int)(&(val.i)));
val.i = 0x12345678;
if(val.s == 0x5678)
printf(“小端模式\n”);
else
printf(“大端模式\n”);
} /addr:0x407970, 0x407970, 0x407970 小端模式/
或,更容易理解的:
union U
{
char str[2];
short num;
};
Void main()
{
U u;
u.str[0] = 10;//存放在低地址,0000 1010
u.str[1] = 1;//存放在高地址, 0000 0001
cout << u.num << endl;//组合的时候,整数类型内部低地址存储低位,高地址存储高位,因此是0000 0001 0000 1010 = 266
}

指针面试题

int *p[3];
首先从P处开始,先与[]结合,因为其优先级比高,所以P是一个数组。然后再与结合,说明数组里的元素是指针类型。之后再与int结合,说明指针所指向的内容的类型是整型的,所以P是一个由返回整型数据的指针所组成的数组。
Int (*p)(int);
从P处开始,先与指针结合,说明P是一个指针。然后与()结合,说明指针指向的是一个函数。之后再与()里的int结合,说明函数有一个int型的参数,再与最外层的int结合,说明函数的返回类型是整型,所以P是一个指向有一个整型参数且返回类型为整型的函数的指针。
链接

用变量a给出下面的定义
a) 一个整型数;
b)一个指向整型数的指针;
c)一个指向指针的指针,它指向的指针是指向一个整型数;
d)一个有10个整型的数组;
e)一个有10个指针的数组,该指针是指向一个整型数;
f)一个指向有10个整型数数组的指针;
g)一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
h)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
答案:
a)int a
b)int *a;
c)int **a;
d)int a[10];
e)int *a [10];【?】
f) int a[10], *p=a;【?】
g)int (*a)(int)【?】
h) int( *a[10])(int)【?】

指针的类型

int*ptr ;//指针的类型是int /指针所指向的类型是int
int(ptr)[3]; //指针的类型是int()[3] //指针所指向的的类型是int()[3] 【 ?】
从语法的角度看,把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。

指针所指向的类型

指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待
从语法上看,把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。
在指针的算术运算中,指针所指向的类型有很大的作用。

指针的值或者叫指针所指向的内存区

在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始

指针本身所占据的内存区。

用函数sizeof(指针的类型)测一下。32位平台里,指针本身占据4个字节

  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值