【C生万物】 指针篇 (初级)

news2024/11/24 22:40:01

 欢迎来到 Claffic 的博客 💞💞💞                               👉 专栏:《C生万物 | 先来学C》👈

前言:

面对C语言,很多童鞋都会高呼:指针难,指针难,对于我来说,指针是解决问题的一大杀器,是C/C++的灵魂,先不考虑难不难的问题,上了车再说。


 

目录

Part1:何为指针

1.概念

2.编址和指针大小

Part2:指针使用

1.类型

2.解引用

Part3:野指针

1.概念

2.成因

2.1指针未初始化

2.2指针越界访问

2.3指针指向的空间释放

3.如何规避

Part4:指针运算

1.指针 +- 整数

2.指针 - 指针

3.指针的运算关系

Part5:指针与数组

Part6:指针数组

Part7:二级指针


Part1:何为指针

1.概念

在初始C语言的时候就提到了,指针就是地址,具有指向作用。

这里有指针理解的两个要点:

• 指针是内存中一个最小单元的编号,也就是地址;
• 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

总结一下,还是指针就是地址,口语中说的指针就是指针变量。

理解:

内存中的每个字节都是有标号的,称为地址:

(地址以十六进制展示)

考考你,如何取到指针变量呢?

用取地址符号&,在操作符篇已经讲过了。

指针变量:

我们可以通过  & (取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量。
#include <stdio.h>
int main()
{
	int a = 10; // 在内存中开辟一块空间
	int* p = &a; // 使用&操作符,取出变量a的地址
	
	return 0;
}

a 变量占用4个字节的空间,这里是 将 a 的4个字节的第一个字节的地址存放在p变量中

p就是一个指针变量。 

2.编址和指针大小

不知道你注意了吗,上方展示的是一个字节编一个地址,那么为什么这么做呢?

任何软件上的行为都可以归结到硬件上: 

对于32位的机器,假设有32根地址线,

每根地址线在寻址的时候会产生高电压(1)或低电压(0),

32根地址线产生的地址就有:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
... ...
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111111

计算一下,这里有2^32个地址,

每个地址标识一个字节,就可以给4GB的空间进行编址。

(一位0/1为一个比特位,1Byte == 8bit)

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

总结: 

指针变量是用来存放地址的,地址是唯一表示一个内存单元的
指针的大小在 32 位平台是 4 个字节,在 64 位平台是 8 个字节

Part2:指针使用

1.类型

我们知道变量是有类型的,那么指针有类型吗?

答案是肯定的,

如:

p 没有指定类型,所以会爆红。

正确情况应该是:

以下是一些常见的指针类型:

char* pc = NULL;
int* pi = NULL;
short* ps = NULL;
long* pl = NULL;
float* pf = NULL;
double* pd = NULL;

可见,指针的定义方式是 type + * + name 

变量的类型与指针的类型是对应的

如 int* 指针存储 int 类型的变量,char* 指针存储 char 类型的变量。

2.解引用

指针的解引用符号也是 * ,是由地址找到变量的操作。

以上只是笼统的说法,实际上这种说法并不准确。

看下面这段代码:

pc 和 pi 是不同的,区别在于访问的位数不同

 char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
准确的说法是:
指针的类型决定了对指针解引用的时候有多大的权限(能操作几个字节)。

Part3:野指针

1.概念

野指针就像一条野狗,它面向的位置是随机的

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

 

2.成因

2.1指针未初始化

#include <stdio.h>
int main()
{
	int* p; // 局部变量指针未初始化,默认为随机值
	*p = 20;
	return 0;
}

此处就像随机找个房间闯入... ...

2.2指针越界访问

在数组中存在越界访问:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 1; i <= 11; i++)
	{
		*(p++) = i; // 当i等于11时,数组越界访问
	}

	return 0;
}

当指针指向的范围超出数组arr的范围时,p就是野指针。

2.3指针指向的空间释放

试想,这有一块空间,有个指针指向它,突然这块空间被释放了,

指针不见了空间,那它不就变野了吗?

以上是笼统的说法,具体到动态内存开辟篇讲解

3.如何规避

这里总结几种规避野指针的方法:

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

敲代码时养成好习惯。

对于检查有效性,这里详细解释下:

#include <stdio.h>
int main()
{
	int* p = NULL;
	int a = 10;
	p = &a;
	if (p != NULL)
	{
		*p = 20;
	}

	return 0;
}

例如这段代码中,要改变 a ,提前用 p 保存了 a 的地址,在访问之前检查一下 p 是否为空,确保指针的有效性。

Part4:指针运算

1.指针 +- 整数

用下面这段代码测试:

