什么是指针?
- 一个内存变量或数组变量在内存中的地址就是指针。
- 简单来说,内存地址就是指针,指针就是内存地址
- 存放指针(内存地址)的变量就称为指针变量。
- 在32位操作系统中,任何类型的指针变量的空间大小都是4个字节。在64位操作系统中,任何类型的指针变量的空间大小都是8个字节。
- 指针变量记录的内存地址,也称为他指向的地址。
指针变量的定义方法
格式:变量类型 * 指针变量名称=[ ]
*
符号两旁都没有空格或者左边或右边有一个空格都是可以的。
&
:取地址,获取一个变量的地址
*
:取值
- 指针变量自身的大小全部都是4个字节,跟类型毫无关系;
- 对目标操作的大小跟类型完全相关;
*p = -1; //(此处操作4个字节)代替普通变量赋值:i= -1;
*ps = -1; //(此处操作2个字节)代替普通变量赋值:j= -1;
*pd = 0; //(此处操作8个字节)代替普通变量赋值:d = 0;
*p
等价于是4字节变量i
的别名,*ps
等价于2字节变量j
的别名,
int a[] = {1,2,3,4,5,6,7,8,9,0};
int i = -1;
int *p = a;
while(++i < _countof(a))
printf("%d",*(p+i)); //i:0...8
//p[i]等价于*(p+i) 加1就向高平移1个int,如果是double*的变量加1就平移一个double
- 指针变量的步长:
- 对目标读和写是跟类型相关,
double
操作8个字节,int操作4个字节; - 指针加减也和类型相关,
double*
的变量加减1跨越一个double
的距离,int*
和cha*
同理。 - 我们把指针变量对目标操作或加减称为步长
- 对目标读和写是跟类型相关,
- 指针变量的赋值原则:
- 右值必须是指针变量或者指针常量,而不可以是一个整数或者浮点数。例如:
int main(){
//&n指针常量,p是指针变量
int n=0,a[20]; //数组可以认为是指针常量
int *p = 888; //错误, 数值型与地址型不能交互赋值
int *p = &n;//使用指针常量赋值
int* q = p; //使用指针变量赋值
int* p = 0; //正确,经常利用到空地址对指针变量初始化
}
指针变量的等级
指针变量今后分为一级指针和二级以及多级指针变量。
int n = 999;//0级
int *p = &n;//&代表升级,p是一级指针变量;
int ** pp = &p;//&代表升级,p是二级指针变量;
*p = 666;//*代表降级
指针的偏移(加减)
p+n
的地址偏移与指针变量的类型有关:- 若
x
是double
或者int
型,偏移的物理距离就是sizeof(x)*n
- 如果是
char*
类型,p+n偏移的物理距离是n个字节; - 如果是
short*
类型,p+n偏移的物理距离是n*2
个字节; - 如果是
int*
类型,p+n偏移的物理距离是n*4
个字节; - 如果是
double*
类型,p+n偏移的物理距离是n*8
个字节;
- 若
p+n
与p[n]
才是等价的,因为p[n]
的地址与p
指向的地址之间也是相差n
的sizeof(x)
倍;
特殊类型的指针变量
C语言中,特殊类型的指针变量包括:常量指针、指针常量和万能指针等几种类型。
无论是指针常量还是常量指针,const
关键字都是编译时禁止修改的意思。只不过一个是禁止修改记录的地址,一个禁止修改指向的内存中的数据。
常量指针
指向常量的指针变量,例如:const int* p;
**常量指针的特点:
- 常量指针的核心功能,是阻止修改指针向内存的数值。
- 常量指针的特点:禁止对目标数据赋值操作,允许读取操作,允许偏移操作。
指针常量
指针变量中的常量”,例如:int* const p;
**指针常量的特点:
- 指针常量:指向固定的位置的指针变量,格式是
const
在指针变量前星号后。 - 禁止偏移操作,允许对数据赋值操作和读取操作。
*p
和p[0]
的类型是int类型,而不是const int
类型。- 指针常量必须初始化。
万能指针
只记录地址不记录类型的指针变量,也可称之为“无类型指针”。例如:void* p;
**万能指针的特点:
- 定义万能指针的格式为:
void* 变量名;
*p
和p[0]
的类型是未知类型,禁止赋值与取值。- 禁止对目标数据赋值操作和读取操作,允许指向任何新地址,但禁止自增自减。
double d = 10;
p=&d; //编译正确
++p; //编译错误
- 如果要对万能指针指向的内存操作,必须先强制转化为一种具体类型。
double *pd = (double*)p;
*pd=9999.9999;
万能指针最常用于做形式参数,功能是对任何类型的实参都可以自动匹配。
测试万能指针
#include<stdio.h>
int main()
{
int n = 10;
double d = 9999.9999;
char s[]= "abcdefg";
void *p = NULL;
p = &n; //正确:万能指针能接收任何类型的地址
//*p = -1; 错误:万能指针能皆不能取值也不能赋值
p = &d; //正确:万能指针能接收任何类型的地址
//p[0] = 0; 错误:万能指针能皆不能取值也不能赋值
p = s; //正确:万能指针能接收任何类型的地址
//p++; 错误:万能指针无法加减,因为没有单位长度
//printf("%d", sizeof(*p)); 错误:*p是未知的类型
return 0;
}