C语言马拉松_04.1
指针类型
C语言中最重要的就是指针类型,尤其对于经常需要跟单片机、寄存器等打交道的人来说尤为重要。因为通过指针的操作可以非常便捷的与底层的寄存器进行沟通。
指针的初级阶段主要是理解指针的功用。
指针是一个存储着目标对象的地址值的一个特殊变量,实质上它也是一个数值,而这个数值所代表的是这个指针所指向的对象的地址编号。
还记得最开始的格子吗?我们从第一个格子为0开始一次编号,这个编号实际上就是地址值,而这个值被保存在指针变量中。
指针与数组
有了这个基础认识我们就不难理解指针了,我们进一步解释数组与指针之间的联系。
我们知道数组名称其实就是数组的首地址值,实际上,数据是一片固定大小的存储区域,我们可以按照以下形式理解数组:
声明数组:
<数组类型> <数组名称-地址偏移>[存储区域大小]
例子:
char base_addr[8];
我们声明一个数组的时候可以这样来理解,首先,char是数据类型,代表这片存储区域是用来存储char类型的数据的;然后,base_addr是这片区域的首地址例如说:0x40000040,也就是说这个数组从0x40000040这个地址开始存储数据;再者,方括号中的数值则是这片存储区域的数量,我们知道sizeof(char) = 1,那么这么存储区域的大小就是 8 * 1 = 8bytes。通过上述内容就可以知道,这片存储区域从0x40000040开始,到0x40000048结束。
接下来通过这些信息我们就可以唯一的去访问这片存储区域。我们通过一段程序来查看
#include <stdio.h>
int main()
{
char base_addr[8]; // 定义一个数组
int i = 0;
for(i = 0; i < 8; i++) // 循环打印出每个元素的地址
{
printf("0x%08x\r\n", &base_addr[i]);
}
return 0;
}
通过观察上述程序的运行结构我们可以发现,数组的地址逐一递增,请修改程序,将数组类型改为int, long等类型,然后观察输出结果,仔细思考结果变化的原因。
指针与数组的关系:
我们通过一个例子来说明指针与数组之间的联系。
#include <stdio.h>
int main()
{
char base_addr[8]; // 定义一个数组
char *pbase_addr = base_addr; // 定义一个指向数组首地址的指针变量
printf("base_addr : 0x%08x\r\n", base_addr);
printf("&base_addr[0]: 0x%08x\r\n", &base_addr[0]);
printf("pbase_addr : 0x%08x\r\n", pbase_addr);
return 0;
}
通过上边的程序我们可以看出来,这三者有着相同的值:
通过1, 2的对比我们可以知道数组名称就是数组的首地址
通过1, 3对比我们可以知道数组名称是一个特殊的指针
通过上边的实验我们可以知道,我们可以通过指针去访问数组元素,理解如下代码:
#include <stdio.h>
int main()
{
char base_addr[8]; // 定义一个数组
char *pbase_addr = base_addr;
int i = 0;
// 给base_addr中的元素赋值
printf("base_addr中的值:\r\n");
for(i = 0; i < 8; i++)
{
base_addr[i] = 2 * i;
printf("%d\t", *pbase_addr);
}
printf("\r\n");
printf("pbase_addr取到的值:\r\n");
// 循环打印出每个元素的地址
for(i = 0; i < 8; i++)
{
printf("%d\t", *pbase_addr);
pbase_addr++;
}
printf("\r\n");
return 0;
}
请仔细思考地址与变量之间的关系。
tips
在刚开始接触指针的时候很令人费解的就是“*”这个符号,不知道该怎么使用,在这里一次性说明白:
在C语言中“*”这个运算符只有在定义指针变量的时候是用来说明这个变量是个指针,在其它情况下不在具有这个含义。
当已经声明了一个变量为指针的时候,在这个变量之前使用“*”操作符的含义是从这个指针变量的地址中取出所保存的数据值。
当然“*”还有一个最常用的作用就是作为乘法运算符。
请仔细领会“*”在不同情况下的含义。