#include <stdio.h>
int main()
{
	int n = 10;
	char* pc = (char*)&n;
	int* pi = &n;

	printf("%p\n", &n);
	printf("%p\n", pc + 1); // char*类型的指针
	printf("%p\n", pi);
	printf("%p\n", pi + 1); // int*类型的指针

	return 0;
}

运行结果: 

 

指针 + 1,地址走了多大由指针类型决定。

运用这一点,我们可以这样遍历数组:

int main()
{
	float values[5];
	float* vp;
	for (vp = &values[0]; vp < &values[5];)
	{
		*vp++ = 0; // 后置++,先使用后++
	}

	return 0;
}

2.指针 - 指针

在计算数组长度的场景下可以利用指针 - 指针

模拟 strlen 函数:

int my_strlen(char *s)
{
       char *p = s;
       while(*p != '\0' ) // 数组以 \0 结尾
              p++;
       return p-s;
}

3.指针的运算关系

标准规定:

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

Part5:指针与数组

在数组篇讲过:

• sizeof(数组名),计算整个数组的大小,内部单独放一个数组名,表示整个数组;

• &数组名,取出的是数组的地址,数组名表示整个数组。

除以上两种情况之外,所有的数组名都表示数组首元素的地址。  

借用下面这段程序解释: 

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = arr; // 指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p <=> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

 运行结果:

 

嗯,除了利用下标,是不是又会了一种访问数组元素方法呢?

#include <stdio.h>
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

运行结果: 

 

  

Part6:指针数组

数组我们是懂的,那么指针数组是什么?

先说指针数组是指针还是数组:

答案是数组,那它有什么特别之处呢?

其实它存储的数据类型是指针,就这里特别。

表示法:

指针类型 + 指针数组名称 + [];

例如:

int* arr[5];

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

 

Part7:二级指针

前面讲的指针都是一级指针,那么什么是二级指针呢?

对的,就是指向指针的指针 / 指针变量的地址

 多一级就多一颗 * 

对二级指针的运算有:

• *ppa 通过对 ppa 中的地址进行解引用,这样找到的是 pa *ppa 其实访问的就是 pa
int b = 20;
*ppa = &b;//等价于 pa = &b;
• **ppa 先通过 *ppa 找到 pa , 然后对 pa 进行解引用操作: *pa ,那找到的是
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

 


总结: 

指针,指针,看完后你应该就觉得指针其实没那么难,学会了它,你就可以处理很多问题,起码还可以装x

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

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

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

相关文章

【计算机专业漫谈】【计算机系统基础学习笔记】W2-1十进制数与二进制数,各进制数直接的转换

利用空档期时间学习一下计算机系统基础&#xff0c;以前对这些知识只停留在应试层面&#xff0c;今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC&#xff0c;参考书籍也是袁老师的教材&#xff0c;这是我的听课自查资料整理后的笔记 W2-1十进制…

ChatGPT背后的技术:人类反馈强化学习RLHF

文章目录 前言Chat GPT是如何基于RLHF进行训练的RLHF 技术分解预训练语言模型训练奖励模型强化学习微调预训练模型 局限性参考 前言 随着OpenAI推出的Chat GPT火热出圈&#xff0c;Chat GPT背后的技术原理之一&#xff0c;人类反馈强化学习RLHF (Reinforcement Learning from …

Matplotlib 网格线

我们可以使用 pyplot 中的 grid() 方法来设置图表中的网格线。 grid() 方法语法格式如下&#xff1a; matplotlib.pyplot.grid(bNone, whichmajor, axisboth, ) 参数说明&#xff1a; b&#xff1a;可选&#xff0c;默认为 None&#xff0c;可以设置布尔值&#xff0c;true…

prometheus实战之二:使用常见指标

欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码)&#xff1a;https://github.com/zq2599/blog_demos 本篇概览 本文是《prometheus实战》系列的第二篇&#xff0c;在《prometheus实战之一&#xff1a;用ansible部署》一文咱们部署了prometheus服务&#xff0c…

防护服穿戴检测识别算法 yolov8

防护服穿戴检测识别系统基于yolov8网络模型图片数据识别训练&#xff0c;算法模型自动完成对现场人员是否按照要求穿戴行为实时分析。YOLOv8 算法的核心特性和改动可以归结为如下&#xff1a;提供了一个全新的 SOTA 模型&#xff0c;包括 P5 640 和 P6 1280 分辨率的目标检测网…

【开发工具】 我居然可以使用Office Tool Plus 安装上Office 真的是太不可思议了

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

【开发工具】 Office Tool Plus 居然也可以部署 Office 365 我的天 真的是太厉害了

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

人不成熟的五大特征-读后感

