C语言指针·入门用法超详解

news2024/11/26 12:34:10

目录

1.  什么是指针

2.  指针变量的定义格式

3.  指针的作用

3.1  查询数据

3.2  存储数据(修改数据)

3.3  操作其他函数中的变量

 3.4  函数返回多个值

3.5  函数的结果和计算状态分开


1.  什么是指针

        通过内存地址,指向的空间,我们可以对空间的数据进行修改,而这个内存地址就被称为指针

        在代码当中,我们会拿一个变量将指针进行存起来,那么这个变量就叫做指针变量

        通常情况下,我们会将指针变量,称为指针,但我们需要了解,真正的指针,实际上是指针变量存起来的内存地址

2.  指针变量的定义格式

        指针变量起始就是存着指针的变量,本身也是变量,而我们变量的定义格式是:

数据类型  变量名;

        但如果我们要是这样声明指针变量,那么就无法和普通变量做一个区分,因此我们将指针的数据类型和变量名之间加一个“*”进行区分:

数据类型  *  变量名;

        对于指针变量的数据类型要跟指向的变量类型保持一致,例如:

int a =10;
int* p1=&a;

double b = 10;
double* p2 =&b;

        对于指针变量的*可以理解为这是一个标记,见到*我们可以理解为此时声明的变量为指针变量,他右面声明的变量名,所存储的是内存地址,例如以上代码的p1,p2。

        对于指针变量的变量名,就是字节起的名字,可随意取,但是需要避开关键字。

3.  指针的作用

3.1  查询数据

格式:*指针名

其中*在这里是解引用运算符

        首先我们创建如下代码:

int a =10;         //①
int* p=&a;         //②

printf("%d\n",*p); //③

*p=200;           //④

printf("%d\n",*p); //⑤

        对于①我们可以理解为,在一个内存当中存储一个变量,这个变量的数据为10,下面我们假设这个数据存储的内存地址位0x0011:

        对于②我们可以理解为,我获取了变量a的地址,在存储到指针p当中,指针p可以通过内存地址指向了变量a:

        对于③中的*p,我们直到此时的p代表地址0x0011,而*p代表通过内存地址获取改地址下变量数据的意思,因此此时输出的数据为10;

注意:这里会有人将指针变量格式的*和解引用运算符的*混淆:

指针变量格式的定义指针的*,仅仅作为标记使用,告诉你*右边的变量记录的是内存地址;

而查询数据里面的是解引用运算符,他表示通过后面的内存地址去获取到对应的数据。

3.2  存储数据(修改数据)

格式:*指针名 = 数据值;

        对于④,我们可以理解为修改改地址下的数据,及此时0x0011下的数据会从10变为200:

        完整代码:

#include <stdio.h>

int main()
{
	int a = 10;

	//定义一个指针变量a
	int* p = &a;

	//利用指针获取变量中的数据
	printf("%d\n", *p);

	//利用指针去存储数据/修改数据
	*p = 200;

	//输出打印
	printf("%d\n", a);
	printf("%d\n", *p);

}

指针使用细节:

(1)指针变量的名字,例如int*  p需要分开;

(2)指针变量的数据类型要跟指向的变量的类型保持一致;

(3)指针变量占用的大小,跟数据类型无关,跟编译器有关,32位的是4字节,64位的是8字节。对于这里我们可以看一下:C++学习之指针-CSDN博客的1.3中的介绍;

(4)给指针变量赋值的时候,不能把一个数值赋值给指针变量。例如下图右侧,因为对于500编译器并未分配该空间的内存地址,要是将其赋值给p编译器会报错。

3.3  操作其他函数中的变量

        在使用,指针变量前,我们先来了解一下普通变量的值传递,编写代码:

#include <stdio.h>

void swap(int num1, int num2);

int main()
{
	//定义两个变量,要求交换变量中记录的值
	//注意:交换的代码写在一个新的函数swap中

	//定义两个变量
	int a = 10;
	int b = 20;

	//调用swap函数
	printf("调用前:%d,%d\n", a, b);
	swap(a, b);
	printf("调用后:%d,%d\n", a, b);

	return 0;

}

