C语言基础(9)之指针(1)

news2024/10/5 17:00:11

目录

1. 指针的概念

1.1 内存

1.2 指针是什么        

1.3 指针变量的大小

2. 指针类型

2.1 指针类型的意义

2.2 指针类型意义的疑问

3. 野指针

3.1 野指针的概念

3.2 野指针的成因

3.3 如何规避野指针

4. 指针运算

4.1 指针 + 或 - 整数

4.2 指针 - 指针

4.3 指针 -  指针的用途


        在前面的文章中我详细的讲解了各种操作符的知识,不知道小伙伴们在了解完后有没有自己去练习呀!那么今天这篇文章小编就带大家来了解指针的相关知识。包括什么是指针、指针类型、指针运算等知识点。

1. 指针的概念

        在学习指针之前,我们首先得理解内存的概念,因为指针是用来访问内存的。

1.1 内存

        那么什么是内存呢?内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的。
        所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。
        而为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址,且每一个内存单元都有一个唯一的编号。如下图:

1.2 指针是什么        

        那么指针到底是什么呢?在C语言中,把 这些编号 或 这些地址 也叫做 指针。因此 编号 == 地址 == 指针。

        但我们口头语中常说的指针,基本上都是指针变量。(指针变量  —>  变量  —>  存放地址的变量

        需要注意的是:我们在写C语言程序的时候,创建的变量、数组等都是创建在内存中的(即在内存中分配空间的),而每个内存单元都有地址,所以变量也是有地址的

1.3 指针变量的大小

        在谈及指针变量的大小之前,小编先来给大家讲讲 地址或者编号是如何产生的呢?  ——>      在计算机上,有地址线(物理的电线),通过产生高低电平的信号,转换为数字信号:1/0。在32位的机器中,上面就会有32根地址线;在64位的机器中,上面就会有64根地址线。

        因此在32位的机器上,地址是32个0或者1组成二进制序列,那内存中就得用32个bit位(即4个字节)的空间来存储,所以一个指针变量的大小就应该是4个字节。

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

        大家可以这样记忆:地址可以类比为身份证,并不会因为身份的不同(存储不同的数据类型时)而改变。而指针变量的大小可以类比为身份证的位数,也不会因为一个人身份的改变(数据类型的不同)而改变大小。

总结:

        1. 指针是内存中一个最小单元的编号,也就是地址。

        2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

        3. 指针变量是用来存放地址的,地址是唯一标识一个内存单元的。

        4. 指针变量的大小在32位平台是4个字节,在64位平台是8个字节。

2. 指针类型

        我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?答案当然是有的!

指针的类型:type* p


其中:
* 说明p是指向的 type类型 的指针变量


type说明:1. p指向的对象的类型
                  2. p解引用的时候访问的对象大小是sizeof(type)


例如:
char* pc = NULL;
short* ps = NULL;
int* pi = NULL;
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。

2.1 指针类型的意义

        那指针的类型究竟有什么意义呢?

#include<stdio.h>
int main()
{
	char a = 'x';
	char* pc = &a;

	int i = 10;
	int* pi = &i;

	printf("%p\n", pc);
	printf("%p\n", pc + 1);

	printf("\n");

	printf("%p\n", pi);
	printf("%p\n", pi + 1);

	return 0;
}

        如上所示例子,当我们对不同类型的指针进行 +1 操作时,其在内存中跳过的字节数是不一样的,char类型的指针pc 进行 +1 操作只跳过了一个字节,而int型的指针进行 +1 操作跳过了4个字节。

        也就是说,指针类型决定了指针 +/- 1 操作时的步长,整型指针+1跳过4个字节,字符指针+1跳过1个字节。 +/- n 对于type* p 来说跳过的是:n*sizeof(type)这么多个字节。

int main()
{
	int n = 0x11223344;

	char* pc = (char*)&n;

	*pc = 0;

	printf("0x%x\n", n);

	return 0;
}

        在上述的这个例子中,"0x11223344" 是16进制的数字,我们将整型n的地址 强制类型转换 并赋值给了字符类型的指针pc,当指针pc解引用并修改值时,可以看出 n 的值并没有完全被修改,而是只改变了一个字节的值。

        即指针的类型决定了,对指针解引用的时候有多大的权限,或者说能操作几个字节。 比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

总结指针类型的意义:

        1. 指针的类型决定了指针向前或者向后走一步有多大(距离)
        2. 指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。

2.2 指针类型意义的疑问

        这里也许有一些小伙伴会对第二点有疑问:不是说指针不是4个字节就是8个字节吗?怎么这里又能根据类型来操作字节的个数了? 下面举例来说明:

        如上例子,我们前面说的指针不是4字节就是8字节指的是指针本身自己的大小,如上无论是字符指针pc还是整型指针pi,它们在64位的机器上大小都是8字节。

        而我们所说的指针解引用能操作几个字节,可以这么理解:对于整型指针pi来说,它解引用后,即 *pi 等同于 变量 i而变量 i 是整型类型的,整型(int)的大小是4个字节,因此变量 i 能操作4个字节,即 *pi也只能操作4个字节。

3. 野指针

3.1 野指针的概念

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

3.2 野指针的成因

        那为什么会有野指针呢?野指针是怎么来的呢?主要有以下三点原因!

                1. 指针未初始化。

        如上例子,当局部变量不初始化时,内容会是随机值,此时 p 就称为野指针。

                2. 指针越界访问。

        我们设定数组的长度为10,但当我们用指针访问数组时,访问时却超出了数组大小的范围。换句话说,当指针p指向的范围超出数组arr的范围时,p就是野指针。

                 3. 指针指向的空间释放 (这点小编会在后续讲解动态内存开辟的时候跟老铁们探讨,这里就不先进行讲解了)

3.3 如何规避野指针

既然有野指针,那么我们该如何规避野指针的生成呢?小编在这里给大家总结了几点:

                1. 指针初始化。
                        1.1 明确知道指针应该初始化为谁的地址,就直接初始化。
                        1.2 不知道初始化为什么值,暂时初始化为NULL。
                2. 小心指针越界。
                3. 指针指向的空间释放,及时置为NULL。
                4. 避免返回局部变量的地址。
                5. 指针使用之前检查有效性。

4. 指针运算

        指针运算又可分为:1. 指针 +或- 整数                2. 指针 - 指针。

4.1 指针 + 或 - 整数

        假定这样一个场景:我们设置一个长度大小为10的整型数组arr,要求不使用数组下标的方式访问数组,即不采用arr[0]、arr[1]...这种形式来访问数组。

        那该采用什么样的方式呢?毫无疑问肯定是 指针 + 或 - 整数 的方式。代码如下:

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	
	int* p = &arr[0];
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	for ( i = 0; i < sz; i++)
	{
		*p = i;
		p++;
	}

	for (i = 0; i < sz; i++)
		printf("%d ", arr[i]);

	printf("\n\n");

	p = arr;
	for (i = 0; i < sz; i++)
		printf("%d ", *(p + i));  

	printf("\n");

	return 0;
}

        如结果所示,采用 指针 + 或 - 整数 的方式也能得到正确的结果。

        需要注意的是:

                1. arr是数组名,数组名是首元素的地址,所以可以把arr理解为指针,指向数组首元素,故可以写成p = arr。

                 2. 因为p = arr,所以arr[0] = *p = *(p+0) = p[0]。类推:若p = arr,则arr[i] = *(p+i) = p[i]。

                3. arr[i] == *(arr+i) == *(i+arr) == i[arr] (注:[]仅仅是个操作符)

