你还在恐惧指针吗?点进来,带你全方位深入了解指针

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

指针是什么在这里插入图片描述

指针也就是内存地址指针变量是用来存放内存地址的变量。(存放在指针中的值都被当做地址处理)

对于32位的机器假设有32根地址线那么假设每根地址线在寻找地址的时候会产生高电平高电压和低电平低电压就是1或者0

那么32根地址线产生的地址就会是

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 0000001011111111 11111111 11111111 11111111

这里就有2的32次方个地址

每个地址标识一个字节那我们就可以给4G的空间进行编辑地址

2^32Byte == 2^32/1024KB ==2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB

在32位的机器上地址是32个0或者1组成二进制序列那地址就得用4个字节的空间来存储所以
一个指针变量的大小就应该是4个字节

那么64根地址线产生的地址就会是

00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000010
...
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111

这里就有2的64次方个地址

每个地址标识一个字节那我们就可以给8G的空间进行编辑地址

2^64Byte == 2^64/1024KB ==2^64/1024/1024MB==2^64/1024/1024/1024GB == 8GB

在32位的机器上地址是64个0或者1组成二进制序列那地址就得用8个字节的空间来存储所以
一个指针变量的大小就应该是8个字节

指针变量是用来存放地址的地址是唯一标识一个内存单元的

指针的大小在32位平台是4个字节在64位平台是8个字节

如何使用指针

使用指针时会频繁进行以下几个操作定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。

#include <stdio.h>
 
int main ()
{
   int  var = 20;   /* 实际变量的声明 */
   int  *ip;        /* 指针变量的声明 */
 
   ip = &var;  /* 在指针变量中存储 var 的地址 */
 
   printf("var 变量的地址: %p\n", &var  );
 
   /* 在指针变量中存储的地址 */
   printf("ip 变量存储的地址: %p\n", ip );
 
   /* 使用指针访问值 */
   printf("*ip 变量的值: %d\n", *ip );
 
   return 0;
}

编译结果

var 变量的地址: 0x7ffeeef168d8
ip 变量存储的地址: 0x7ffeeef168d8
*ip 变量的值: 20

C 中的 NULL 指针

在变量声明的时候如果没有确切的地址可以赋值为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为指针。

NULL 指针是一个定义在标准库中的值为零的常量。

内存地址 0 有特别重要的意义它表明该指针不指向一个可访问的内存位置。但按照惯例如果指针包含空值零值则假定它不指向任何东西。

#include <stdio.h>
 
int main ()
{
   int  *ptr = NULL;
 
   printf("ptr 的地址是 %p\n", ptr  );
 
   return 0;
}

编译结果

ptr 的地址是 0x0

指针和指针类型

char *pc = NULL;   //char* 类型的指针是为了存放 char 类型变量的地址。
int *pi = NULL;    //int* 类型的指针是为了存放 int 类型变量的地址。
short *ps = NULL;  //short* 类型的指针是为了存放 short 类型变量的地址。
long *pl = NULL;   //long* 类型的指针是为了存放 long 类型变量的地址。
float *pf = NULL;  //float* 类型的指针是为了存放 float 类型变量的地址。
double *pd = NULL; //double* 类型的指针是为了存放 double 类型变量的地址。

指针±整数

#include <stdio.h>
//演示实例
int main()
{
int n = 10;
char *pc = (char*)&n;//因为n和pc类型不同直接将pc指向n编译器会显示类型不兼容如果一定要进行操作需要对n进行强制类型转换
int *pi = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);//因为char型占1个字节,所以向后移动1位
printf("%p\n", pi);
printf("%p\n", pi+1);//因为int型占4个字节所以向后移动4位
return 0;
}

编译结果

004FFB20
004FFB20
004FFB21
004FFB20
004FFB24

指针的类型决定了指针向前或者向后走一步是多大

指针的解引用

//演示实例
#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0; //重点在调试的过程中观察内存的变化。
*pi = 0; //重点在调试的过程中观察内存的变化。
return 0;
}

指针的类型决定了对指针解引用的时候有多大的权限能操作几个字节。
比如 char* 的指针解引用就只能访问一个字节而 int* 的指针的解引用就能访问四个字节

什么是野指针

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

野指针产生的原因

  1. 指针未初始化
  2. 指针越界访问
  3. 指针指向的空间被释放

如何避免野指针的产生

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放及时置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

指针运算

指针±整数

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}

指针-指针

int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}

指针的关系运算

for(vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}

C语言标准规定

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

指针和数组

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}

运行结果

004FFDFC
004FFDFC

数组名表示的是数组首元素的地址

二级指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtqh0XwL-1674044271602)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20230117222645294.png)]

a的地址存放在pa中pa的地址存放在ppa中

pa是一级指针ppa是二级指针

指针数组

int* arr[5];

arr是一个数组有5个元素每个元素是一个整形指针

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EHYYyA1K-1674044271604)(C:\Users\LENOVO\Desktop\arr.png)]

数组指针

数组指针的定义

数组指针是能够指向数组的指针数组指针中存放的是数组的地址

int (*p)[10];//p先和*结合说明p是一个指针变量然后指着指向的是一个大小为10的整型的数组所有p是一个指针指向一个数组叫数组指针

&数组名VS数组名的区别

&arr表示的是数组的地址&arr+1表示跳过整个数组的大小

arr表示的是数组首元素的地址arr+1表示跳过一个元素的大小

函数指针

函数指针是指向函数的指针变量。

通常我们说的指针变量是指向一个整型、字符型或数组等变量而函数指针是指向函数。

函数指针可以像一般函数一样用于调用函数、传递参数。

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

函数指针数组

数组是存放相同类型数据的存储空间那要把函数的地址存到一个数组中那这个数组就叫函数指针数组

指向函数指针数组的指针

指向函数指针数组的指针是一个指针

指针指向一个数组数组的元素都是函数指针

定义形式

void (*(ppfunArr)[5])(const char*)=&pfunArr;//指向函数指针数组ppfunArr

回调函数

回调函数就是一个通过函数指针调用的函数如果你把函数的指针地址作为参数传递给另一个函数当这个指针被用来调用其所指向的函数时我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用而是在特定的事件或条件发生时由另外一方调用的用于对该事件或条件进行响应

字符指针

方式1

int main()
{
char ch = 'w';
char *pc = &ch;
printf("%c",*pc);
return 0;
}

方式2

int main()
{
const char* pstr = "hello bit.";//本质是把字符串"hello bit"首字符的地址放到了pstr中
printf("%s\n", pstr);
return 0;
}

数当这个指针被用来调用其所指向的函数时我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用而是在特定的事件或条件发生时由另外一方调用的用于对该事件或条件进行响应

字符指针

方式1

int main()
{
char ch = 'w';
char *pc = &ch;
printf("%c",*pc);
return 0;
}

方式2

int main()
{
const char* pstr = "hello bit.";//本质是把字符串"hello bit"首字符的地址放到了pstr中
printf("%s\n", pstr);
return 0;
}
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6