指针 初阶

本文详细介绍了C语言中的指针概念,包括指针作为内存地址、指针变量的初始化和解引用、不同类型的指针以及指针运算。讨论了野指针的成因及如何避免,还涉及到了二级指针和指针数组的使用。通过对指针的深入理解,有助于更好地掌握C语言的内存管理和程序设计。
摘要由CSDN通过智能技术生成

目录

一、什么是指针

二、指针和指针类型

三、野指针

四、指针运算

五、指针和数组

六、二级指针

七、指针数组


一、什么是指针

指针是内存中一个最小单元的编号,也就是地址。 平时口语中所说的指针是指针变量,用来存放内存地址的变量。

总结:指针就是地址,口语中的指针是指针变量,指针变量是用来存放地址的。指针的大小在32位平台上是4个字节,在64位平台上是8个字节。

 

 

int main()
{
   int a=19;
   int* pa=&a;
   *pa=20;
   printf("%d\n",a);
}

 打印结果为:20

a是一个变量,里面假设存储了数字19,则,&a获取了a的首地址,即位006FF9F8,pa是指针变量,它用来存放&a存放的地址006FF9F8。

代码中:int* pa=&a,&a意思是取a的地址,pa存储了a的地址,而int*的意思是,*表示pa是指针,int表示pa指针所指的对象a的类型是int型。

二、指针和指针类型

1.1 指针的解引用

int main()
{
   int a=0x11223344;
   //a是十六进制位数字
   char* pa=(char*)&a;
   *pa=0;
}

a是整型,但指针变量却用了char类型,(char*)强制转换,也可实现运行。

但是在解引用*pa=0;时,因为是char类型所以,只访问一个字节。

结论:指针类型决定了指针在被解引用的时候访问几个字节。

如果是int*类型的指针,解引用访问4个字节

如果是char*类型的指针,解引用访问1个字节

如果是double*类型的指针,解引用访问8个字节。

1.2 指针+-整数

int main()
{
   int a=0X11223344;
   int* pa=&a;
   char* pc=&a;
   printf("pa=%p\n",pa);
   printf("pa+1=%\n",pa+1);
   printf("pc=%p\n",pc);
   printf("pc+1=%p\n",pc+1);
   return 0;
}
   

打印结果:pa=006FF9F8

                  pa+1=006FF9FC

                  pc=006FF9F8

                  pc+1=006FF9F9

pa到pa+1:增加了4个字节

pc到pc+1:增加了1个字节

结论:指针的类型决定了指针+-1操作的时候跳过了几个字节,即决定了指针的步长。

三、野指针

野指针就是指针指向位置是不可知的(随机的,不正确的,没有明确限制的)

3.1 野指针成因

1.指针未初始化

int main()
{
   int* p;//p没有初始化,就意味着没有明确的指向,一个局部变量不初始化的化,放的就是随机值
   *p=10;//非法访问内存,这里的p就是野指针
   return 0;
}

2.指针越界访问 

int main()
{
   int arr[10]={0};
   int* p=arr;//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();
   return 0;
}

test()函数运行时,获取了a的地址,主函数获取了a的地址,但此时test()函数的空间已经释放,主函数获取a的地址,通过a的地址找到a,但是由于已经释放,无法找到a。

3.2 避免野指针一般出现

1.指针初始化

2.小心指针越界

3.指针指向空间释放,即使置NULL

4.避免返回局部变量地址

5.指针使用之前检查有效性

四、指针运算

4.1 指针+-整数

#define N_VALUES 5
float values[N_VALUES]
float* vp;
//指针+-整数
for(vp=&values[0];vp<&values[N_VALUES];)
{
   *vp++=0;//后置++:先使用后++
}

4.2 指针-指针 

int main()
{
   int arr[10]={0};
   printf("%d\n",&arr[0]-&arr[9]);
   return 0;
}

打印结果为:9

|指针-指针|得到的是指针和指针之间元素的个数。

不是所有指针都能相减,只有指向同一块空间的两个指针才能相减。

4.3 指针的关系运算

#define N_VALUES 5
float values[N_VALUES]
float* vp;
//指针+-整数
for(vp=&values[N_VALUES];vp>&values[0];)
{
   *--vp=0;
}
#define N_VALUES 5
float values[N_VALUES]
float* vp;
//指针+-整数
for(vp=&values[N_VALUES-1];vp>=&values[0];vp--)
{
   *vp=0;
}

上述代码一和代码二都可行,原理如4.1指针+-整数的计算,但是代码二,标准并不保证它可行。

标准规定:允许指向数组元素的指针指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较

五、二级指针

int main()
{
   int a=10;
   int* pa=&a;//pa是一个指针变量,一级指针变量
   int** ppa=&pa;//ppa是一个二级指针变量
   **ppa=20;
   printf("%d\n",a);
   return 0;
}

打印结果为:20

 

二级指针变量是用来存放一级指针变量的地址的。

六、指针数组

//存放指针的数组就是指针数组。

int main()
{
   int a=10;
   int b=20;
   int c=30;
   int* pa=&a;
   int* pb=&b;
   int* pc=&c;
   return 0;
}
int main()
{
   int arr1[4]={1,2,3,4};
   int arr2[4]={2,3,4,5};
   int arr3[4]={3,4,5,6};
   
   int* parr[3]={arr1,arr2,arr3};
   int i=0;
   for(i=0;i<3;i++)
   {
      int j=0;
      for(j=0;j<4;j++)
      {
      printf("%d ",parr[i][j]);
      }
      printf("\n");
   }
   return 0;

}

打印结果:1 2 3 4

                  2 3 4 5

                  3 4 5 6

 i=0时,进入j循环:

  i=0,j=0:i=0的意思是parr[0],即是parr指针数组的第0位是arr1

                   j=0的意思是arr1[0],即是arr1数组的第0位是1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值