4.2 指针 - 指针

        大家先来看看下面两个例子:

        上面这个例子说明指针 - 指针结果的绝对值是指针与指针之间的元素个数。

        而这第二个例子出错了,是因为数组ch和数组arr并没有执行同一块内存空间,所以两者之间不能相减。

总结:

        1. 指针 - 指针得到的数值的绝对值:是指针和指针之间的元素个数。
        2. 指针 - 指针运算的前提条件是:指针和指针指向了同一块空间。

4.3 指针 -  指针的用途

        我们都知道strlen库函数是用来求字符串的长度的。那当我们自己模拟实现strlen函数时,大多数的小伙伴可能都是设置一个int的变量count来统计字符个数,最终求得字符串的长度。

        下面小编就来教大家怎么用指针 - 指针的方式来模拟实现strlen函数,代码如下:

#include<stdio.h>

int my_strlen(char* s)
{
	char* start = s;

	while (*s) // *s != '\0'
	{
		s++;
	}

	return s - start;

}

int main()
{
	char ch[] = "abcdef";
	int len = my_strlen(ch);

	printf("%d\n", len);

	return 0;
}

        我们只要找到字符串的末尾的地址,再减去字符串的首地址,即可得到字符串的长度。

        好了,小编今天就先讲解到这里啦,各位老铁们我们下期再见吧!

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

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

