【C语言】初阶指针详解

news2024/11/22 17:28:32

目录

一、什么是指针?

1.指针变量 

2.指针大小

二、指针类型

三、野指针

四、指针运算

1.指针+-整数

2.指针-指针 

3.指针的关系运算

五、指针和数组

六、二级指针

七、指针数组


一、什么是指针?

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

说到指针,那么我们还要了解一下内存,内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节

为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。

变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。 

1.指针变量 

我们可以通过&(取地址操作符)取出变量的内存地址,把地址可以存放到一个变量中,这个
变量就是指针变量

#include<stdio.h>
int main() 
{
	int a = 10;
	int* p = &a;//&a拿到a的地址
	//注意a占用4个字节,这里只是将a的第一个字节的地址放到p变量中
	//p 是一个指针变量
	return 0;
}

指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)

2.指针大小

指针是用来存放地址的,地址是唯一标示一块地址空间的

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

这里简单地介绍一下地址线

对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0) 

00000000 00000000 00000000 00000000

00000000 00000000 00000000 00000001

...

11111111 11111111 11111111 11111111

2 ^ 32 (2的32次方 bit 转GB 是  4GB,即4G大的空间可以进行编址)

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

二、指针类型

我们知道 定义一个变量有许多 类型 有 int 、float 等。当然 指针 也是有类型的

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

 类型 *

char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址

指针类型的意义 指针类型决定解引用操作的时候,访问几个字节

指针+-整数

指针的类型决定了指针向前或者向后走一步有多大(距离)

指针的解引用

指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)

 char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

下方代码经过调试得到 执行前三行代码 

 在执行一行得到

这里就可以看到解引用不同权限的区别了

三、野指针

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

造成野指针的原因

1.指针未初始化

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

2.指针越界访问

#include <stdio.h>
int main()
{
  int arr[10] = {0};
  int *p = arr;
  int i = 0;
  for(i=0; i<=11; i++)
 {
    //当指针指向的范围超出数组arr的范围时,p就是野指针
    *(p++) = i;
 }
  return 0;
}

*(p++)  先解引用在++,可以改为 *p  = i; p++;

在这里指针越界访问,不能访问不属于你的空间。

3.指针指向的空间释放

那木我们如何避免野指针呢?

  • 指针要初始化
  • 小心指针越界
  • 指针指向空间释放 使其置 为 NULL
  • 避免返回局部变量的地址
  • 指针使用之前检查有效性
//检查有效性
#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	int i = 0;
	for (i = 0; i <= 11; i++)
	{
		//当指针指向的范围超出数组arr的范围时,p就是野指针
		*(p++) = i;
	}
	return 0;
}

四、指针运算

1.指针+-整数

#include<stdio.h>
int main() 
{
	int i = 0;
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* p = arr;
	for (i = 0; i < 10;i++)
	{
		printf("%d ",*p+i);
	}
	return 0;
}

2.指针-指针 

指针-指针的绝对值 是 指针与指针之间的元素个数(前提 指向同一块区域,指针的类型相同)

这里用一个模拟strlen()来进行说明

#include<stdio.h>
int my_strlen(char * str) 
{
	char* a = str;
	while (*a != '\0')
		a++;

	return a - str;
}
int main()
{
	char* p = "abcdef";
	int ret = my_strlen(p);
	printf("%d\n",ret);
	return 0;
}

 【结果】

return a - str ; //返回之间的元素个数(即字符的个数) 

3.指针的关系运算

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

五、指针和数组

#include <stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

我们发现 数组名  和  数组首元素地址 是一样的

这里我们又会说到

数组名一般表示的是数组首元素的地址

特殊情况  sizeof(arr),&arr  表示的都是整个数组

那么 把数组名当成地址存放到一个指针中

#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;
}

执行结果

 发现一样,所以 p+i 其实计算的是数组 arr 下标为i的地址

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//            0 1 2 3 4 5 6 7 8 9
	//使用指针打印数组的内容
	int * p = arr;
	int i = 0;
	//arr-->p
	//arr == p
	//arr+i  ==  p+i
	//*(arr+i) == *(p+i) == arr[i]
	//*(arr+i) == arr[i]
	//*(i+arr) == i[arr]
	//3+5
	//5+3
	for (i = 0; i < 10; i++)
	{
		//printf("%d ", *(p + i));
		printf("%d ", *(arr + i));
		//printf("%d ", arr[i]);
		//printf("%d ", i[arr]);

		//p指向的是数组首元素
		//p+i 是数组中下标为i的元素的地址
		//p+i 起始时跳过了i*sizeof(int)个字节
	}
	return 0;
}

