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

news2024/12/28 23:41:30

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

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

对于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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/170732.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[ZJCTF 2019]NiZhuanSiWei

目录 信息收集 代码审计 第一层 第二层 第三层 信息收集 打开页面又是代码审计 代码如下 <?php $text $_GET["text"]; $file $_GET["file"]; $password $_GET["password"]; if(isset($text)&&(file_get_contents($text,…

React + TS + TDD 扫雷游戏学习心得

React TS TDD 扫雷游戏学习心得 试玩地址&#xff1a;https://goldenaarcher.com/minesweeper&#xff0c;stroybook 的地址&#xff1a;https://www.chromatic.com/build?appId63b2530f575ed5942cf105be&number1 测试主要使用 jest&#xff08;mock&#xff09; RTL …

Linux进程控制(进程替换)

目录 一、进程程序替换原理 二、进程替换函数 三、函数实现子进程进程替换 3.1 测试函数 3.2 写时拷贝保证替换后的进程独立性 四、自我实现一个简单的 shell 五、内置命令 5.1 pwd查询路径本质 5.2 内置命令概念 5.3 自我实现shell Pro 先见见进程替换&#xff1a; …

Unity学习笔记--如何在Unity中把自己的代码打包成dll给别人使用?(纯保姆式教学,看完还不会,今晚八点,来沙城砍我)

目录前言背景步骤一步骤二步骤三步骤四&#xff08;关键&#xff01;&#xff01;&#xff01;&#xff09;步骤五步骤六步骤七步骤八步骤九步骤十总结前言 最近公司放年假了&#xff0c;没什么事做&#xff0c;所以来公司学习&#xff08;蹭吃蹭喝ing&#xff09; 突然记起来…

CSS总结笔记+案例

此文章属于前端篇中的第二节CSS样式 继前期HTML标记语言 CSS总结笔记&#xff1a; 3.CSS样式 css&#xff0c;专门用来“美化”标签。 基础CSS&#xff0c;写简单页面&看懂&改。模块、调整和修改 3.1CSS应用方法 1.在标签上 - 高度和宽度样式&#xff1a; <i…

linux基本功系列之alias命令实战

本文目录 文章目录前言&#x1f680;&#x1f680;&#x1f680;一. alias命令介绍二. 语法格式及常用选项三. 参考案例3.1 查看系统已经存在的别名3.2 设置别名的操作3.3 取消别名3.4 alias的全局生效和当前用户生效四. 使用命令的注意事项总结前言&#x1f680;&#x1f680;…

行云洞见 | 为什么说云端IDE代表未来趋势?

原文作者&#xff1a;行云创新解决方案架构师 李楠 预知未来最可靠的方法是了解历史&#xff0c;让我们简单回顾下IDE的发展史。 所谓IDE&#xff0c;即集成开发环境&#xff0c;是软件开发人员在他们用于编程的计算机本地安装的应用程序。伴随着计算机编程语言从第一代机器语…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(万用表)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;万用表 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Multisim 14.0&#xff0c;打开如图所示的启动界面&#x…

【虹科分享】虹科ATEasy软件,您的测试执行和开发专家!

测试和执行专家 虹科ATEasy是功能测试&#xff0c;自动测试系统&#xff0c;数据采集&#xff0c;过程控制和仪表系统的测试执行和快速应用开发框架。虹科ATEasy提供开发&#xff0c;部署和维护软件组件的所有必要工具&#xff0c;包括仪器驱动程序&#xff0c;测试程序&#x…

SGA与PGA的区别

前几天有被别人问到什么是SGA和PGA&#xff0c;说实在的&#xff0c;之前一直搞分布式&#xff0c;已经基本把单机里面的这两个概念忘记的差不多了&#xff0c;不过当时还是根据自己的一点数据库经验说了点七七八八&#xff0c;后来网上查了一下相关说明&#xff0c;发现自己的…

现货黄金与白银现货的区别

黄金与白银同为贵金属&#xff0c;二者均在人类货币史上担当过货币的功能&#xff0c;而现货黄金与白银现货作为其最重要的金融衍生品&#xff0c;都具备良好的收益性、流动性和的可操作性&#xff0c;都是比较理想的投资产品。那么和现货黄金和白银现货的区别在哪里呢?小编认…

C++初学者学习笔记

面向对象的程序设计 初步理解 相比较于面向过程的程序设计来说有更多的封装的函数可以使用&#xff0c;相比较来说会比较方便。但是如何去设计整个程序的思路也是需要一定的训练的。 C 简介 C 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言&#xf…

linux系统目录结构

在 Linux 或 Unix 操作系统中&#xff0c;所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。 文件系统的最顶层是由根目录开始的&#xff0c;系统使用 / 来表示根目录。在根目录之下的既可以是目录&#xff0c;也可以是文件&#xff0c;而每一个目录中又可以包含…

【荐书】C程序设计语言(第二版)

“在大多数人眼中&#xff0c;我是个一事无成、乖僻古怪、令人作呕的人。我毫无社会地位可言&#xff0c;也永远不会有。总之&#xff0c;我是底层人中的底层人。好吧&#xff0c;就算这些看法都完全正确&#xff0c;我也想有那么一天&#xff0c;通过我的作品向他们展示&#…

C++模板(函数模板,类模板)的基本使用与非类型模板参数与模板的特化

C模板模板初阶泛型编程函数模板函数模板概念函数模板格式函数模板的原理函数模板的实例化隐式实例化显式实例化&#xff1a;在函数名后的<>中指定模板参数的实际类型模板参数的匹配原则类模板类模板的定义格式类模板的实例化模板进阶非类型模板参数模板的特化概念函数模板…

【TypeScript】TS与Vue

TypeScript与Vue 文章目录TypeScript与VuedefineProps与TypescriptdefineEmits与Typescriptref与Typescriptreactive与Typescriptcomputed与Typescript事件处理与TypescriptTemplate Ref与Typescript可选链操作符非空断言参考链接&#xff1a;https://vuejs.org/guide/typescri…

【OpenGL学习】texture

纹理 一、什么是纹理&#xff1f; 引用百度百科的定义&#xff1a; 计算机图形学中的纹理既包括通常意义上物体表面的纹理即使物体表面呈现凹凸不平的沟纹&#xff0c;同时也包括在物体的光滑表面上的彩色图案&#xff0c;通常我们更多地称之为花纹。对于花纹而言&#xff0c…

ES6 课程概述⑦

文章目录Vuex_State安装使用State在 Vue 组件中获得 Vuex 状态mapState 辅助函数Vuex_Getter通过属性访问通过方法访问mapGetters 辅助函数Vuex_Mutation在组件中提交 Mutation提交载荷&#xff08;Payload&#xff09;对象风格的提交方式使用常量替代 Mutation 事件类型Mutati…

Spring Boot(五十六):基于Redis的搜索栏热搜功能

1 功能要求 使用SpringBoot和redis实现一个简单的热搜功能&#xff0c;具备以下功能&#xff1a; 搜索栏展示当前登陆的个人用户的搜索历史记录&#xff0c;删除个人历史记录用户在搜索栏输入某字符&#xff0c;则将该字符记录下来 以zset格式存储的redis中&#xff0c;记录该…

Flink DataSet API和DataStream API 对于WordCount的演示

文章目录准备工作Flink DataSet APIFlink DataStream API结论准备工作 pom依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-insta…