相关文章

国庆普及模拟赛-5

题目链接&#xff1a; file:///C:/Users/Administrator/Desktop/%E4%B8%8B%E5%8F%91%E6%96%87%E4%BB%B61005/20241005.pdf T1&#xff1a; 题目分析&#xff1a;不需要进行模拟&#xff0c;想要获得分数最大化&#xff0c;只需要将大的数据相加&#xff0c;再减去小的数据。 …

AD7606 ADC的SPI驱动——FPGA学习笔记17

素材来源 米联客 一、AD7606简介 功能框图&#xff1a; 转换控制时序&#xff1a; AD7606 支持 2 种时序转换&#xff0c; 由于我们采用的时串行 SPI 模式&#xff0c; 本身 SPI 读取数据就会耽误很多时间&#xff0c; 所以必须采用第二种工作时序&#xff0c; 才…

呆仔君最新可用版本及作废版本说明截止日期10.5

呆仔君最新可用版本及作废版本说明 当前最新可用版本为 5.0 及以上版本。 截至今天&#xff0c;最新版本为 5.3。本次 5.3 版本的更新功能如下&#xff1a; 新增清悦阁&#xff08;用于搜歌&#xff09;新增手绘功能新增语音合成&#xff08;包括卢本伟、刘华强、特朗普等人物…

