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

目录

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;//定义一个指针变量aint* 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函数,并使用该函数的变量aint* 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函数,并使用该函数的变量aint* 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函数,并使用该函数的变量aint* 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.rhkb.cn/news/387493.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3后台管理系统 vue3+vite+pinia+element-plus+axios上

前言 项目安装与启动 使用vite作为项目脚手架 # pnpm pnpm create vite my-vue-app --template vue安装相应依赖 # sass pnpm i sass # vue-router pnpm i vue-router # element-plus pnpm i element-plus # element-plus/icon pnpm i element-plus/icons-vue安装element-…

C++第一篇 入门基础

目录 1.C的第一个程序 2.c历代版本 3.命名空间 3.1 namespace关键字 namespace的用法&#xff1a; namespace中定义函数 namespace中定义结构体 C中的域&#xff1a; 3.2就近原则 4.命名空间的使用 5.C输入输出 6.缺省参数 全缺省: 半缺省:必须从右往左连续缺省(也…

爆“卷”的AI视频,大厂向左,创企向右

文&#xff5c;白 鸽 编&#xff5c;王一粟 “生成的人物一转身就变成老外&#xff0c;怎么解决呢&#xff1f;” “没有办法&#xff0c;10s中动作大的&#xff0c;人物一致性有问题&#xff0c;只能抽卡&#xff0c;多刷几个&#xff0c;选择一个变化不大的。” 在一个以…

RocketMQ Server Windows安装

RocketMQ阿里开发 开源给apache 官网:RocketMQ 官方网站 | RocketMQ 下载后解压 配置环境变量 注意启动顺序 双击 注意 4.9.0这个版本必须 jdk 8 高了用不了 namesrv是注册中心的作用 broke是核心用于接收生产者消息 存储消息 发送给消费者消息 类似DubboZookeeper…

Java红娘相亲交友平台系统源码小程序

&#x1f495;遇见真爱&#xff0c;从“红娘相亲交友平台系统”开始&#xff01;&#x1f46b; &#x1f339;【精准匹配&#xff0c;缘分不再擦肩而过】 还在为茫茫人海中找不到那个TA而烦恼吗&#xff1f;“红娘相亲交友平台系统”利用先进的大数据分析技术&#xff0c;根据…

匿名内部类

一个类的内部又完整的嵌套了另一个类结构&#xff0c;被嵌套的类称为内部类&#xff0c;嵌套其他的类称为外部类。 类的五大成员&#xff1a;属性、方法、构造器、代码块、内部类 内部类最大的特点的就是直接访问私有属性&#xff0c;并且可以体现类鱼类之间的包含关系。 基本…

北斗三号海上人员落水报警及示位搜救系统升级方案

随着海洋经济的快速发展&#xff0c;海上作业活动日益频繁&#xff0c;人员安全问题也日益凸显。传统的海上救援手段存在诸多不足&#xff0c;如救援响应时间长、定位不准确等。为了提高海上救援的效率和成功率&#xff0c;北斗三号海上人员落水报警及示位搜救系统应运而生。该…

微波传感器 - 从零开始认识各种传感器【第二十期】

微波传感器|从零开始认识各种传感器 1、什么是微波传感器 微波传感器是一种利用微波技术进行探测和测量的传感器。 一般来说&#xff0c;微波是波长为1到1000毫米的电磁波。使用微波传感器&#xff0c;在不接触目标物体的情况下&#xff0c;通过检测和分析微波信号的反射、散…

Matplotlib柱形图大揭秘:让数据‘站’起来,比增高鞋垫还管用!

1. Matplotlib绘制柱形图/柱状图/条形图 柱状图是一种用矩形柱来表示数据分类的图表&#xff0c;柱状图可以垂直绘制&#xff0c;也可以水平绘制&#xff0c;它的高度与其表示的数据成正比关系 # 导包 import numpy as np import pandas as pd import matplotlib.pyplot as p…

机械学习—零基础学习日志(高数16——函数极限性质)

零基础为了学人工智能&#xff0c;真的开始复习高数 这里我们继续学习函数极限的性质。 局部有界性 充分条件与必要条件 极限存在是函数局部有界的充分条件。什么是充分条件&#xff0c;什么是必要条件呢&#xff1f;我这里做了一点小思考&#xff0c;和大家分享&#xff0c…

