5.1 指针定义
指针就是地址。
注意:
1. 指针是内存中一个最小单元的编号,也就是地址,一个内存单元为一个字节。
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。
5.1.1 指针变量
我们可以通过&(取地址操作符)取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量。
注意:
1. 指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
2. 指针变量是用来存放地址的,地址是唯一标示一块地址空间的。
3. 指针的大小在32位平台(X86)是4个字节,在64位平台(X64)是8个字节。
int main()
{
int a = 10;//在内存中开辟一块空间,a是整型变量,占用4个字节空间
int* p = &a;//这里我们对变量a,取出它的地址(取得是首地址),可以使用&操作符。
//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量中,p就是一个之指针变量。
return 0;
}
5.2 指针和指针类型
指针类型:指针的定义方式是:type + *。 int* p: *说明p是指针,int说明p指向的对象是int类型;p是指针变量,p的类型是int*。
char *pc; int *pi; short *; long *; float *; double *;
注意:
1. 不管什么类型,指针大小是一样的。指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如:char* 的指针解引用就只能访问一个字节,而int* 的指针的解引用就能访问四个字节。
int main()
{
//0 1 2 3 4 5 6 7 8 9 a b c d e f
//11111111
// 8421
int a = 0x11223344;
char* pc = &a;
*pc = 0;//char类型,*pc把&a内的第一个字节改为0
int* pa = &a;
*pa = 0;//int类型,*pa把&a内的第1-4个字节改为0
return 0;
}
2. 指针的类型决定了指针向前或者向后走一步有多大距离(指针+1、-1操作时跳过的几个字节)。
int main()
{
int arr[10] = { 0 };
int *p = arr;
char *pc = arr;
printf("%p\n", p);//p=006FF9F8
printf("%p\n", p+1);//P+1=006FF9FC
printf("%p\n", pc);//PC=006FF9F8
printf("%p\n", pc+1);//006FF9F9
return 0;
}
5.3 野指针
野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。
产生野指针的原因:
1. 指针未初始化
2. 指针越界访问
3. 指针指向的空间释放
//野指针:
//1.指针未初始化
int main()
{
//这里的p就是一个野指针
int* p;//p是一个局部的指针变量,局部变量不初始化的话,默认是随机值
*p = 20;//非法访问内存了
return 0;
}
//2.越界访问
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 10; i++)
{
*p = i;
p++;
}
return 0;
}
//3. 指针指向的空间释放
int* test()
{
int a = 10;
return &a;
}
int main()
{
int*p = test();
*p = 20;
return 0;
}
避免野指针:
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放及时置NULL //int *p=NULL;空指针
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
//避免野指针:
int main()
{
//知道p就直接初始化赋值;当前不知道p应该初始化为什么地址的时候,直接初始化为NULL
int* p = NULL;
if(p != NULL) //这样使用p
*p = 10;
return 0;
}
5.4 指针运算
1. 指针+ - 整数
//1.指针+ - 整数
int main()
{
int arr[10] = { 0 };
int i = 0;
int j = sizeof(arr) / sizeof(arr[0]);
int* vp = arr;
for (i=0;i<j;i++)
{
*vp = i+1;
vp++ ;//*vp++ =1 <=> *vp=1 -> vp++
printf("%d ", arr[i]);//1 2 3 4 5 6 7 8 9 10
}
return 0;
}
2. 指针-指针:|指针-指针| 得到的是指针和指针之间元素的个数
注意:指向同一块空间的2个指针才能相减!
指针+指针无意义。
//2.指针-指针
int main()
{
int arr[10] = { 0 };
printf("%d\n", &arr[9] - &arr[1]);//8
return 0;
}
3. 指针的关系运算
注意:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
//3. 指针的关系运算
int main()
{
int arr[10] = { 0 };
int i = 0;
int j = sizeof(arr) / sizeof(arr[0]);
int* vp = arr;
for (vp = &arr[j - 1]; vp >= &arr[0]; vp--)
{
*vp = 1;
}
for (i = 0; i < j; i++)
{
printf("%d ", arr[i]);//1 1 1 1 1 1 1 1 1 1
}
}
5.5 指针与数组
数组:一组相同类型元素的集合
指针变量:是一个变量,存放地址,可以通过指针存放数组首元素的地址来访问数组。
int arr[10]={0};
int* p = arr; / / arr[i] = *(arr+i) = *(p+i)
/ / *arr=arr[]
int main()
{
int arr[10] = { 0 };
//arr=&arr[0] 是首元素的地址
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p+i));//通过指针来访问数组;*(p+i)=arr[i]=*(arr+i)
}
return 0;
}
5.6 二级指针
一级指针:
int* p: *说明p是指针,int说明p指向的对象是int类型;p是指针变量,p的类型是int*。
二级指针:用来存放一级指针变量的地址。
int** sp:*说明p是指针,int* 是说明sp指向的对象是int* 类型。
//二级指针:
int main()
{
int a = 10;
int* pa = &a;//pa是指针变量,一级指针
int** ppa = &pa;//ppa就是一个二级指针变量;pa也是个变量,&pa取出pa在内存中起始地址
int*** pppa = &ppa;//三级指针
**ppa = 20;
printf("%d", a);//a=20
return 0;
}
5.7 指针数组
指针数组是存放指针的数组
//指针数组:
int main()
{
int a = 0;
int b = 1;
int c = 2;
int d = 3;
int e = 4;
int* pa[5] = { &a,&b,&c,&d,&e };//pa指针数组:存放指针的数组
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", *(pa[i]));//0 1 2 3 4
}
return 0;
}