前言
我是在B站鹏哥C语言那自学的C,每篇博客相当于对自己上课内容的复习,希望自己在大学这段时间多写博客,做到至少一周两更,如果内容有勘误欢迎指正,大家一起加油。
一、什么是指针
指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。
代码如下:
int main()
{
int a = 0;//a占4个字节
int* pa = &a;//a的地址存放在指针变量pa中
*pa = 40;//a的值变为40
return 0;
}
总结:指针就是变量,用来存放地址变量。
在32位机器中,地址是32个0或1组成二进制,地址就要用4个字节来存储,一个指针变量就应该是4个字节。
在64位机器中,一个指针变量的大小是8个字节,才能存放一个地址。
二、指针和指针类型
指针变量的声明为:typedef *var_name;
int *pi; /* 一个整型的指针 */
double *pd; /* 一个 double 型的指针 */
float *pf; /* 一个浮点型的指针 */
char *pc; /* 一个字符型的指针 */
short *ps /* 一个 short 型的指针 */
我们可以看到:char类型的指针存放的是char类型变量的地址, int类型的指针存放的是int类型变量的地址…
指针的解引用
操作符为解引用操作符,它返回指针p所指的对象的值(注意不是地址)。
1、指针类型决定了:指针解引用的权限有多大
2、指针类型决定了:指针走一步,能走多远(步长),比如char的指针解引用只能访问一个字节,而int的指针解引用就能访问四个字节。
三、野指针
野指针概念
概念:野指针就是指针指向的位置是不可知的(随机、不正确的、没有明确说明的)
野指针成因
1.指针未初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;//非法访问内存
return 0;
}
2.指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int *p = arr;
int i =0;
for (i = 0; i <= 10; i++)//只有10个元素,访问第11个元素时越界
{
*p = i;
p++;
}
return 0;
}
3.指针指向的空间释放
(动态内存分配中涉及)
如何避免野指针
1.指针初始化
2.小心越界指针
3.指针指向空间释放即使置NULL
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。
#include <stdio.h>
int main ()
{
int *ptr = NULL;//指针置NULL
printf("ptr 的地址是 %p\n", ptr );//ptr 的地址是 0x0
return 0;
}
4.指针使用之前检查有效性
5.避免返回局部变量的地址
四、指针运算
指针±整数
#include<stdio.h>
int main ()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};//定义一个有十个元素的数组
int *a = arr;//字符串名为首元素地址
int *temp =NULL;//将temp指针置NULL
int *end = arr + 9;//代表数组arr第10个元素
temp = a;//将a的地址赋给temp
while(temp <= end)
{
printf("%d ", *temp);//打印当前位置的元素
printf("%p\n", temp);//打印当前位置的地址
temp++;//指针++代表进入下一个元素的地址
}
printf("\n");//换行
temp = end;//将end的地址赋给temp
while(temp >=a)
{
printf("%d ", *temp);//打印当前位置的元素
printf("%p\n", temp);//打印当前位置的地址
temp--;//指针--代表进入上一个元素的地址
}
return 0;
}
输出结果:
总结:指针±整数实际上是指向下一个/上一个元素的地址
指针-指针
int main ()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};//定义一个有十个元素的数组
int *pa = arr;//数组名代表首元素地址
int *pb = &arr[6];//第七个元素地址
printf("%d", pb-pa);//指针相减代表中间相差几个元素
return 0;
}
指针相减代表中间相差几个元素
指针的关系运算
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
int main()
{
int v[10] = {0,1,2,3,4,5,6,7,8,9};
int *vp = NULL;
for( vp = &v[9] ; vp>&v[0];)//vp是第10个元素的地址,vp地址大于v数组首元素地址时做循环
{
*vp-- = 0;//元素赋0
}
int i = 0;
for(i = 0;i<10;i++)
{
printf("%d ",v[i]);
}
return 0;
}
结果如下:
五、指针和数组
所有的数组名都是数组首元素的地址
&数组名 - 数组名表示整个数组, 取出的是整个数组的地址
int main ()
{
int arr[10]={0,1,2,3,4,5,6,7,8,9};//定义一个有十个元素的数组
printf("%p\n",arr);//打印首元素的地址
return 0;
}
//arr[2]<==>*(arr+2)<==>*(p+2),都指向第三个元素
结果如下
六、二级指针
指针变量属于变量,只要是变量就有地址,二级指针存放一级指针的地址
int main()
{
int a = 10;
int* pa = &a;//pa是指针变量,一级指针
//ppa是二级指针
int** ppa = &pa;//pa也是个变量,&pa取出pa在内存中的起始位置
//*ppa== pa
//*pa == a
// **ppa == a
return 0;
}
七、指针数组
指针数组是多个指针变量,以数组的形式存储在内存中,占有多个指针的存储空间。
int main()
{
int a = 0;
int b = 2;
int *parr[5];//定义指针数组
parr[0] = &a;
parr[1] = &b;
printf("%p\n",parr[0]);//打印第一个元素的地址
printf("%p\n",&a);//打印a的地址
printf("%p\n",parr[1]);//打印第二个元素的地址
printf("%p\n",&b);//打印b的地址
return 0;
}
结果如下: