指针
初始化指针变量
指针是一个值为内存地址的变量。
正如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;
}
- 指针pdata是作为函数的形参存在,指向一个储存int类型变量的地址;
- 指针pdata++,语句执行后,pdata指向的地址自增的不是1,而是int类型所占的大小,加入pdata最初的值是0,int类型占2个字节,那么pdata++;语句执行后,pdata的值就变成了2,而不是1,而*pdata的值是地址2所在的值,不是地址1所在的值;
- 这个函数有个危险,即函数实现的是从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;
}
指针应用的基本原则:
- 首先必须要指定指针的类型;
- 如果是普通指针变量,非函数形参或者函数指针,必须要给指针变量指定地址,避免成为一个“野指针”;