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

news2024/12/22 22:11:07

文章目录

  • 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));//计算⼀个指针变量的⼤⼩
}
  • 数组元素的访问在编译器处理的时候,也是转换成⾸元素的地址+偏移量求出元素的地址,然后解引⽤来访问的。

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

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

相关文章

SpringBoot自动装配定义先后顺序失效原因极其解析

SpringBoot自动装配定义先后顺序失效原因极其解析 1、场景分析1.1、问题总结 2、使用AutoConfigureBefore、AutoConfigureAfter和AutoConfigureOrder注解指定加载顺序2.2、AutoConfigureXX注解失效原因总结 3、使用静态内部装配类提升加载顺序4、bean加载顺序规则 1、场景分析 …

腾讯云优惠券介绍、作用、领取方法及使用教程

随着云计算技术的发展&#xff0c;越来越多的企业和个人选择使用云服务进行数据存储、计算等业务。腾讯云作为国内知名的云服务商&#xff0c;提供了一整套完善的云解决方案&#xff0c;并不定期发放优惠券以吸引更多的客户。本文将为大家详细介绍腾讯云优惠券的作用、领取方法…

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

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

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

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

解决wrong fs type, bad option, bad superblock on /dev/sda1问题

1 背景 某天挂载硬盘的时候&#xff0c;系统提示了如下错误&#xff1a; 在此记录排查过程以及解决方案。 2 排查过程 出现这种问题应该先尝试从日志入手&#xff0c;输入&#xff1a; sudo dmesg | tail输出如下&#xff1a; 关键信息&#xff1a; [ 164.750178] ntfs3:…

【Mybatis小白从0到90%精讲】16: Mybatis like语句四种传参方式

文章目录 前言方式一:Java代码拼接方式二:MySQL CONCAT函数方式三:Mybatis bind标签方式四:SQL拼接前言 在实际开发中,SQL中使用 模糊查询like使用非常普遍,在MyBatis中,为了防止SQL注入攻击,可以使用#{}来传递参数,切记like语句不要使用${}的方式! 这里我总结了 四…

【离散数学必刷题】谓词逻辑(第二章 左孝凌版)刷完包过!

专栏&#xff1a;离散数学必刷题 本章需要掌握的重要知识&#xff1a; 1.利用谓词表达式表示命题 2.变元的约束 3.谓词公式的定义、谓词公式的赋值 4.谓词公式的翻译&#xff08;注意在全总个体域时使用特性谓词&#xff09; 5.有限论域上量词的消去 6.谓词公式中关于量词的等价…

【算法每日一练]-单调队列,滑动窗口(保姆级教程 篇1) #滑动窗口 #求m区间的最小值 #理想的正方形 #切蛋糕

今天讲单调队列 目录 题目&#xff1a;滑动窗口 思路&#xff1a; 题目&#xff1a;求m区间的最小值​ 思路&#xff1a; 题目&#xff1a;理想的正方形 思路&#xff1a; 题目&#xff1a;切蛋糕 思路&#xff1a; 一共两种类型&#xff1a;一种是区间中的最值&…

代码随想录算法训练营第四十九天|121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 II

第九章 动态规划part10 121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最…

C语言证明一个偶数总能表示为两个素数之和。输入一个偶数并将其分解为两个素数

完整代码&#xff1a; // 一个偶数总能表示为两个素数之和。输入一个偶数并将其分解为两个素数#include<stdio.h>//判断一个数n是否为素数 int isPrimeNumber(int n){//1不是素数if (n1){return 0;}for (int i 2; i <(n/2); i){//当有n能被整除时&#xff0c;不是素…

吃透 Spring 系列—IOC部分

目录 ◆ 传统Javaweb开发的困惑 -传统Javaweb开发代码分析-用户模块 -传统Javaweb开发困惑及解决方案 ◆ IoC、DI和AOP思想提出 - IoC 控制反转思想的提出 - DI 依赖注入思想的提出 - AOP 面向切面思想的提出 - 框架概念的出现 - 思想、框架和编码关系 ◆ Spring框架…

UML软件建模软件StarUML mac中文版软件介绍

StarUML for mac是一款UML建模器&#xff0c;StarUML for mac提供了几个模版&#xff0c;帮助用户建立使用新的图表&#xff0c;是目前最流行的UML建模工具&#xff0c;给开发工作带来大大的便利。 StarUML mac软件介绍 StarUML 是一个流行的软件建模工具&#xff0c;用于创建…

[vuex] unknown mutation type: SET_SOURCE

项目中使用了vuex&#xff0c;并且以模块的形式分好之后。在调用的时候出现了以上问题 /*当我们commit的时候要注意要加上模块的名字 user是模块名称&#xff0c;SET_SOURCE是user模块中定义的方法 正确写法&#xff1a;*/ this.$store.commit("user/SET_SOURCE", th…

Java14新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 、Java13的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 Java13新增特性 今天我们来一起看一下Java14这个版本的一些重要信息 版本介绍 Java 14…

自动泊车轨迹规划学习

1.基于6次多项式的自动泊车轨迹算法研究 针对常见的自动泊车系统无法躲避障碍物&#xff0c;以及轨迹的曲率不连续等问题进行了泊车轨迹算法的研究以及跟踪算法的设计。 针对低速自动泊车场景进行分析&#xff0c;建立符合对应场景下的车辆运动学模型以及能够泊车的最小车位大…

JavaWeb Day10 案例 准备工作

目录​​​​​​​ 一、需求说明 二、环境搭建 &#xff08;一&#xff09;数据库 &#xff08;二&#xff09;后端 ①controller层 1.DeptController.java 2.EmpController.java ②mapper层 1.DeptMapper.java 2.EmpMapper.java ③pojo层 1.Dept.java 2.Emp.jav…

数据库加密的常用方法 安当加密

数据库加密的方法主要有以下几种&#xff1a; 前置代理及加密网关技术&#xff1a;在数据库之前增加一道安全代理服务&#xff0c;对数据库访问的用户都必须经过该安全代理服务&#xff0c;在此服务中实现如数据加解密、存取控制等安全策略。加密数据存储在安全代理服务中。但…

S32K3基础学习 linker链接器脚本ld文件的学习(一)

一、简介 最近学习NXP新推出的S32K3系列芯片&#xff0c;我在学习容易转牛角尖&#xff0c;非得要搞明白这个芯片的启动流程&#xff0c;所以花费了一些时间&#xff0c;进行查阅资料进行学习&#xff0c;这里做下详细的记录&#xff0c;希望有用&#xff0c;如果有错误欢迎指正…

Springboot+vue的毕业生实习与就业管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的毕业生实习与就业管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点…

dream_ready

&#x1f9f8;欢迎来到dream_ready的博客&#xff0c;&#x1f4dc;相信您对这篇博客也感兴趣o (ˉ▽ˉ&#xff1b;) Python 语法及入门 &#xff08;超全超详细&#xff09; 专为Python零基础 一篇博客让你完全掌握Python语法 路的尽头是什么&#xff1f;这是我年少时常伴在嘴…