六、二级指针

前面我们已经了解到 指针变量 存放地址的变量,指针变量也是变量 ,那指针变量的地址放到哪?

二级指针 来 存放指针变量

 

*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa 

//**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
int b = 20;
*ppa = &b;//等价于 pa = &b;
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

七、指针数组

指针数组是 数组   ,是存放 指针的数

int*arr[5];

整型指针数组 

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

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

相关文章

MySQL_数据库的DDL语句(表的创建与修改)

DDL 数据库操作 查看当前有哪些数据库 SHOW databases;#查看哪些数据库查询当前数据库 SELECT database();创建数据库 create database [ if not exists ] 数据库名 [ default charset 字符集 ] [ collate 排序 规则 ] ;创建一个sycoder数据库, 使用数据库默认的字符集 CREATE…

retrofit-helper 简洁的封装retrofit,优雅的取消请求

retrofit-helper Retrofit是很多android开发者都在使用的Http请求库&#xff01;他负责网络请求接口的封装,底层实现是OkHttp,它的一个特点是包含了特别多注解&#xff0c;方便简化你的代码量,CallAdapter.Factory 和Converter.Factory可以很灵活的扩展你的请求。我们在使用的…

“崩溃”漏洞会影响英特尔 CPU 的使用寿命,可能会泄露加密密钥等

对于 CPU 安全漏洞来说&#xff0c;本周是重要的一周。昨天&#xff0c;不同的安全研究人员发布了两个不同漏洞的详细信息&#xff0c;一个影响多代英特尔处理器&#xff0c;另一个影响最新的 AMD CPU。“ Downfall ”和“ Inception ”&#xff08;分别&#xff09;是不同的错…

CEC2013(MATLAB):能量谷优化算法EVO求解CEC2013的28个函数

一、能量谷优化算法EVO 能量谷优化算法&#xff08;Energy valley optimizer&#xff0c;EVO&#xff09;是MahdiAzizi等人于2023年提出的一种新颖的元启发式算法&#xff0c;其灵感来自关于稳定性和不同粒子衰变模式的物理原理。能量谷优化算法&#xff08;Energy valley opt…

AI时代的较量,MixTrust能否略胜一筹?

人工智能的能力正在迅速接近人类&#xff0c;而在许多细分领域&#xff0c;已经超越了人类。虽然短期内这个突破是否会导致人工通用智能&#xff08;AGI&#xff09;还不清楚&#xff0c;但我们现在有的模型被训练成在数字交互中完美地模仿高能人类。尽管AGI仍不确定&#xff0…

时序预测 | MATLAB实现CNN-BiGRU-Attention时间序列预测

时序预测 | MATLAB实现CNN-BiGRU-Attention时间序列预测 目录 时序预测 | MATLAB实现CNN-BiGRU-Attention时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLAB实现CNN-BiGRU-Attention时间序列预测&#xff0c;CNN-BiGRU-Attention结合注意力机制时…

Java课题笔记~ Request请求

1.请求消息格式 客户端发送一个HTTP请求到服务器的请求消息包括以下格式&#xff1a; 请求行&#xff08;request line&#xff09;、请求头部&#xff08;header&#xff09;、空行和请求数据四个部分组成。下图给出了请求报文的一般格式。 GET请求&#xff1a; POST请求&am…

每日一学——OSI参考模型

OSI参考模型&#xff08;Open Systems Interconnection Reference Model&#xff09;是国际标准化组织&#xff08;ISO&#xff09;制定的一个网络通信协议的概念框架。它将网络通信划分为七个层次&#xff0c;每个层次负责不同的功能和任务&#xff0c;从物理层到应用层依次为…

【ThreadPoolTaskSchedule】实现手动开启关闭定时任务

最近在公司呢&#xff0c;有一个需求&#xff0c;大概意思就是需要我去调用远程接口&#xff0c;但如果出现异常或者响应失败的时候&#xff0c;就需要开启重试机制&#xff0c;直到返回成功的响应为止。我很疑惑&#xff0c;按理说这种情况通常都应该有一个最大重试次数吗&…

