【C语言:深入理解指针一】

文章目录

  • 1.指针存在的意义
  • 2.指针变量和地址
  • 3.指针变量类型的意义
    • 3.1指针解引用
    • 3.2指针+ - 整数
    • 3.3void*
  • 4.关键字const
    • 4.1const修饰变量
    • 4.2 const修饰指针
  • 5.指针运算
    • 5.1指针+ -整数
    • 5.2指针-指针
    • 5.3指针比较大小
  • 6. 野指针
  • 7.assert断言
  • 8. 数组名的理解
  • 9.一维数组传参的本质

在这里插入图片描述

1.指针存在的意义

说到C语言,你是不是最害怕里面的指针呀。看完下面的内容,你或许对指针就没那么胆怯了。
首先,我们要明白C语言中为什么要有指针。

  • 指针是C语言的灵魂,这句话并不夸张。指针是C语言中最基础、最重要的概念之一,它使得C语言成为一门强大的、高效的、灵活的编程语言。
  • 指针的存在使得C语言可以进行复杂的内存操作,能够更好地控制程序的行为,同时也能够实现高效的数据结构和算法。
  • 指针是一个变量,它存储了一个内存地址,而这个内存地址指向的是另一个变量或对象的位置。通过指针,我们可以直接访问或修改这个位置的变量或对象,这为我们提供了很大的灵活性和控制力

在计算机中我们把内存单元的编号也称为地址。C语言中给地址起了新的名字叫:指针。
所以我们可以理解为:内存单元的编号=地址 = 指针

2.指针变量和地址

  1. 在C语言中,创建变量就是向内存申请空间,如下图:

在这里插入图片描述
上述代码就是创建了一个整型变量a,向内存中申请了4个字节的空间,每个字节都有自己的地址。
&a取出的是a所占4个字节中地址较小的字节的地址。,我们知道了它的地址,就可以顺藤摸瓜访问到4个字节的数据。

  1. 如何拿到变量的地址?

我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0133FE28,这个数值有时候也是需要存储起来,⽅便后期再使⽤的,那我们把这样的地址值存放在哪⾥呢?答案是:指针变量中。
指针变量的写法:就是在变量前加上一颗 *
在这里插入图片描述
指针变量也是⼀种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址。指针变量也有自己的地址 ,这里pa的地址就是0x00cffdfc。

  1. 如何通过地址获取变量?

我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)。
在这里插入图片描述

  1. 指针变量的大小
  • 指针变量的大小取决于地址的大小,与指针变量的类型无关。
  • 32位平台下,地址是32个bit位,即4个字节。
  • 64位平台下,地址是64个bit位,即8个字节。

在这里插入图片描述

3.指针变量类型的意义

3.1指针解引用

在这里插入图片描述
在这里插入图片描述
通过调试我们可以看到,第一个会将a的4个字节全部改为0,第二个只是将a的第⼀个字节改为0。
结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)

3.2指针+ - 整数

在这里插入图片描述

通过上图我们可以发现 int 类型的指针+1跳过了4个字节,char类型的指针+1跳过1个字节。
结论:指针的类型决定了指针向前或者向后走⼀步有多⼤(距离)

3.3void*

在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针(或者叫泛型指针),这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的+ -整数和解引⽤的操作。

  • void* pi 可以接受任意类型的地址

在这里插入图片描述

  • 不能对void 类型的指针进行解引用和加减整数的操作

在这里插入图片描述

4.关键字const

4.1const修饰变量

如果我们希望⼀个变量加上⼀些限制,不能被修改,怎么做呢?这就是const的作⽤。

  • const修饰变量,变量的值就不能修改了

在这里插入图片描述

4.2 const修饰指针

  • const 在 * 号的左边

在这里插入图片描述

  • const 在 * 号的右边

在这里插入图片描述

  • const在 * 的两边

在这里插入图片描述

总结::左定值,右定向

5.指针运算

5.1指针+ -整数

在这里插入图片描述

在这里插入图片描述

