指针!!C语言(第一篇)

news2024/11/13 22:03:17

指针1

  • 指针变量和地址
    • 1.取地址操作符(&)
    • 2.指针变量和解引用操作符(*)
  • 指针变量的大小和类型
  • 指针的运算
  • 特殊指针
    • 1.viod*指针
    • 2.const修饰指针
    • 3.野指针
  • assert断言
  • 指针的使用和传址调用
    • 1.strlen的模拟实现
    • 2.传值调用和传址调用

指针变量和地址

在认识指针之前,我们先引入一个实际生活的例子,比如我们要找一个小区内的房子,如果我们知道它在具体的几号楼,房间编号是多少的话那我们就很容易找到。那么对照到计算机中,我们知道CPU读取数据也是在内存中读取,存储数据也同样在内存中,如果将内存也分成一个个编号和一个个空间,那我们寻找一个数据岂不是更快更便捷?

其实在计算机中我们同样也是将内存划分为一个个内存单元,一个内存单元取一个字节,也就是8个比特位,每个内存单元也都有一个编号(这个编号就相当于小区房间的门牌号),有了这个内存单元的编号,CPU就可以快速找到一个内存空间。生活中我们把门牌号也叫地址,在计算机中我们把内存单元的编号也称为地址。C语言中给地址起了新的名字叫:指针所以我们可以理解为:内存单元的编号 = 地址 = 指针。

1.取地址操作符(&)

理解了内存和地址的关系,我们再回到C语言,在C语言中创建变量其实就是向内存申请空间,比如:在这里插入图片描述

2.指针变量和解引用操作符(*)

指针变量:那我们通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x006FFD70,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中。下面展示一些 内联代码片

#include <stdio.h>
int main()
{
int a = 10;
int* p = &a;//取出a的地址并且存在指针变量p中
return 0}

指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址在这里插入图片描述
解引用操作符: 当我们把一个变量存储在一个指针变量中,如果我们要使用这个指针变量的话,我们要怎样使用呢?
下面展示一些 内联代码片

#include <stdio.h>
int main()
{
int a=10;
int* pa=&a;
*pa=20;//将a中的数值改为20
printf("%d\n",a);
return 0;
}

在上面的代码中, *pa 的意思就是通过pa中存放的地址,找到指向的空间 *pa其实就是a变量了;所以 *pa = 20,这个操作符就是把a改成了20,也就是通过指针来修改a变量中存的数值。

指针变量的大小和类型

首先我们要知道指针变量也是有大小,指针变量的大小是通过字节来判断的,指针变量的大小取决于地址的大小:
比如:32位平台下地址是32个bit位(即4个字节),64位平台下地址是64个bit位(即8个字节)
在这里插入图片描述
虽然所占字节大小与类型无关,但是类型仍然是有意义的,决定了它解引用时候的权限,例如int* pa=&a;char* pc=&a;假如给a重新赋一个值0,就会发现通过调试int类型中的字节全部变为0,而char类型中的字节只有第一个字节变为0。

指针的运算

指针+ - 整数:指针也有运算,例如对于整型指针的加减&a→&a+1,就将指针的地址移动了4个字节,但如果是char类型的话,就只移动1个字节,也就是说不同类型的指针移动的字节大小是不相同的。
指针-指针:指针-指针的绝对值是指针和指针之间元素的个数,但是两个指针指向的是同一块空间才可以。

特殊指针

1.viod*指针

在指针类型中有⼀种特殊的类型是 void * 类型的,可以理解为无具体类型的指针(或者叫泛型指针),这种类型的指针可以用来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进行指针的±整数和解引用的运算。一般 void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得⼀个函数来处理多种类型的数据。

2.const修饰指针

如果在一个程序中我们希望一个变量不能被随便修改,那我们应该怎么办呢?const就可以实现这个作用。
比如:int a=100; a=200;那么输出的a就等于200,但是如果我们在int前面加上const,那么此时的a就不能被修改了。但是如果我们通过指针也就是用地址来变:下面展示一些 内联代码片

#include <stdio.h>
int main()
{
 const int n = 0;
 printf("n = %d\n", n);
 int*p = &n;
 *p = 20;
 printf("n = %d\n", n);
 return 0;
}

通过上面的代码,即使我们用const来修饰但是通过指针变量我们还是能把变量改变,那么有没有什么办法始终不能改变量里面的值呢?给大家放一张图:在这里插入图片描述

3.野指针

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

  1. 指针初始化(如果不知道指向哪里,就赋值NULL空指针)
  2. 不要越界访问(例如我们访问一个数组,当超过数组的范围还要继续访问,将成为野指针)
  3. 指针变量不再使用时,及时置NULL,指针使用之前检查有效性。
  4. 避免返回局部变量的地址

assert断言

