一、指针简介
- 指针(Pointer)是C语言的一个重要知识点,其使用灵活、功能强大,是C语言的灵魂
- 指针与底层硬件联系紧密,使用指针可操作数据的地址,实现数据的间接访问
- 指针就是地址,通过访问此地址来获取该地址存储的数据
二、计算机存储机制
每个字节(Byte)(8位Bits)对应有自己的地址;
1、 int a = 0x123456;(一个整型是4个字节,即32位),下图中是以小端字节序跨字节存储,有关字节序内容请参考Linux系统编程-网络通信_linux系统网络通信_单行梦想家的博客-CSDN博客
2、short b = 0x5A6B;
3、char c[ ] = {0x33,0x34,0x35}; char型是一个字节;数组在内存中必须分配一个连续的线性空间;
如果要把short d[ ] = {0x5A6B,0X5B6A}存储,表示为图二,数组元素按顺序存储(0->1...),每个short按小端字节序存储
三、定义指针
- 指针即指针变量,用于存放其他数据单元(变量/数组/结构体/函数等)的首地址。
- 若指针存放了某个数据单元的首地址,则这个指针指向了这个数据单元
- 若指针存放的值是0,则这个指针为空指针
- 定义一个指针变量:
16位系统:x=2,32位系统:x=4,64位系统:x=8 (与系统位宽相等)
demo1:查看数据类型的长度(即存储大小)
#include <stdio.h>
int main()
{
int a;
int *p1;
char b;
char *p2;
printf("a:%d\n",sizeof(a));
printf("p1:%d\n",sizeof(p1));
printf("b:%d\n",sizeof(b));
printf("p2:%d\n",sizeof(p2));
return 0;
}
>>>运行结果:
a:4
p1:8
b:1
p2:8
四、指针操作
若已定义:
int a; //定义一个int型的数据
int *p; //定义一个指向int型数据的指针
则对指针p有如下操作方式:
demo2:打印char型变量a的地址
#include <stdio.h>
int main()
{
char a = 0x66;
char *p = &a;
printf("a:%x\n",a);
printf("p:%x\n",p);
printf("取内容p:%x\n",*p);
return 0;
}
>>>运行结果:
a:66
p:61fe17
取内容p:66
指针++的操作:偏移的是1个数据宽度,int*就是4个字节,char*就是1个字节,short*2个字节
demo3:指针++操作
#include <stdio.h>
int main()
{
char a;
char *p1 = &a;
int b;
int *p2 = &b;
printf("p1:%x\n",p1);
printf("p2:%x\n",p2);
p1++;
p2++;
printf("p1++:%x\n",p1);
printf("p2++:%x\n",p2);
return 0;
}
>>>运算结果:
p1:61fe0f
p2:61fe08
p1++:61fe10
p2++:61fe0c
五、数组与指针
- 数组是一些相同数据类型的变量组成的集合,其数组名即为指向该数据类型的指针。
- 数组的定义等效于申请内存、定义指针和初始化
例如:
char c[ ] = {0x33, 0x34, 0x35};
等效于: 申请内存
定义 char *c = 0x4000;
初始化数组数据
利用下标引用数组数据也等效于指针取内容
例如: c[0]; 等效于: *c;
c[1]; 等效于: *(c+1);
c[2]; 等效于: *(c+2);
demo4:数组与指针
#include <stdio.h>
#include <stdlib.h>
int main()
{
//char a[] = {0x33,0x34,0x35};//等效于以下步骤
char *a;
a=malloc(3*1);
*a=0x33;
*(a+1)=0x34;
*(a+2)=0x35;
printf("a[0]=%x\n",a[0]);
printf("a[1]=%x\n",a[1]);
printf("a[2]=%x\n",a[2]);
printf("a[0]=%x\n",*a);
printf("a[1]=%x\n",*(a+1));
printf("a[2]=%x\n",*(a+2));
return 0;
}
>>>运算结果:
a[0]=33
a[1]=34
a[2]=35
a[0]=33
a[1]=34
a[2]=35
六、注意事项
- 在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误
- 同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告
七、指针应用
传递参数
- 使用指针传递大容量的参数,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行效率,减少了内存占用
- 使用指针传递输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计
传递返回值
- 将模块内的公有部分返回,让主函数持有模块的“句柄”,便于程序对指定对象的操作
直接访问物理地址下的数据
- 访问硬件指定内存下的数据,如设备ID号等
- 将复杂格式的数据转换为字节,方便通信与存储
demo5:函数返回多个返回值,求数组中最大值以及该值出现的次数
#include <stdio.h>
void FindMaxAndCount(int *max,int *count,const int *array,int length)
{
int i;
*max=array[0];
*count=1;
for(i=1;i<length;i++)
{
if(array[i]>*max)
{
*max=array[i];
*count=1;
}
else if(array[i]==*max)
{
(*count)++;
}
}
}
int main()
{
int a[]={1,2,4,6,4,6,3};
int Max;
int Count;
FindMaxAndCount(&Max,&Count,a,7);
printf("Max=%d\n",Max);
printf("Count=%d\n",Count);
return 0;
}