5.2指针-指针

  • 指针-指针的绝对值是两个指针之间的元素个数(两个指针必须指向同一块空间

在这里插入图片描述

5.3指针比较大小

  • 指针比较大小,就是地址比较大小

在这里插入图片描述

6. 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针是如何造成的呢?

  1. 指针未初始化

局部变量不初始化,默认是随机值。
在这里插入图片描述

  1. 指针越界访问

在这里插入图片描述

  1. 指针指向的空间被释放

在这里插入图片描述

可以打印出来10是因为test函数的栈帧空间还没有被破坏,再次打印的时候,就变成随机值了。

指针虽好,但是不规范使用指针可能会造成意想不到的后果,因此在使用时,应该避免出现野指针。

如何规避野指针呢?

  1. 指针初始化
  2. 不要越界访问
  3. 指针变量不使用时及时置为NULL
  4. 指针使用前检查是否为NULL

7.assert断言

assert.h 头⽂件定义了宏 assert() ,⽤于在运行时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断言”。
assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣任何作⽤,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写⼊⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的⽂件名和⾏号,如下:

#include<stdio.h>
#include<assert.h>
int main()
{
	int* p = NULL;
	assert(p != NULL);
	printf("66666\n");
	return 0;
}

在这里插入图片描述
使⽤ assert() 有几个好处:它不仅能自动标识⽂件和出问题的行号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断言,就在 #include <assert.h> 语句的前⾯,定义⼀个宏 NDEBUG 。
在这里插入图片描述
⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就行,在 VS 这样的集成开发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在 Release 版本不影响⽤⼾使⽤时程序的效率。

8. 数组名的理解

  • 数组名就是数组首元素的地址,但是有2个例外!

在这里插入图片描述

  • 例外1

sizeof(数组名),sizeof中单独放数组名,数组名表示整个数组的大小,单位是字节。
在这里插入图片描述

  • 例外2

&数组名,取出的是整个数组的地址(整个数组的地址和数组首元素的地址是有区别的)

在这里插入图片描述
这里我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素
但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的
到这里大家应该搞清楚数组名的意义了吧。

9.一维数组传参的本质

首先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把函数传给⼀个函数后,函数内部求数组的元素个数吗?
在这里插入图片描述
我们发现结果不是我们想要的,在func函数内部,sizeof(arr) 的大小不是40了,而是4,这是为什么呢?

  • 通过对数组名的学习后我们知道,数组名是数组⾸元素的地址;
  • 那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址
  • sizeof一个地址,那它的大小肯定是4/8个字节,所以结果才会是1.
  • 因此我们可以明白:一维数组传参,传递的是数组首元素的地址。当我们接收的参数是数组名的时候,可以写成指针的形式。
void test(int* arr)//参数写成指针形式
{
 	printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩
}
  • 数组元素的访问在编译器处理的时候,也是转换成⾸元素的地址+偏移量求出元素的地址,然后解引⽤来访问的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

博客积分上一万一千了

博客积分上一万一千了 充满自信&#xff0c;继续前进。

程序员职业生涯规划:多领域路线图一网打尽 | 开源日报 No.72

kamranahmedse/developer-roadmap Stars: 244.4k License: NOASSERTION 这是一个互动的路线图&#xff0c;指南和其他教育内容&#xff0c;旨在帮助开发人员在他们的职业生涯中成长。 提供多个不同领域 (如前端、后端、DevOps 等) 的路线图路线图可交互&#xff0c;并提供了详…

C语言--每日五道选择题--Day9

第一题 1、如下程序的运行结果是&#xff08; &#xff09; char c[5]{a, b, \0, c, \0}; printf("%s", c); A: a b B: ab\0c\0 C: ab c D: ab 答案及解析 D 首先这是一个字符数组&#xff0c;我们要知道无论是字符串还是字符数组&#xff0c;它们遇到ASCII值为0就…

Django中如何创建表关系,请求生命周期流程图

Django中ORM创建表关系 如何创建表关系(一对一 &#xff0c; 一对多 &#xff0c; 多对多) 图书表&#xff0c;出版社表&#xff0c;作者表&#xff0c;作者详情表 换位思考法判断表关系 图书表和出版社表 >>> 一对多 >>> 图书表是多&#xff0c;出…

【Spring】@Component组件

大前提&#xff1a; 添加了相关的约束文件以及注解支持 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:…

异步编程工具Promise与Async/Await:解决前端开发中的嵌套回调地狱

文章目录 Promise&#xff1a;处理异步操作的基本工具Promise.all async/await&#xff1a;更简洁的异步编程方式Promise与async/await的比较结论 当谈及JavaScript中的异步编程时&#xff0c;两个非常常见且强大的工具是Promise和async/await。在本文中&#xff0c;我们将以实…

​软考-高级-系统架构设计师教程(清华第2版)【第3章 信息系统基础知识(p120~159)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第3章 信息系统基础知识(p120~159)-思维导图】 课本里章节里所有蓝色字体的思维导图

【Redis】String字符串类型

上一篇&#xff1a;Redis-key的使用 https://blog.csdn.net/m0_67930426/article/details/134361821?spm1001 .2014.3001.5501 目录 appen (附加&#xff09; strlen(获取字符串的长度&#xff09; incr decr getRange(获取字符串&#xff09; setRange&#xff08;替…

Flink

1. Flink简介 1.1 初识Flink Flink项目的理念是&#xff1a;“Apache Flink是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源的有状态的流处理框架”。 Apache Flink是一个框架和分布式处理引擎&#xff0c;用于对无界和有界数据流进行有状态计算。Fl…

fastbins_Double Free调试

我大哥给我出了一题pwn heap题&#xff0c;当时现场的时候没解出来&#xff0c;想岔了。事后感概自己还是理解的不够透彻。决定认真再次调试下。用的是2.23版本的how2heap中fastbins_dup.c。 简单用gcc编译下&#xff0c;然后带源码调试&#xff1a; 生成一个a.out的文件&#…

leetcode刷题日记:111. Minimum Depth of Binary Tree(二叉树的最小深度)

给我们一个二叉树&#xff0c;我们应该如何来求二叉树的最小深度呢&#xff1f; 二叉树的最小深度指的是叶子结点到所处的位置最小的&#xff0c;这就是二叉树的最小深度&#xff0c;也就是说我们要找的是离根结点最近的叶子结点。如果我们从根结点向下出发寻找叶子节点&#x…

移动硬盘和u盘的区别哪个好 移动硬盘和u盘有啥区别

在数字时代的今天&#xff0c;数据存储已经成为我们生活中的重要一环。当我们需要移动、备份或传输大量数据时&#xff0c;常常会不知道是选择移动硬盘还是U盘。其实&#xff0c;对于许多人来说&#xff0c;移动硬盘和U盘之间的区别并不清晰。下面我们就来看移动硬盘和u盘的区别…

思科9300交换机使用USB进行升级ISO

一、下载ISO 一、网址 Software Download - Cisco Systems 二、找到型号 四、选择XE 软件 五、进行下载 二、COPY 进 U盘 一、、请注意&#xff01;如果你的U盘不是Fat32文件格式则交换机读取不了&#xff0c;请先格式化再复制文件。 二、下载后将 bin文件复制到U盘。 1.扩展…

经典OJ题:重排链表

题目&#xff1a; 给定一个链表&#xff0c;在进行重排前&#xff1a; 进行重排链表后&#xff1a; 如上图所示&#xff0c;所谓的重拍链表&#xff0c;就是将第一个节点连接第倒数第一个节点&#xff0c;第二个节点连接倒数第二个节点&#xff0c;以此类推&#xff0c;最后在连…

【matlab】KMeans KMeans++实现手写数字聚类

目录 matlab代码kmeans matlab代码kmeans MNIST DATABASE下载网址: http://yann.lecun.com/exdb/mnist/ 聚类 将物理或抽象对象的集合分成由类似特征组成的多个类的过程称为聚类(clustering)。 对于给定N个n维向量x1&#xff0c;…&#xff0c;xN∈Rn&#xff0c;聚类的目标…

贪心

【深基12.例1】部分背包问题 题目描述 阿里巴巴走进了装满宝藏的藏宝洞。藏宝洞里面有 N ( N ≤ 100 ) N(N \le 100) N(N≤100) 堆金币&#xff0c;第 i i i 堆金币的总重量和总价值分别是 m i , v i ( 1 ≤ m i , v i ≤ 100 ) m_i,v_i(1\le m_i,v_i \le 100) mi​,vi​(…

统计学_蒙特卡罗方法

1、蒙特卡罗方法的基本思想 蒙特卡罗方法(Monte Carlo method)是由冯诺依曼和乌拉姆等人发明的&#xff0c;“蒙特卡罗”这个名字是出自摩纳哥的蒙特卡罗赌场&#xff0c;这个方法是一类基于概率的方法的统称&#xff0c;不是特指一种方法。 蒙特卡罗方法也成统计模拟方法&am…

SpringBoot3数据访问

SpringBoot3数据访问 SpringBoot整合 Spring、SpringMVC、MyBatis进行数据访问开发。 整合SSM场景 整合步骤 1、创建SSM整合项目 ①数据库准备 DROP TABLE IF EXISTS t_user; CREATE TABLE t_user (id bigint NOT NULL AUTO_INCREMENT COMMENT 编号,login_name varchar(200)…

前端---认识HTML

文章目录 什么是HTML&#xff1f;HTML的读取、运行HTML的标签注释标签标题标签段落标签换行标签格式化标签图片标签a标签表格标签列表标签表单标签form标签input标签文本框单选框复选框普通按钮提交按钮文件选择框 select标签textarea标签特殊标签div标签span标签 什么是HTML&a…

2.1 CE修改器:精确数值扫描

本关是CE修改器的第一关&#xff0c;用户需要通过 Cheat Engine 工具完成精确扫描值。在这个练习中&#xff0c;需要将一个特定的数值&#xff08;健康值&#xff09;改变为 1000。首先&#xff0c;要确保数值类型设置正确&#xff0c;默认的是2字节或4字节。接着&#xff0c;选…