void swap(int num1, int num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

        该段代码主要想要实现的功能是:定义两个变量,要求交换变量中记录的值,但是我们会发现调用了交换变量的函数,但是a和b的值并未发生转换,那是因为上面这段函数,仅仅是将a和b的值赋值给了num1和num2:

        变量之间值的交换也仅仅是num1和num2值的交换,根本就没有修改a和b的值:

        因此最终输出的结果会是:

        那么我们如何实现不同函数之间,值的修改呢?

        这里我们就可以使用指针变量的功能,修改代码:

#include <stdio.h>

void swap(int* p1, int* p2);

int main()
{
	//定义两个变量,要求交换变量中记录的值
	//注意:交换的代码写在一个新的函数swap中

	//定义两个变量
	int a = 10;
	int b = 20;

	//调用swap函数
	printf("调用前:%d,%d\n", a, b);
	swap(&a, &b);
	printf("调用后:%d,%d\n", a, b);

	return 0;
}

void swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

        这里我们可以理解为swap(&a,&b)是将a和b的内存地址,也就是指针指向的变量作为参数p1和p2,通过指针操作,将p1指向的值和p2指向的值进行交换,实现了变量值的交换:


注意:

        函数中的变量的生命周期跟函数相关,函数结束消失,变量也会消失,此时在其他函数中,就无法通过指针使用了:

#include <stdio.h>

int* method();

int main()
{
	//调用method函数,并使用该函数的变量a
	int* p = method();

	printf("%d\n",*p);

	return 0;
}

int* method()
{
	int a = 10;
	return &a;
}

        此时运行我们会发现:

        为什么,不是说函数结束消失,变量也会消失吗?这是一个偶然发生的概念,那是因为我们执行完 int* p = method(); 并没有别的代码执行,此时这一块内存还没来得及被回收,所以此时还能使用到变量a,那我们就在该段指令后拖点时间多执行几条指令:

#include <stdio.h>

int* method();

int main()
{
	//调用method函数,并使用该函数的变量a
	int* p = method();

	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");

	printf("%d\n",*p);

	return 0;
}

int* method()
{
	int a = 10;
	return &a;
}

        会发现:

        如果不想函数中的变量被回收,可以在变量前加static关键字:

#include <stdio.h>

int* method();

int main()
{
	//调用method函数,并使用该函数的变量a
	int* p = method();

	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");
	printf("拖点时间\n");

	printf("%d\n",*p);

	return 0;
}

int* method()
{
	static int a = 10;
	return &a;
}


 3.4  函数返回多个值

        老样子,我们下不使用指针看看如何实现:

#include <stdio.h>


//函数返回多个值
int main()
{
	//定义一个函数,求数组的最大值和最小值,并进行返回


	return 0;
}

void getMaxAndMin(int arr[], int len)
{
	//求数组的最大值
	int max = arr[0];

	for (int i = 0; i < len; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}

	//求数组的最小值
	int min = arr[0];

	for (int i = 0; i < len; i++)
	{
		if (arr[i] < min)
		{
			min = arr[i];
		}
	}

	int res[] = { max,min };
	return res;
}

        我们正常情况下,一个函数只能返回一个值,而若是我们想要返回多个值,我们可以如上代码,创建一个数组,将想要返回的值全部保存到数组内,不过这样会出现,若是别人想要调用你这个函数,还要读懂你这个函数,了解你这个函数的返回值,每一位都代表什么,比较麻烦,那么如何更简便一些呢?

        我们可以直接使用指针操控该内存地址的值,进行修改变量,达到返回值的目的:

#include <stdio.h>

void getMaxAndMin(int arr[], int len, int* max, int* min);

//函数返回多个值
int main()
{
	//定义一个函数,求数组的最大值和最小值,并进行返回

	//定义数组
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int len = sizeof(arr) / sizeof(arr[0]);

	//调用getMaxAndMin求最大值和最小值
	int max = arr[0];
	int min = arr[0];

	getMaxAndMin(arr, len, &max, &min);

	printf("数组最大值为:%d\n", max);
	printf("数组最小值为:%d\n", min);

	return 0;
}

void getMaxAndMin(int arr[], int len, int* max, int* min)
{
	//求数组的最大值
	*max = arr[0];

	for (int i = 0; i < len; i++)
	{
		if (arr[i] > *max)
		{
			*max = arr[i];
		}
	}

	//求数组的最小值
	*min = arr[0];

	for (int i = 0; i < len; i++)
	{
		if (arr[i] < *min)
		{
			*min = arr[i];
		}
	}
}

        其中,如何求len可以参考2.2.1:C++学习之数组-CSDN博客

3.5  函数的结果和计算状态分开

        继续我们先编写一个小例子:

#include <stdio.h>

//函数的结果和计算状态分开
int main()
{
	//定义一个函数,将两个数相除,获取他们的余数



	return 0;
}

int getRemainder(int num1, int num2)
{
	if (num2 == 0)
	{
		return ???;
	}

	int res = num1 % num2;
	return res;
}

        首先,定义一个函数,将两个数相除,获取他们的余数,然后return 返回值res,但是这就会出现一个问题,若是num2==0,那么等式将会不成立,那么我们就需要加一个判断条件if(num2==0)进行返回别的值,但是此时返回什么呢?当然我们代码也可以这样写:

#include <stdio.h>

//函数的结果和计算状态分开
int main()
{
	//定义一个函数,将两个数相除,获取他们的余数



	return 0;
}

int getRemainder(int num1, int num2)
{
	if (num2 != 0)
	{
	    int res = num1 % num2;
	}

	return res;
}

        或者也可以写为:

#include <stdio.h>

//函数的结果和计算状态分开
int main()
{
	//定义一个函数,将两个数相除,获取他们的余数



	return 0;
}

int getRemainder(int num1, int num2)
{
	if (num2 == 0)
	{
		return -1;
	}

	int res = num1 % num2;
	return res;
}

        这两种方法都可以完成,除此之外,我们也可以使用指针来进行操作:

#include <stdio.h>

//函数的结果和计算状态分开
int main()
{
	//定义一个函数,将两个数相除,获取他们的余数

	//定义两个变量
	int a = 10;
	int b = 3;
	int res = 0;
	
	//调用函数获取余数
	int flag = getRemainder(a, b, &res);//获取getRemainder(a, b, &res);的返回值赋值给flag

	//对状态进行判断
	if (!flag)
	{
		printf("获取到的余数为:%d\n", res);
	}

	return 0;
}

//此时返回值表示计算的状态,0表示正常,1表示不正常
int getRemainder(int num1, int num2, int* res)
{
	if (num2 == 0)
	{
		return 1;
	}

	*res = num1 % num2;
	return 0;
}

指针_时光の尘的博客-CSDN博客

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

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

相关文章

装饰大师——装饰模式(Java实现)

引言 大家好&#xff0c;上期我们介绍了装饰模式在Python中的实现&#xff0c;今天&#xff0c;我们将继续探讨装饰模式&#xff0c;并展示如何在Java中实现它。 装饰模式概述 装饰模式的核心思想是将功能附加到对象上&#xff0c;而不是通过继承来实现&#xff0c;这种模式…

【JavaSE-线程安全问题-死锁详解】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a; c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 &#x1f308;…

HTML基础1-文本级元素

HTML 简介 什么是 HTML&#xff1f; HTML (HyperText Markup Language) 是一种用于创建网页的标准标记语言。它通过使用一系列预定义的元素来描述文档的结构和外观&#xff0c; 您可以使用 HTML 来建立自己的 WEB 站点。 HTML 的作用 HTML 用于定义网页的结构&#xff0c;…

快手文生图模型-Kolors快速上手

Kolors是什么 可图(Kolors)&#xff1a;用于真实感文本到图像合成的扩散模型的有效训练 可图&#xff0c;是快手开源的一个文生图模型&#xff0c;架构上使用了chatglm&#xff0c;比普通的sd模型在中文理解上要强大很多&#xff0c;以往sd模型的提示词理解能力往往只有两种 …

《BeanShell 在 JMeter 中的应用》总结

通过案例进行讲解 一、BeanShell 介绍 官网: http://www.BeanShell.org BeanShell 是一种完全符合 Java 语法规范的脚本语言&#xff0c;具有以下特点&#xff1a; 是一种松散类型的脚本语言&#xff0c;类似 JS。是用 Java 写成的小型、免费、可下载的嵌入式 Java 源代码解…

计算机毕业设计选题推荐-零食批发商仓库管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

LocalDateTime的序列化和反序列化

背景 最近定位出一个LocalDateTime序列化相关的问题&#xff0c;简单记录一下。本文重点介绍Jackson对LocalDateTime的序列化和反序列化&#xff0c;并结合Spring应用场景进行介绍。 1.LocalDateTime与字符串转换 可以通过DateTimeFormatter实现LocalDateTime与字符串的相互…

Windows远程桌面无法拷贝文件问题

场景说明 Winwdows远程桌面&#xff0c;相比Linux方便一点就是&#xff0c;同是windows连接&#xff0c;其中复制粘贴功能&#xff0c;可以在两个windows无缝切换。 但最近笔者远程一台测试windows服务器时&#xff0c;发现无法在服务器上复制内容到本地&#xff0c;也无法从…

西门子s7第三方(S7netplus)读写操作

和西门子PLC通讯需要使用S7netplus​​这个包&#xff0c;可以在NuGet​​上搜索下载&#xff0c;下载后引入命令空间using S7.Net;​​ 创建PLC对象进行连接使用Write Read进行读写操作即可不需要在发请求帧 //创建Plc对象Plc plc; //西门子设备是s7-1200//参数1 CPu类型//参…

微信小程序+JAVA实现微信支付

时隔两年再次回归 本文主要讲的是小程序实现微信支付功能&#xff0c;后台采用JAVA。 一.准备工作 1.小程序 2.微信商户号 1.商户号申请 这里对小程序的申请不做赘述。 如果没有微信商户号的同学&#xff0c;点击该链接https://pay.weixin.qq.com/&#xff0c;按照下属步骤…

低代码与人工智能的融合:加速应用开发的未来趋势

什么是低代码&#xff0c;它是如何工作的&#xff1f; 低代码是一种软件开发概念&#xff0c;它通过最小化手工编码的方式&#xff0c;为开发和部署定制化应用提速。低代码平台具备模型驱动、沙盒多环境、可编程的可视化开发方式等&#xff0c;能用于开发包含有用户界面、业务逻…

二叉树——链式结构的实现

首先是分为三个文件进行实现&#xff1a;tree.h、tree.c、test.c tree.h 用链表来表示⼀棵⼆叉树&#xff0c;即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成&#xff0c;数据域和左右指针域&#xff0c;左右指针分别用来给出该结点左孩⼦和右孩⼦所在…

基于Springboot + vue + mysql 校友社交管理系统 设计实现

目录 &#x1f4da; 前言 &#x1f4d1;摘要 1.1 研究背景 &#x1f4d1;操作流程 &#x1f4da; 系统架构设计 &#x1f4da; 数据库设计 &#x1f4ac; E-R表 4.2.2数据库逻辑结构设计 &#x1f4da; 系统功能的具体实现 系统功能模块 系统首页 校友会信息 校友活动 …

仿RabbitMQ实现消息队列———整体框架

目录 一、项目简介 需求分析 AMQP 特点&#xff1a; AMQP 模型&#xff1a; 交换机类型 持久化 网络通信 二、服务端模块 1、交换机数据管理 2、队列数据管理 3、绑定数据管理 4、消息数据管理 5、虚拟机数据管理 6、路由匹配管理 7、消费者管理 8、信道管理 …

智源发布三款BGE新模型,再次刷新向量检索最佳水平

近期&#xff0c;以大语言模型&#xff08;LLM&#xff09;为基础的向量模型&#xff08;embedding model&#xff09;变得愈发流行。得益于大语言模型强大的语义理解能力&#xff0c;相关模型在下游任务中的检索精度得到了显著的提升。然而&#xff0c;当前基于大模型的向量模…

leetcode 1555 银行账号概要(postgresql)

需求 用户表&#xff1a; Users --------------------- | Column Name | Type | --------------------- | user_id | int | | user_name | varchar | | credit | int | --------------------- user_id 是这个表的主键。 表中的每一列包含每一个用户当前的额度信息。 交易表&…

Nginx反向代理实战

使用反向代理代理服务 假设我们有三台服务器提供不同的服务 nginx作为代理服务器 代理服务器&#xff1a; 192.168.101.23 其余三台服务器 服务器1 192.168.101.18 服务器2 192.168.101.87 服务器3 192.168.101.20 代理服务器的nginix配置 server {listen 8085;ser…

【机器学习基础】机器学习概述与实践基础

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

Docker中使用自定义网络方式实现Redis集群部署与测试流程

场景 Docker中Docker网络-理解Docker0与自定义网络的使用示例&#xff1a; Docker中Docker网络-理解Docker0与自定义网络的使用示例-CSDN博客 参考上面的流程实现自定义网络的实现。 下面记录其应用实例&#xff0c;使用Docker的自定义网络实现redis集群部署。 注&#xf…