python编程英语词汇大全app,python常用单词中英对照

大家好&#xff0c;小编为大家解答python编程英语词汇大全 知乎的问题。很多人还不知道python编程英语词汇大全app&#xff0c;现在让我们一起来看看吧&#xff01; 第1天 editor[edtr]n. 编者&#xff0c;编辑&#xff1b;社论撰写人&#xff1b;编辑装置 setting[set]n. 环境…

《爬虫》爬取页面图片并保存

爬虫 前言代码效果 简单的爬取图片 前言 这几天打算整理与迁移一下博客。因为 CSDN 的 Markdown 编辑器很好用 &#xff0c;所以全部文章与相关图片都保存在 CSDN。而且 CSDN 支持一键导出自己的文章为 markdown 文件。但导出的文件中图片的连接依旧是 url 连接。为了方便将图…

封装一个常用的Enum

前言 项目里面经常用到一些下拉框 尝试封装一个比较好用的Enum 文件目录 ├── utils.ts ├── index.txs └── package.josn代码 utils.ts class Enum {static keys: string[];static values: Enum[];/*** call this function after declare all staic enum variable*…

【效率提升-Perl脚本】根据Verilog文件自动生成tb文件

文章目录 Verilog端口文件&#xff08;仅做示范用&#xff09;对应的tb文件相应代码 在数字IC设计过程中&#xff0c;根据顶层生成testbench时存在很多重复性工作&#xff0c;因此为了提高工作效率&#xff0c;特地开发此脚本。 相应的python脚本见链接&#xff1a; 【效率提升…

跨境商城app源代码开发--Java、H5用户端

随着全球电子商务的快速发展&#xff0c;跨境贸易已经成为一种新的商业趋势。在这个背景下&#xff0c;开发一个跨境商城APP&#xff0c;提供一站式跨境贸易服务&#xff0c;具有非常重要的意义。本文将详细阐述使用Java和H5技术进行跨境商城APP用户端源代码开发的步骤。 一、…

帮源头厂家“跑市场、谈终端、拿订单” 郑州:找准发力点,入局“预制菜”

过去5年&#xff0c;国内预制菜行业大火&#xff0c;复合增速高达95%&#xff0c;全国相关企业逼近6万家&#xff0c;面对这盘万亿级的大棋&#xff0c;郑州近日终于出招了&#xff0c;而且&#xff0c;一出就是大招—— 经相关部门批准&#xff0c;位于郑东新区的“郑菜直供园…

学C的第三十三天【C语言文件操作】

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十二天【动态内存管理】_高高的胖子的博客-CSDN博客 1 . 为什么要使用文件 以前面写的通讯录为例&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删…

LeetCode 1572. 矩阵对角线元素的和

【LetMeFly】1572.矩阵对角线元素的和 力扣题目链接&#xff1a;https://leetcode.cn/problems/matrix-diagonal-sum/ 给你一个正方形矩阵 mat&#xff0c;请你返回矩阵对角线元素的和。 请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。 示例 1&…

JDK1.8 jvisualvm远程连接linux服务器tomcat8

JDK1.8 jvisualvm远程连接linux服务器tomcat jvisualvm工具 1、 可以通过官网单独下载 2、 JDK安装的bin路径下Java VisualVM.exe应用程序打开软件截图 linux服务器上tomcat8配置 只需要修改tomcat8 bin目录下的catalina.sh文件在catalina.sh文件添加以下信息 注意IP地址为…

PPO和文本生成

策略梯度 策略梯度&#xff08;Policy Gradient&#xff09;方法梯度的计算如下&#xff1a; E ( a t , s t ) ∈ π θ [ A ^ t ∇ θ log ⁡ π θ ( a t ∣ s t ) ] \mathbb E_{(a_t,s_t) \in \pi_\theta}[\hat A_t \nabla_ \theta \log \pi_\theta(a_t | s_t)] E(at​,st…

了解IL汇编跳转语句

il代码&#xff0c; .assembly extern mscorlib {}.assembly Test{.ver 1:0:1:0}.module test.exe.method static void main() cil managed{.maxstack 5.entrypointldstr "Enter First Number"call void [mscorlib]System.Console::WriteLine (string)call string …