Windows11下 Visual Studio 2022 + Qt6 的 WebSocket 线程池异步 客户端

Windows11下 Visual Studio 2022 + Qt6 的 WebSocket 线程池异步 客户端 1 开发 WebSocket 客户端1.1 开发环境1.1.1 为Qt 6安装 websockets1.2 .基于Qt6的 QWebSocket 客户端示例1.2.1 实现 WebSocket 客户端1.2.2 创建 QtQWesocketClient1.2.3 创建QWebsocket对象1.2.3.1 添加…

iOS object-C 解答算法:找到所有数组中消失的数字(leetCode-448)

找到所有数组中消失的数字(leetCode-448) 题目如下图:(也可以到leetCode上看完整题目,题号448) 光看题看可能有点难以理解,我们结合示例1来理解一下这道题. 有8个整数的数组 nums [4,3,2,7,8,2,3,1], 求在闭区间[1,8]范围内(即1,2,3,4,5,6,7,8)的数字,哪几个没有出现在数组 …

新装centos7虚拟机如何配置网络,NAT配置固定IP

首先声明&#xff0c;我想使用的是NAT连接模式&#xff0c;并且设置完IP之后&#xff0c;使得这个IP固定住&#xff0c;以后不会再变了。 文章目录 1&#xff0c;打开Vmware软件的【编辑】-【虚拟网络编辑器】2&#xff0c;先选择VMnet8&#xff08;画1处&#xff09;&#xf…

解析capl文件生成XML Test Module对应的xml工具

之前一直用的CAPL Test Module来写代码&#xff0c;所有的控制都是在MainTest()函数来实现的&#xff0c;但是有一次&#xff0c;代码都写完了&#xff0c;突然需要用xml的这种方式来实现&#xff0c;很突然&#xff0c;之前也没研究过&#xff0c;整理这个xml整的一身汗&#…

Hive3:库操作常用语句

1、创建库 create database if not exists myhive;2、选择库 use myhive;3、查看当前选择的库 SELECT current_database();4、查看库详细信息 desc database myhive;可以查看数据文件在hdfs集群中的存储位置 5、创建库时制定hdfs的存储位置 create database myhive2 …

安全防护软件的必要性:从微软蓝屏事件谈起

最近微软遭遇了的大规模蓝屏事件&#xff0c;让全球很多用户措手不及。这次事件告诉我们&#xff0c;保护我们的电脑和数据&#xff0c;安全防护软件是多么重要。 微软蓝屏事件源于网络安全公司CrowdStrike的技术更新错误&#xff0c;导致全球范围内大量Windows用户系统崩溃&a…

什么是五力分析?5分钟带你了解它在企业财务经营中的应用与价值!

如今&#xff0c;随着全球化进程的不断加速&#xff0c;市场环境复杂多变&#xff0c;市场竞争日益激烈&#xff0c;财务经营已经成为了企业应对复杂市场环境、保持自身竞争力的关键。体系化的五力分析平台能够为企业提供一套全面的解决方案&#xff0c;帮助企业在盈利能力、偿…

HamonyOS性能优化工具和方法

性能优化&#xff0c;如何做到更快的启动、更流畅的使用&#xff0c;概括图如下 ArkTS高性能编程&#xff1a; 1. ArkTS规则&#xff1a;有利于方舟编译运行时进行编译优化 2. 使用AOT(Ahead Of Time)模式对应用进行编译优化&#xff1a;方舟编译运行时通过采用PGO(Profile-Gui…

React 学习——组件内通信(兄弟之间)

A组件 > B组件 核心思路&#xff1a; 1、A组件先通过子传父的方式把数据传给父组件App 2、App拿到数据后通过父传子的方式再传递给B组件 import { useState } from "react" function A({onGetMsg}){const AMsg 我是A组件的消息return (<div><button…

ESP-ADF适配到自定义开发板中

ESP-ADF适配到自定义开发板中 前言:项目开发完了,来记录一下开发过程。 安装: 这里采用vscode+ESP-IDF+ESP-ADF的开发方式。 安装esp-idf的方法很简单,网上都是,这里不说了。想用esp-adf那么你idf的环境肯定是已经搭建好了。 安装adf也很简单,一步完成。 按下F1,选…