assert.h 头文件定义了宏 assert() ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”。
eg:assert(p!=NULL);
上面代码在程序运行到这一行语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运行,否则就会终止运行,并且给出报错信息提示。assert() 宏接受一个表达式作为参数。如果该表达式为真(返回值非零), assert() 不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。
使用assert的好处也有很多,它不仅能自动标识文件和出问题的行号,还有一种无需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断言,就在 #include <assert.h> 语句的前面,定义一个宏 NDEBUG 。
在这里插入图片描述
assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。
一般我们可以在 Debug 中使用,在 Release 版本中选择禁用 assert 就行,在 VS 这样的集成开发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,在 Release 版本不影响用户使用时程序的效率。

指针的使用和传址调用

1.strlen的模拟实现

库函数strlen的功能是求字符串长度,统计的是字符串中 \0 之前的字符的个数。
函数原型如下:下面展示一些 内联代码片

#include <assert.h>
size_t my_strlen(const char* s)//保证s不被改变
{
	int count = 0;
	assert(s != NULL);//保证s不能是空指针
	while (*s)
	{
		count++;
		s++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdef";
	size_t len = my_strlen(arr);
	printf("%zd\n", len);
	return 0;
}

const保证了字符串内容不被改变。

2.传值调用和传址调用

写一个函数交换两个变量的值:下面展示一些 内联代码片

#include <stdio.h>
void Swap1(int x, int y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	printf("交换前:a=%d b=%d\n", a, b);
	Swap1(a, b);
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

在这里插入图片描述
通过上面的代码我们可以看出来,即使我们使用函数交换两个变量的数值,但是输出的结果仍然不是我们想要的结果,那么问题到底出现在哪呢?这个时候我们就要知道一个叫做传值调用,也就是如果直接将数值传过去,就是传值调用。实参传递给形参的时候,形参会单独创建一份临时空间,对形参的修改不影响实参。那么有没有什么办法呢?我们可以想到使用指针传址的办法,也就是传址调用
下面展示一些 内联代码片

#include <stdio.h>
void Swap2(int*px, int*py)
{
 int tmp = 0;
 tmp = *px;
 *px = *py;
 *py = tmp;
}
int main()
{
 int a = 0;
 int b = 0;
 scanf("%d %d", &a, &b);
 printf("交换前:a=%d b=%d\n", a, b);
 Swap2(&a, &b);
 printf("交换后:a=%d b=%d\n", a, b);
 return 0;
}

在这里插入图片描述
传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。

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

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

相关文章

鸿蒙实训笔记

第一天 #初始化一个新的NPM项目(根据提示操作) npm init #安装TSC、TSLint和NodeJS的类型声明 npm install -s typescript tslint types/node 在根目录中新建一个名为tsconfig.json的文件&#xff0c;然后在代码编辑器中打开&#xff0c;写入下述内容&#xff1a; {"co…

SpringBoot+Vue实现简单的文件上传(Excel篇)

SpringBootVue实现简单的文件上传 1 环境 SpringBoot 3.2.1&#xff0c;Vue 2&#xff0c;ElementUI 2 页面 3 效果&#xff1a;只能上传xls文件且大小限制为2M&#xff0c;选择文件后自动上传。 4 前端代码 <template><div class"container"><el…

性能测试(2)

jmeter参数化 loadrunner Jmeter IP欺骗&#xff0c;也称为IP欺诈&#xff0c;是指通过伪装、篡改IP地址的方式&#xff0c;进行网络攻击或欺骗行为。这种行为可能会导致网络安全问题&#xff0c;包括身份盗窃、数据泄露、DDoS攻击等。为了保护自己的网络安全&#xff0c;用户…

5.3 需求分析

软件需求 定义 分类 真题 需求工程 需求获取 真题 需求分析 状态转换图 数据流图 数据流图分层 顶层数据流图、0层数据流图 1层数据流图 真题 需求规约 需求定义方法 需求验证 需求验证内容 需求管理 版本控制 需求跟踪 变更控制 真题

mysql不初始化升级

1、下载mysql&#xff0c;下载地址&#xff1a;MySQL :: Download MySQL Community Server 2、解压下载好的mysql&#xff0c;修改配置文件的datadir指定目录为当前数据存储的目录 3、通过管理员cmd进入新版本mysql的bin目录&#xff0c; 然后执行命令安装mysql服务&#xff…

2024年山东省安全员B证证考试题库及山东省安全员B证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年山东省安全员B证证考试题库及山东省安全员B证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大…

LeetCode 441, 57, 79

目录 441. 排列硬币题目链接标签思路代码 57. 插入区间题目链接标签思路两个区间的情况对每个区间的处理最终的处理 代码 79. 单词搜索题目链接标签原理思路代码 优化思路代码 441. 排列硬币 题目链接 441. 排列硬币 标签 数学 二分查找 思路 由于本题所返回的 答案在区间…

通过 PPPOE 将 linux 服务器作为本地局域网 IPv4 外网网关

将 linux 服务器作为本地外网网关&#xff0c;方便利用 Linux 生态中的各种网络工具&#xff0c;对流量进行自定义、精细化管理… 环境说明 拨号主机&#xff1a;CentOS 7.9, Linux Kernel 5.4.257 拨号软件: rp-pppoe-3.11-7.el7.x86_64初始化 1、升级系统到新的稳定内核&a…

半年GMV狂飙166亿!酒水赛道正在崛起自播之路

从2022年开始&#xff0c;酒水以“兴趣”为核心的直播电商迎来爆发式增长。以抖音电商为例&#xff0c;2022年下半年整体销售额破百亿&#xff0c;环比增幅超100%&#xff0c;2023年全年更是破300亿大关&#xff01;兴趣电商成为酒行业的第二增长曲线。 今年上半年&#xff0c;…

机器学习第四十七周周报 CF-LT

文章目录 week47 CF-LT摘要Abstract1. 题目2. Abstract3. 网络结构3.1 CEEMDAN&#xff08;完全自适应噪声集合经验模态分解&#xff09;3.2 CF-LT模型结构3.3 SHAP 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程 5. 结论6.代码复现小结参考文献 week47 CF-LT 摘要 本周…

可视耳勺是不是智商税?五款好用挖耳勺推荐!

随着人们追求健康生活方式的需求日益增长&#xff0c;可视耳勺这一产品逐渐走入了人们的视野&#xff0c;并受到了广泛的青睐。 然而&#xff0c;市场上可视耳勺品牌和种类繁多&#xff0c;部分产品存在清晰度不高、亮度较暗等问题&#xff0c;在使用过程很容易存在损坏耳道的风…

负载箱如何帮助维持电气系统的最佳性能

负载箱在维持电气系统最佳性能方面发挥着至关重要的作用&#xff0c;以下是负载箱如何帮助维持电气系统最佳性能的详细分析&#xff1a; 一、保护电气设备 负载箱能够在电气系统中产生恒定的负载&#xff0c;使电气设备在正常工作状态下运行。这避免了因负载波动过大而导致的…

数据库管理1

数据库管理 数据库运维。 sql语句 数据库用来增删改查的语句 备份 数据库的数据进行备份 主从复制&#xff0c;读写分离&#xff0c;高可用。 数据库的概念和相关的语法和规范&#xff1a; 数据库&#xff1a;组织&#xff0c;存储&#xff0c;管理数据的仓库。 数据库的管理系…

FreeRTOS_定时器

定时器概述 定时器运行过程 定时器就像一个闹钟&#xff0c;它有超时时间、函数、是否为周期性这三个部分。 超时时间&#xff1a;什么时候到时间&#xff0c;就像闹钟响起函数&#xff1a;闹钟响起&#xff0c;要干什么是否为周期性&#xff1a;这个闹钟只响一次&#xff0…

杭州高校大学智能制造实验室数字孪生可视化系统平台建设项目验收

杭州高校大学智能制造数字孪生技术作为智能制造的重要支撑&#xff0c;通过构建虚拟世界的镜像&#xff0c;实现对物理世界的实时监控、预测和优化。杭州高校大学智能制造实验室数字孪生可视化系统平台建设项目&#xff0c;旨在通过引入先进的数字孪生技术&#xff0c;构建一个…

刚刚,Claude国内可直连!

刚刚&#xff0c;Claude国内可直连&#xff01; 大家好&#xff01;我是科技博主Maynor。今天我们要分享一个激动人心的消息&#xff1a;知名AI助手Claude现在可以在国内直接访问了&#xff01; 这对于科技爱好者、学生、研究人员和各行各业的专业人士来说都是一个重大利好。…

进嵌入式公司当学徒没工资去不去啊?

在开始前分享一些嵌入式资料需要的同学评论888即可拿走 是我根据网友给的问题精心整理的 嵌入式是做技术岗位。技术不到位&#xff0c;没有人会要你。技术都没有&#xff0c;还要你的&#xff0c;一定是骗子。记住这句话就行了。 世上哪有那么好的事情。能免费让你学到真正有…

线性代数|机器学习-P24加速梯度下降(动量法)

文章目录 1. 概述2. 引入3. 动量法梯度下降 1. 概述 我们之前学的最速梯度下降[线搜索方法] 公式如下&#xff1a; x k 1 x k − s k ∇ f ( x k ) \begin{equation} x_{k1}x_k-s_k\nabla f(x_k) \end{equation} xk1​xk​−sk​∇f(xk​)​​ 但对于这种方法来说&#xff…

debian固定ip

debian固定ip 前言 安装好的Debian系统后&#xff0c;为了确保每次登陆的ip不变&#xff0c;需要固定 方法 命令如下 ip addr | grep inet因为有有线网和无线网 2 种连接方式&#xff0c;因此需要区别。 其中 enp 的是有线&#xff0c;wlp 的是无线 查看网关 IP 命令如下 …

蓝牙BLE广播

这里只讨论蓝牙BLE广播 这部分可以看蓝牙标准Core Specification V5.3的卷3 Host part C。当然广播参数那一块和“控制器”层有关&#xff0c;只需要了解广播参数的含义和设置方法就行&#xff0c;控制器的细节不太容易理解。 主要目标 广播参数&#xff08;广播间隔、TX 功…