原文地址&#xff1a;人不成熟的五大特征-百度经验 1 立即要回报 1 所有简单的快的&#xff0c;别人也能做&#xff0c;这并不能使你超过别人。 2 做出别人做不出来的复杂成果&#xff0c;需要较长的时间和持续的学习&#xff0c;得到就得付出&#xff0c;时间&#xff0c;资源…

Windows10本地搭建网站教程 - 内网穿透发布公网访问

文章目录 概述1. 搭建一个静态Web站点2. 本地浏览测试站点是否正常3. 本地站点发布公网可访问3.1 安装cpolar内网穿透3.2 创建隧道映射公网地址3.3 获取公网URL地址 4. 公网远程访问内网web站点5. 配置固定二级子域名5.1 保留二级子域名5.2 配置二级子域名 6. 测试访问二级子域…

【Java笔试强训 30】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;最难的问…

家乡特色推荐系统~java~mysql

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括家乡特色推荐的网络应用&#xff0c;在外国家乡特色推荐系统已经是很普遍的方式&#xff0c;不过国内的管理网站可能还处于起步阶段。家乡特色推荐系统采用java技术&…

常用半导体器件

&#xff08;1&#xff09;N 型半导体 在纯净的半导体硅或锗中掺入适量的五价磷元素&#xff0c;可形成带负电 的自由电子&#xff08;又称多数载流子&#xff09;参与导电。 &#xff08;2&#xff09;P 型半导体 在纯净的半导体硅或锗中掺入适量的三价硼元素&#xff0c;可形…

JavaEE初阶 - 文件/IO

一、认识文件 我们先来认识狭义上的文件(file)。针对硬盘这种持久化存储的I/O设备&#xff0c;当我们想要进行数据保存时&#xff0c;往往不是保存成一个整体&#xff0c;而是独立成一个个的单位进行保存&#xff0c;这个独立的单位就被抽象成文件的概念&#xff0c;就类似办公…

Docker持久化固定容器IP

基于Docker引擎创建Docker容器&#xff0c;在默认条件下创建容器是bridge桥接模式&#xff0c;启动容器IP地址是DHCP随机分配并且递增的&#xff0c;而且容器之间可以互相通信&#xff0c;网段也是固定的。 当Docker容器一旦关闭再次启动&#xff0c;就会导致容器的IP地址再次重…

C#,生信软件实践(01)——序列文件(如FASTA)合并工具的源代码

1 生物信息学简介 生物信息学&#xff08;BioInformatics&#xff09;是研究生物信息的采集、处理、存储、传播&#xff0c;分析和解释等各方面的学科&#xff0c;也是随着生命科学和计算机科学的迅猛发展&#xff0c;生命科学和计算机科学相结合形成的一门新学科。它通过综合…

Photoshop如何使用通道之实例演示?

文章目录 0.引言1.利用通道调整图像的颜色2.给风景照替换天空3.制作故障艺术效果4.使用通道抠取复杂图像 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程》及其配套素材结合网上相关资料进行学习笔记总结&a…

Linux命令集

一、Linux常用的目录处理命令集 1、ls命令&#xff08;用来查看目录和文件&#xff09; &#xff08;1&#xff09;ls -a&#xff08;查看所有文件包括隐藏文件&#xff09; &#xff08;2&#xff09;ls -l &#xff08;以长格式显示目录下的内容列表&#xff09; &#xff0…

【小样本分割 2022 ECCV】DCAMA

文章目录 【小样本分割 2022 ECCV】DCAMA摘要1. 简介2. 网络2.1 整体架构2.2 特征提取与掩模制备2.3 多尺度多层交叉注意加权掩码聚合。2.4 掩码特性混合器。 3. 代码 【小样本分割 2022 ECCV】DCAMA 论文题目&#xff1a;Dense Cross-Query-and-Support Attention Weighted Ma…

【分布式】路由配置服务

在之前我们将路由表以及分组信息一直存储在网关中&#xff0c;如下图&#xff1a; 显然这样设计并不合理&#xff1a; 网关应该只负责对用户的信息进行解析并根据类型进行转发&#xff0c;最大限度减少其他的负荷网关作为一个单点&#xff0c;在出现故障后&#xff0c;我们希…

CH32V307V-EVT-R1 简单上手入门

文章目录 〇、前言一、开发板展示以及介绍二、开发环境配置与搭建2.1 IDE 介绍2.2 IDE 环境搭建2.3 IDE 配置2.3.1 语言切换&#xff08;汉化&#xff1f;不存在的&#xff09; 三、初次烧录与体验四、简单总结与心得&#x1f517; 链接直达 〇、前言 运气不错&#xff0c;前几…