[大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠

[大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠 目录 文章目录 [大语言模型-论文精读] 更大且更可指导的语言模型变得不那么可靠目录0. 摘要1. 核心内容3. 创新点4. 算法模型5. 实验效果6. 重要数据与实验结论7. 推荐阅读指数&#xff1a;8. 推荐理由 后记 论文…

【Java】—— 集合框架:Collections工具类的使用

目录 7. Collections工具类 7.1 常用方法 7.2 举例 7.3 练习 7. Collections工具类 参考操作数组的工具类&#xff1a;Arrays&#xff0c;Collections 是一个操作 Set、List 和 Map 等集合的工具类。 7.1 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序…

超声波清洗机什么牌子值得入手?推荐四款入手不亏的眼镜清洗机

在当今这个注重细节完美的时代&#xff0c;超声波清洗机凭借其卓越的清洁效率、深层渗透力及细腻的清洗效果&#xff0c;迅速赢得了家庭与专业场景的青睐。无论是精细的珠宝、眼镜框&#xff0c;还是金属装饰品、电子设备乃至医疗器具&#xff0c;超声波技术都能精准祛除隐秘处…

汇编语言笔记2

7.MASM,NASM,ATT,ARM的介绍 MASM:Windows下编译汇编指令的软件,可以在DOSBox下运行 NASM:优化版的MASM,主要用于Linux操作系统 ATT:Linux默认的汇编风格(但不友好) ARM:非PC(IOT设备)的汇编,比如写51单片机打开keil4的界面可以看到ARM 8.汇编 C语言 C 之间的关系 发展历程…

45集 ESP32 ADC按键程序编写

45集 ESP32 ADC按键程序编写 参考例程是 D:\Espressif\esp-adf\examples\checks\check_board_buttons 1、config 这个向下兼容的要加上&#xff0c;如果不加会有错误。 CONFIG_FREERTOS_ENABLE_BACKWARD_COMPATIBILITYy 2、程序里面引入如下头文件 #include “periph_adc_but…

Python+Matplotlib可视化y = e^(1/x)函数

可视化y e^(1/x)函数&#xff1a; import numpy as np import matplotlib.pyplot as pltplt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] Falsefig, ax plt.subplots(figsize(12, 8))def e_to_1_over_x(x):return np.where(x ! 0, np.exp(1/x), …

C初阶(十二)do - while循环 --- 致敬革命烈士

大家国庆看阅兵仪式和天安门升旗仪式了吗&#xff1f;岁月安好&#xff0c;只因有人负重前行。 ————山那边是什么 ————是烈士的英魄 ————是他们拼死保卫的新中国 ————河那边是什么 ————是绵延的战火 ————她望着远方泪一滴滴的落 ————和平来了 ——…

Arduino UNO R3自学笔记20 之 Arduino如何测定电机速度?

注意&#xff1a;学习和写作过程中&#xff0c;部分资料搜集于互联网&#xff0c;如有侵权请联系删除。 前言&#xff1a;在学习了Arduino的相关基础知识后&#xff0c;现在做个综合应用&#xff0c;给旋转的电机测速。 1.实验目的 测定旋转电机的转速。 2.实验器材-编码器 …

比较搜索难度曲线5s1-4和4s1

在行列可自由变换的条件下&#xff0c;平面上的5点结构只有34个,4点结构有16个 (A,B)---6*n*2---(0,1)(1,0) 让B全是0。当收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值。让隐藏层节点数n分别为10&#xff0c;15&#xff0c;20&#xff0c;25&#xff0c;30&#xff…

一些关于上传数据-p7zip-full-压缩包的经验

目录 前言 7z 简介 Windows如何压缩tar.gz格式 一、下载7-ZIP 二、tar文件进一步压缩 说明&#xff1a; 前言 本人每次在linux服务器上执行apt-get install p7zip-full命令&#xff0c;都会有复杂依赖报错&#xff08;因为实验过程中用到的依赖包太多了&#xff09;&…

今日指数项目个股周K线功能实现

个股周K线功能实现 1 个股周K线功能实现功能分析 1&#xff09;个股周K线功能原型分析 2&#xff09;个股周K线功能接口分析 个股周K线数据主要包含&#xff1a; 股票ID、 一周内最高价、 一周内最低价 、周1开盘价、周5的收盘价、 整周均价、以及一周内最大交易日期&#x…

【Linux】-----进程第二弹(优先级,环境变量)

目录 一、进程优先级 是什么 为什么要有&#xff1f; 查看进程优先级 修改进程优先级 二、环境变量 命令行参数 概念 常见环境变量 查看环境变量 配置环境变量 内存级别修改&#xff08;命令行修改&#xff0c;暂时&#xff09; ①拷贝到系统路径下 ② 路径添加…

【Android】中级控件

其他布局 相对布局RelativeLayout RelativeLayout下级视图的位置是相对位置&#xff0c;得有具体的参照物才能确定最终位置。如果不设定下级视图的参照物&#xff0c;那么下级视图默认显示在RelativeLayout内部的左上角。用于确定视图位置的参照物分两种&#xff0c;一种是与…

算法专题三: 二分查找

目录 1. 朴素版: 二分查找2. 查找排序数组元素第一个和最后一个位置3. 搜索插入位置4. x的平方根5. 山脉数组的峰顶索引6. 寻找旋转数组中的最小值7. 点名 博客主页: 酷酷学!!! 感谢您的关注~ 正文开始 1. 朴素版: 二分查找 题目思路: 仅需根据题意, 找出二段性, 正确更新下标…

Python编码系列—Python访问者模式:为对象结构添加新功能的艺术

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

LLM端侧部署系列 | PowerInfer-2助力AI手机端侧部署47B大模型 (论文解读)

引言 简介 PowerInfer-2 概述 神经元感知的运行时推理 多态神经元引擎 内存中的神经元缓存 灵活的神经元加载 Neuron-Cluster-Level Pipeline 生成执行计划 执行 总结 0. 引言 一雨池塘水面平&#xff0c;淡磨明镜照檐楹。东风忽起垂杨舞&#xff0c;更作荷心万点声…

2024年liunx安装openvino非源码编译版(比源码编译简单!)

前言 真的要感慨一句&#xff0c;openvino源码编译真的麻烦&#xff01;由于2023年之后openvino官网的之间下载取消之后&#xff0c;很多人只能选择源码编译&#xff0c;我也是研究了好几天&#xff0c;又是clone改变的库&#xff0c;又是安装什么&#xff0c;搞了三四天都没有…