【C语言】善于利用指针(一)

news2025/1/4 19:36:03

💗个人主页💗

⭐个人专栏——C语言初步学习⭐

💫点击关注🤩一起学习C语言💯💫


目录

导读:

1. 什么是指针

1.1 概念

1.2 图解

 1.3 示例

2. 指针和指针类型

2.1 指针的定义

2.2 指针的解引用

3. 野指针

3.1 野指针成因

3.2 如何规避野指针

4. 指针运算

4.1 指针+-整数

 ​编辑

 4.2 指针-指针

5. 指针和数组

5.1 数组指针

5.2 数组元素的访问

6. 二级指针

博主有话说:


导读:

经过前面的学习,我们已经了解了分支结构、循环结构、数组和函数的使用

还包括动态内存分配和柔性数组

 今天我们来学习指针的第一部分,主要学习指针的类型和基本用法

1. 什么是指针

指针是C语言中的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用它,可以使程序简洁、紧凑、高效。每一个学习和使用C语言的人,都应该深入的学习和掌握指针。可以说,不掌握指针就是没有掌握C语言的精华。

1.1 概念

指针理解的2个要点:

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

 总结:指针就是地址,口语中说的指针通常指的是指针变量。

1.2 图解

可以理解为: 

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

 1.3 示例

int main()
{
	int a = 10;//在内存中开辟一块空间
	int* p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
	//a变量占用4个字节的空间,
	//这里是将a的4个字节的第一个字节的地址存放在p变量中,
	//p就是一个之指针变量。
	return 0;
}

我们来进入调试看一看

我们发现,p存的就是a的地址,对p解引用得到的就是该地址所指向的内存空间的内容

总结:

  • 指针是用来存放地址的,地址是唯一标示一块地址空间的。
  • 指针的大小在32位平台是4个字节,在64位平台是8个字节。

2. 指针和指针类型

2.1 指针的定义

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

准确的说:有的。

int num = 10;
 p = #

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢? 我们给指针变量相应的类型。

char  *pc = NULL;

int   *pi = NULL;

short *ps = NULL;

long  *pl = NULL;

float *pf = NULL;

double *pd = NULL; ‘

指针的定义方式是:

type + *

  • int 表示指向整型变量的指针
  • double* 表示指向双精度浮点型变量的指针
  • char* 表示指向字符型变量的指针

 需要注意的是,指针类型并不决定指针变量所指向内存地址的类型,而是决定了指针变量对指向的内存地址所存储的值的解释方式。

例如:

一个int类型的指针变量可以指向一个double类型的变量,但这样会导致解释的错误。

因此,指针类型的指定应该与指针变量所指向的变量类型相同,以确保正确的解释和使用。

2.2 指针的解引用

指针的解引用是指通过指针变量访问其所指向的变量的值。

在C++中,可以使用星号(*)来解引用指针变量,例如:

int main()
{
	int x = 10;
	int* ptr = &x;   // ptr指向x的地址
	printf("%d\n", *ptr); //输出10
	*ptr = 20;       // 将ptr指向的值改为20
	printf("%d\n", *ptr); // 输出20
	return 0;
}

 

在上述代码中,ptr指向变量x的地址,可以使用星号()来解引用ptr,访问x的值。

在第一次输出时,输出了x的初始值10,然后使用星号()将ptr解引用,输出了x的值。

在第二次输出时,输出的是x被修改后的值20。

3. 野指针

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

3.1 野指针成因

1. 指针未初始化

对未初始化的指针进行解引用是一种未定义的行为,会导致程序崩溃或产生随机结果,因此在使用指针前一定要确保其被正确初始化。

int main()
{
	int* p;//局部变量指针未初始化,默认为随机值
	*p = 20;
	printf("%d\n", *p);
	return 0;
}

 

并不能成功运行。

2. 指针越界访问 

指针越界访问是指程序试图访问超出指针所指向的内存空间范围的地址,这也是一种常见的编程错误。

指针越界访问可能会导致程序崩溃、数据被破坏、安全漏洞等问题。这种错误很难检测和调试,因为错误不一定会立即引起程序崩溃,而且错误的结果也不一定与越界访问的代码行直接相关。

 

int main()
{
    int arr[10] = { 0 };
    int* p = arr;
    int i = 0;
    for (i = 0; i <= 11; i++)
    {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
    }
    for (i = 0; i <= 11; i++)
    {
        printf("%d ", *(p++) = i);
    }
    return 0;
}

虽然运行成功,但是依旧是错误的

3. 指针指向的空间释放

int main() 
{
    int* p = (int*)malloc(sizeof(int)); // 分配一个 int 类型的内存块,返回指向该内存块的指针
    if (p == NULL) 
    {
        printf("分配内存失败!\n");
        return -1;
    }
    *p = 10; // 给指针所指向的内存块赋值
    printf("p 指向的值为:%d\n", *p);
    free(p); // 释放指针所指向的内存块
    printf("p 指向的值为:%d\n", *p); 
    // 这里会出现错误,因为指针所指向的内存块已被释放
    return 0;
}

