目录
前言
在计算机中,所有的数据都是存放在存储器中的,一般把存储器的一个字节称为一个内存单元。不同的数据类型占用的内存单元是不同的。为了快速、准确的访问这些内存单元,计算机为每一个内存单元进行编号,内存单元的编号也就是内存单元的地址。C 语言中,把这个地址叫做指针。
1:指针的定义
指针的定义:指针是一种数据类型,基于该类型声明的变量称为指针变量,该变量存放的是内存中的某个地址,
指针的声明:类型 * 指针变量名;//如 int * pNum;“*”表示语句声明的是一个指针变量,类型指定了指针所指的内存单元的数据类型。可以将int*理解成一种复合类型,是指向 int 型数据的指针。
指针的初始化:声明指针变量时,C 并不会自动对其进行初始化,我们通过取地址符(&)给指针变量赋值是个有效的手段,实际上,可以在声明一个指针变量的同时完成其初始化。例如:int num=1; int *pN=#对于无处可指的指针变量,也要将其初始化为 NULL(即 0,空指针)。如:int *pa = NULL;
指针的引用:两个有关的运算符:
1) &:取地址运算符。
2) *:指针运算符(或称“间接访问” 运算符)。
C语言中提供了地址运算符&来表示变量的地址。其一般形式为:&变量名;如&a 表示变量 a 的地址,&b 表示变量 b 的地址。变量本身必须预先说明。
2:指针变量
既然&iNum是指向变量iNum的指针,那么存放指针&iNum的变量就是“指针变量”。从根本上来看,指针变量是一个值为内存地址的变量。如果有以下定义:
int iNum=0x64;
int *ptr =&iNum;
其中,“*”将变量声明为指针,这是一个重载过的符号。显然,重载就是为某个操作符定义新的含义,因为*用于乘法和间接访问或解引用指针时,其意义完全不一样。
iNum变量设置为0x64,在声明ptr的同时将它初始化为iNum的地址。当声明一个指针时,仅仅只是为指针本身分配了空间,并没有为指针所引用的数据分配空间。通常该声明被解读为ptr是指向int的变量iNum的指针,“int*”类型名被解读为指向int的变量iNum的指针类型。虽然ptr与&um的值相等,但它们的类型不一样。ptr的类型为int*,&iNum的类型为int*const即&iNum是一个指向非常量的常量指针,虽然指针不可变,但它所指向的数据可变。比如:
int iNum =0x64;
int const ptr=&iNum;
有了这个声明,则ptr必须被初始化为指向非常量变量,虽然不能修改ptr,但可以修改ptr指向的数据。如果试图初始化ptr使其指向常量Num,则ptr就成为了一个指向常量的指针,即不能通过指针修改它所引用的值。比如:
const int iNum =0x64;
int * const ptr = &iNum;
这样的话就会出现一个警告,因为常量不能被修改
虽然指针&iNum是指内存地址本身,指针变量ptr是指存储内存地址的变量,但两者之间的区别并不重要。因为传递一个指针变量给函数,其实就是在传递该指针的值一—内存地
址。通常在讨论一个内存地址时,将它称为地址;而在讨论一个存储内存地址的变量时,才会将它称为指针。当一个变量存储另一个变量的地址时,通常会说它指向了某个变量。
2.1:const关键字
无论怎样, const修饰的是紧跟在它后面的单词。比如,使用“const int a[2]={5,2};是将数组a的元素修饰为只读(它的值保持不变),而不是将变量a修饰为只读。注意,int const与 const int是等价的。既然可以用 const修饰变量,当然也可以用 const修饰指针变量。比如,“char* const src”是将src自身修饰为只读,而“const char* const src”是src和src指向的对象(变量的值)都修饰为只读。此外还有 const char*sc和 char const*src,其效果是一样的。注意,当指针作为传递参数时, const常用于将指针指向的对象设定为只读。注意,只读变量与指令一起保存在“只读段”中,而变量保存在“读写段”中。具有存储器保护功能的操作系统可能将只读段保护起来,不让程序修改值。类似 Cortex--M0+这样的MCU,其只读段与读写段是分别分配在 Flash与RAM中的,因此无法改变只读变量的值。由于 Flash比RAM便宜很多,且容量大很多,因此建议尽量将变量定义为只读变量,以达到节省存储空间的目的。
3:指针的指针
有如下定义:
int iNum =0x64;
int *ptr =&iNum;
当在“int*ptr;”定义前添加 typedef:
typedef int *ptr;
此时,ptr等同于int*。为了便于理解,通常将类型名ptr替换为ptiT比如:
typedef int *PTR_INT;
显然有了 PTR INT类型,即可构造指向 PTR INT类型的指针变量pPtr.即
PTR_INT *pPtr=&ptr;
其中,pPtr是指向PTRNT*的指针变量,PTR_INT的类型为int*,pPtr是指向int**的指针变量,那么pPtr就成了保存int型ptr地址的双重指针
其中,指针的类型为int**,指针指向的对象的类型为int*,只要看到*就应该想到指针变量。由于*的结合方式是从右到左的,该定义相当于:
int * *pPtr)=&ptr;
即*pPtr是一个一级指针变量。接着第一个*与(*ptr)结合成为“一级指针变量”,这同样是在定义一个指向指针类型数据的指针变量,即二级指针变量。在双重指针变量前,既可加一个或两个指针运算符*,也可以加取地址运算符&。则以
下关系恒成立:
*pPtr ==*(&ptr) == ptr == &iNum
**pPtr == *ptr == *(&iNum) == iNum