1. 定义与初始化
指针实际上是地址,是一串数字;但是日常中所说的指针说的是保存地址的变量(指针变量)。本文中的指针指的是指针变量。
1.1 定义
指针的定义格式为: 数据类型 变量名;
int *p;//这里定义了一个数据类型为int的指针
1.2 初始化
在语法上,指针可以不初始化;但是实际中,建议必须初始化,以免出现无法预料的问题。如果无法给出一个确定的指向,建议置空。
int *p = NULL;//指针置空,不指向任何空间
指针初始化的格式为: 数据类型 变量名 = 一个合法的地址;
int i = 1024;
int* p = &i;//&为取地址符号,执行此步骤后,p所在的空间保存的是i的地址。
2. & 与 *
取地址操作符(&),使用方法为 &变量名 ,运算结果为该变量所在空间的地址
取值操作符(*),使用方法为 *指针变量名,运算结果为该变量指向空间中保存的内容,参与运算的必须是指针变量。
二者是相反运算
int i = 1024; //i的数据类型是int
int* p = &i;//p的数据类型是int* ,&i的数据类型是int*
int j = 512;//j的数据类型为int
*p = j;//*p的数据类型为int。
3. 指针的数据类型
3.1 字节大小
无论指针是什么数据类型,它的大小都是固定的。
在32位机中,它是四个字节,在64位机中,它是八个字节。具体查看方式如下:
printf("%d\n", sizeof(p));//p是指针的名字
3.2 数据类型的意义
指针只能指向与它数据类型相似数据的空间(这里指差 *)
int i = 20;
int* pa = &i;// int* 的指针只能指向 int数据的地址
double * pb = &i;//double* 的指针不能指向 int数据的地址
int** ppa = &pa;
原因如下:
地址指的是一个字节的编号,但是多数数据类型不只一个字节。这就造成了一个问题,【在进行*p操作时】,到底要向后偏转几个字节?
同时,整型和浮点型在内存中的存储方式也不同,在偏转后如何读取也是一个问题。
所以,指针数据类型决定的是【操作指向空间的大小和方式】
3.3 运算
1.对指针进行的加减操作,加减的是指向空间的字节数。
char* pc = (char*)1000;
pc += 1;
printf("%d\n",pc);//最终结果是1001
int* pc = (int*)1000;
pc += 1;
printf("%d\n",pc);//最终结果是1004
4. 指针与数组
1.数组名就是一个地址,并且是数组首“元素”的地址。
int arr[10] = {10};//有10个元素,每一个都是int类型
int* p =arr;//所以指针的类型为int*
printf("%d\n",*p);//结果是10
int arr[2][3] = {1,3,5,2,4,6};//有2个元素,每一个都是int[3]类型
int(*p)[3] = arr;//指针的类型是int[3]*,这里的()不能少,格式必须这样
p++;//这里加了12个字节
printf("%d\n",*(int*)p);//此时的结果是2
2.仍旧可以使用数组的方式操作指针
int arr[10] = { 10,8,7};
int* p = arr;//推导出 p == arr
printf("%d\n", p[2]);//结果是7,相当于打印arr[2]
int arr[2][3] = { 1,3,5,2,4,6 };
int(*p)[3] = arr;//推导出 p == arr
printf("%d\n", p[0][1]);//此时的结果是3
3.数组中可以保存地址
int* parr[5]={0};//定义了5个int*型的空指针。
5. 指针与函数
1.指针可以做函数的参数与返回值
void fun(int* p)
{
(*p)++;//后++的优先级大于 * ,()不能去
}
int a = 5;
fun(&a);
printf("%d\n",a);//最终结果为6
-------------------------------------------------------
int* fun(int a)
{
a++;
return &a;
}
int a = 5;
printf("%d\n",*fun(a));//最终结果为6
--------------------------------------------------------
2.函数名本身是一个地址
void fun(int a)
{
printf("this is fun\n");
}
int a = 25;
void(*p)(int) = fun;//格式:返回值类型 (*指针名)(参数类型列表)
fun(a);//调用fun
p(a);//再次调用fun