3.2 如何规避野指针

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放即使置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

例如:

int main()
{
    int* p = NULL;
    //....
    int a = 10;
    p = &a;
    if (p != NULL)
    {
        *p = 20;
    }
    return 0;
}

4. 指针运算

指针+- 整数

指针-指针

指针的关系运算

4.1 指针+-整数

int main()
{
	int n = 10;
	char* pc = (char*)&n;//强转char*
	int* pi = &n;
	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc + 1);
	printf("%p\n", pi);
	printf("%p\n", pi + 1);
	return  0;
}

 

 我们可以看到,都是加1,但是结果却不一样,而这就是与指针的类型有关了

一个int类型占4个字节,int + 1自然就是加四个字节

 一个char类型占一个字节,char + 1也是加一个字节

总结:

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

 4.2 指针-指针

int main()
{
	int arr[5] = { 1, 2, 3, 4, 5 };
	int* p1 = &arr[1]; // 指向 arr[1] 的指针
	int* p2 = &arr[4]; // 指向 arr[4] 的指针
	printf("p2 - p1 = %ld\n", p2 - p1); 
	// 输出 p1 和 p2 之间的距离
	return 0;
}

5. 指针和数组

5.1 数组指针

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与数组

所以我们可以这样定义一个数组指针

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址

5.2 数组元素的访问

引用数组元素可以用下标法,也可以用指针法

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("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
    }
    return 0;
}

所以我们就可以如下进行访问:

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

 

6. 二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?

这就是二级指针

int main() 
{
    int num = 10;
    int* p = &num;
    int** pp = &p;

    return 0;
}

对于二级指针的运算有:

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

博主有话说:

今天有关指针的初步学习就到这里,更多关于指针的学习关注博主,掌握最新消息

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

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

相关文章

Kubernetes Deployment的运行

Deployment提供了一种更加简单的更新Replication Controller和Pod的机制&#xff0c;更好地解决了Pod的编排问题。本节将详细介绍如何通过Deployment实现Pod的管理。 15.1.1 什么是Deployment Deployment的中文意思为部署、调集&#xff0c;它是在Kubernetes的1.2版本中新增…

【kubernetes】基于prometheus的监控

目录 1 监控解决方案2 prometheus2.1 容器监控2.2 节点监控2.3 资源对象监控2.4 metrics--server 3 prometheus-operator vs kube-prometheus vs helm3.1 prometheus-operator3.2 kube-prometheus3.3 helm 参考文档 1 监控解决方案 从实现方案来说&#xff0c;监控分为3个部分…

计算机网络基础(二):物理层、数据链路层及网络层

一、物理层 1.物理层 物理层面的通信标准可以概括划分为与网络基础设施有关的标准和与被传输物理信号有关的标准两类。 网络基础设施的标准&#xff1a;鉴于物理层面的消息互通也是物理层应该兑现的服务&#xff0c;因此物理层的标准还会包括针脚的用途、线缆的材料与设计等…

vertx的学习总结7之用kotlin 与vertx搞一个简单的http

这里我就简单的聊几句&#xff0c;如何用vertx web来搞一个web项目的 1、首先先引入几个依赖&#xff0c;这里我就用maven了&#xff0c;这个是kotlinvertx web <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apac…

华为云云耀云服务器L实例评测|基于canal缓存自动更新流程 SpringBoot项目应用案例和源码

前言 最近华为云云耀云服务器L实例上新&#xff0c;也搞了一台来玩&#xff0c;期间遇到各种问题&#xff0c;在解决问题的过程中学到不少和运维相关的知识。 在之前的博客中&#xff0c;介绍过canal的安装和配置&#xff0c;参考博客 拉取创建canal镜像配置相关参数 & …

【数据库——MySQL】(14)过程式对象程序设计——游标、触发器

目录 1. 游标1.1 声明游标1.2 打开游标1.3 读取游标1.4 关闭游标1.5 游标示例 2. 触发器2.1 创建触发器2.2 修改触发器2.3 删除触发器2.4 触发器类型2.5 触发器示例 参考书籍 1. 游标 游标一般和存储过程一起配合使用。 1.1 声明游标 要使用游标&#xff0c;需要用到 DECLAR…

<C++> String

目录 一、标准库中的string类 1. string类 2. string类的常用接口说明 2.1 string类对象的常见构造 2.2 string类对象的容量操作 2.3 string类对象的访问及遍历操作 2.4 string类对象的修改操作 2.5 string类非成员函数 总结 前言 C语言中&#xff0c;字符串是以 \0 结尾的一些…

用JMeter对HTTP接口进行压测(一)压测脚本的书写、调试思路

文章目录 安装JMeter和Groovy为什么选择Groovy&#xff1f; 压测需求以及思路准备JMeter脚本以及脚本正确性验证使用Test Script Recorder来获取整条业务线上涉及的接口为什么使用Test Script Recorder&#xff1f; 配置Test Script Recorder对接口进行动态化处理处理全局变量以…

2. 资源管理

2. 资源管理 文章目录 2. 资源管理2.1 资源管理介绍2.2 YAML语言介绍2.3 资源管理方式2.2.1 命令式对象管理2.2.2 命令式对象配置2.2.3 声明式对象配置 2.4. 模拟使用普通用户来操作 2.1 资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通…

二十九、【进阶】MySQL索引的概述和索引查询

1、索引概述 2、 普通查询和索引查询 &#xff08;1&#xff09;基础演示 无索引查询&#xff1a;在查询信息时&#xff0c;比如查询年龄age45的员工&#xff0c;系统会遍历字段为age的列&#xff0c;在找到age45的员工后&#xff0c;依旧会向下扫描&#xff0c;直到表末&…

如何使用 Dijkstra 算法找到从源到所有顶点的最短路径--附C++/Java源码

给定一个图和图中的源顶点,找到从源到给定图中所有顶点的最短路径。 例子: 输入: src = 0,图形如下图所示。 输出: 0 4 12 19 21 11 9 8 14解释:从 0 到 1 的距离 = 4。 从 0 到 2 的最小距离 = 12。0->1->2 从 0 到 3 的最小距离 = 19。0 ->1-

Python基础语法(3)

目录 一、函数 1.1 函数是什么 1.2 函数语法格式 1.3 函数参数 1.4 函数返回值 a. 一个函数中可以有多个 return 语句 b. 执行到 return 语句&#xff0c;函数就会立即执行结束&#xff0c;回到调用位置 c. 一个函数是可以一次返回多个返回值的。使用 , 来分割多个返回值…

Jmeter基础篇

1.性能测试指标 【虚拟用户数】&#xff1a;线程用户 【并发数】&#xff1a;指在某一时间&#xff0c;一定数量的虚拟用户同时对系统的某个功能进行交互&#xff0c;一般通过集合点实现 【事务】:事务代表一个完整的功能&#xff0c;一个接口可以是事务&#xff0c;多个接口…

MyBatisPlus(十一)包含查询:in

说明 包含查询&#xff0c;对应SQL语句中的 in 语句&#xff0c;查询参数包含在入参列表之内的数据。 in Testvoid inNonEmptyList() {// 非空列表&#xff0c;作为参数List<Integer> ages Stream.of(18, 20, 22).collect(Collectors.toList());in(ages);}Testvoid in…

【C语言】转圈报数问题(三种方法--指针,数组)

题目&#xff1a;有n个人围成一圈&#xff0c;顺序排号。从第一个人开始报数&#xff08;从1到3报数&#xff09;&#xff0c;凡报到3的人退出圈子&#xff0c;问最后留下的是原来第几号的那位。 方法一&#xff1a; #include <stdio.h> #define N 10int main() {int …

systemverilog function的一点小case

关于function的应用无论是在systemverilog还是verilog中都有很广泛的应用&#xff0c;但是一直有一个模糊的概念困扰着我&#xff0c;今天刚好有时间来搞清楚并记录下来。 关于fucntion的返回值的问题&#xff1a; function integer clog2( input logic[255:0] value);for(cl…

实验三十五、LM117 稳压电源的设计

一、题目 利用 LM117 设计一个稳压电路&#xff0c;要求输出电压的调节范围为 5 ∼ 20 V 5\sim20\,\textrm V 5∼20V&#xff0c;最大负载电流为 400 mA 400\,\textrm{mA} 400mA。利用 Multisim 对所设计电路进行仿真&#xff0c;并测试所有性能指标。 二、仿真电路 仿真电…

安装NodeJS并使用yarn下载前端依赖

文章目录 1、安装NodeJS1.1 下载NodeJS安装包1.2 解压并配置NodeJS1.3 验证是否安装成功2、使用yarn下载前端依赖2.1 安装yarn2.2 使用yarn下载前端依赖参考目标:在Windows下安装新版NodeJS,并使用yarn下载前端依赖,实现运行前端项目。 1、安装NodeJS 1.1 下载NodeJS安装包…

Vue中实现自定义编辑邮件发送到指定邮箱(纯前端实现)

formspree里面注册账号 注册完成后进入后台新建项目并且新建表单 这一步完成之后你将得到一个地址 最后就是在项目中请求这个地址 关键代码如下&#xff1a; submitForm() {this.fullscreenLoading true;this.$axios({method: "post",url: "https://xxxxxxx…

【python海洋专题十一】colormap调色

【python海洋专题十一】colormap调色 上期内容 本期内容 图像的函数包调用&#xff01; Part01. 自带颜色条Colormap 调用方法&#xff1a; cmap3plt.get_cmap(ocean)查询方法&#xff01; Part02. seaborn函数包 01&#xff1a;sns.cubehelix_palette cmap5 sns.cu…