当前位置: 首页 > news >正文

『C语言进阶』指针进阶(一)

在这里插入图片描述
🔥博客主页 小羊失眠啦
🔖系列专栏 C语言
🌥️每日语录无论你怎么选,都难免会有遗憾。
❤️感谢大家点赞👍收藏⭐评论✍️


在这里插入图片描述

前言

在C语言初阶中,我们对指针有了一定的了解,指针是个变量,是用来存放地址的,指针的大小是固定的4/8个字节,指针是有类型的,指针的类型决定了指针的±整数的步长以及指针的运算,小羊最近已经开学,博客可以正常更新了,好啦,接下来让我们再进一步的了解指针!!


一、字符指针

我们可以定义一个字符指针,指向一个字符变量,并通过指针来修改这个字符变量

例1

#include<stdio.h>
int main()
{char ch = 'x';char* p = &ch;//pc是字符指针ch = 'a';*p = 'a';return 0;
}
//ch是字符变量,可以直接改变ch的值,
//pc这时是字符指针,存放的是ch的地址,也可以通过指针来改变变量ch的值。

例2

#include<stdio.h>
int main()
{char arr[] = "abcdefg";//创建数组,用字符串来初始化char* p = "abcdefg";//常量字符串,"abcdefg"存放在"常量区",只读,不允许被修改//指针变量p存放的是字符串首元素的地址*p='a';//erro 这种情况会报错,pa不能改变为w
}

例3:这段代码运行结果是什么?

int main()
{char* s = "abcdefg";for (int i = 0; i < 4; i++){*(s + i) = '0';}printf("%s\n", s);return 0;
}

结果:

运行错误,原因是"abcdefg"是常量字符串,它们存放在"常量区",只读,不允许被修改,所以一般写成const char* s="abcdefg"

笔试题

int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

在这里插入图片描述

结果分析:

str1和str2是两个字符数组,两个数组是相互独立的,在创建时,会各自向空间申请空间,所以地址是不一样的,只是内存中两块不同内存区域存放着相同内容而已,故str1!=str2
str3和str4里面存放的地址是同一个,都是h的地址,所以是一样的


二、指针数组

2.1 认识指针数组

在C语言初阶里的初识指针中,铁汁们对指针数组也有一定的了解,指针数组是一个存放指针的数组。

整形数组--存放整形的数组
字符数组--存放字符的数组
指针数组--存放指针的数组

#include<stdio.h>
int main()
{int arr1[3];  //存放了三个整形的数组 int int intint* arr2[3]; //存放了三个整形指针的数组 int* int* int*char* arr3[3];//存放了三个一级字符指针的数组 char* char* char*char** arr4[3];//存放了三个二级字符指针的数组 char** char** char**return 0;
}

牛刀小试

int main()
{char* arr[] = { "abcd","efgh","igkl" };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++)printf("%s ", arr[i]);return 0;
}

在这里插入图片描述

arr是首元素地址

2.2 使用指针数组模拟二维数组

#include<stdio.h>
int main()
{int arr1[4] = { 1,2,3,4 };int arr2[4] = { 2,3,4,5 };int arr3[4] = { 3,4,5,6 };int arr4[4] = { 4,5,6,7 };int* arr[4] = { arr1,arr2,arr3,arr4 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++){for (int j = 0; j < 4; j++){printf("%d ", *(arr[i] + j));}printf("\n");}return 0;
}

在这里插入图片描述
结果分析:

经过调试内存可得:int arr1[4] = { 1,2,3,4 };              //arr1的地址是:0x0000001C526FF7F8int arr2[4] = { 2,3,4,5 };              //arr2的地址是:0x0000001C526FF828int arr3[4] = { 3,4,5,6 };              //arr3的地址是:0x0000001C526FF858int arr4[4] = { 4,5,6,7 };              //arr4的地址是:0x0000001C526FF888
由此可见,arr1,arr2,arr3,arr4数组内存中有独立的内存空间,并不是连续的四个内存空间,
我们将这四个一维数组的首元素的地址放在指针数组arr中,通过指针数组来访问这四个一维数组,效果和二维数组是一样的,但是并不是真正的二维数组!!

三、数组指针

3.1 数组指针的定义

定义:指向数组指针被称为数组指针
由于指针数组和数组指针对于初学者很容易混肴,所以我们先通过类比的方法来认识数组指针。

字符指针–指向字符变量的指针,即存放字符变量地址的指针变量。
整型指针–指向整型变量的指针。即存放整型变量地址的指针变量
数组指针–指向数组变量的指针。即存放数组变量地址的指针变量

#include<stdio.h>
int main()
{int a = 2;int* p = &a; int arr[10]; int* arr[10];  //arr先和[10]结合,所以arr是一个数组,里面存的都是指针变量,即为指针数组int(*arr)[10];//arr先和*结合所以arr是一个指针变量,又指向数组,即为指针数组return 0;
}

解释:p先和*结合,说明p是一个指针变量,然后指向一个大小为10个整型的数组(指向的类型 int [10])。所以p是一个指针,指向一个数组,叫数组指针。

注意:[ ]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

3.2 &数组名VS数组名

  • 通常情况下,数组名是首元素地址
  • sizeof(数组名):计算的是整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数组
  • &数组名:取出的是数组的地址,&数组名,数组名表示整个数组
#include<stdio.h>
int main()
{int arr[5] = { 0,1,2,3,4 };printf("  arr=%p\n", arr);printf("arr+1=%p\n", arr + 1);printf("\n");printf("  &arr[0]=%p\n", &arr[0]);printf("&arr[0]+1=%p\n", &arr[0] + 1);printf("\n");printf("  &arr=%p\n", &arr);printf("&arr+1=%p\n", &arr + 1);return 0;
}

在这里插入图片描述

3.3 数组指针的使用

数组指针指向的是数组,那数组指针中存放的数组的地址

#include<stdio.h>
int main()
{int arr[5];int(*p)[5]=&arr;//p的类型是int(*)[5],存放的是存放int类型的数组int* pp[5];//指针数组,pp是数组,存放的是int*类型int* (*ppp) = &pp;//ppp的类型是int*(*)[5],存放的是存放int*类型的数组return 0;
}

3.3.1 打印数组元素

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

3.3.2 打印二维数组元素

#include<stdio.h>void Print1(int arr[3][5], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf("%d ", arr[i][j]);}printf("\n");}
}void Print2(int(*p)[5], int row, int col)
{for (int i = 0; i < row; i++){for (int j = 0; j < col; j++){printf("%d ", *(p[i] + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };Print1(arr, 3, 5);printf("\n");Print2(arr, 3, 5);return 0;
}

3.4 总结:

在这里插入图片描述
数组名arr,表示首元素的地址,二维数组的首元素是二维数组的第一行所以这时传递的arr,其实相当于第一行的地址,是一维数组的地址可以数组指针来接收。

补充:

一维数组传参,形参的部分可以是数组,也可以是指针
二维数组传参,形参的部分可以是数组,也可以是指针

注意:形参写成数组形式是为了让人更容易理解,本质上是指针


四、数组传参和指针传参

4.1 一维数组传参

数组传参的时候,形参可以写成同样数组形式,若是用数组作形参,[ ]里面的值可以省略,也可以随意赋值。传过来的arr是数组首元素地址,所以也可以用一级整形指针来接受。

#include<stdio.h>
void test1(int arr[]);//正确
void test2(int arr[10]);//正确
void test3(int* arr);//正确
int main()
{int arr1[10] = { 0 };
}

实战演练

#include<stdio.h>void test1(int arr[],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void test2(int arr[10],int sz)
{for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}
}void test3(int* arr, int sz)
{for (int i = 0; i < sz; i++){printf("%d ", *(arr+i));}
}int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);test1(arr, sz);printf("\n");test2(arr, sz);printf("\n");test3(arr, sz);return 0;
}

4.2 二维数组传参

void test(int arr[3][5])//ok?
{}
OK
void test(int arr[][])//ok?
{}
NO  二维数组传参,函数形参的设计只能省略行数,不能省略列数
二位数组传参,传的是二维数组第一行的地址,而不是第一行第一个元素的地址
void test(int arr[][5])//ok?
{}
OK
void test(int* arr)//ok?
{}
NO
void test(int* arr[5])//ok?
{}
NO  这是一个存放int* 类型的数组
void test(int(*arr)[5])//ok?
{}
OK  这是一个存放数组的一级指针
void test(int** arr)//ok?
{}
NO
int main()
{int arr[3][5] = { 0 };test(arr);
}

4.3 一维指针传参

void test(int* p)
{}int main()
{int n = 10;test(&n);int* p = &n;test(p);int arr[5] = { 0 };test(arr);return 0;
}

4.4 二维指针传参

void test(int** p)
{}int main()
{int n = 10;int* p=&n;test(&p);int** pp = &p;test(pp);int* arr[5] = { 0 };test(arr);return 0;
}

本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有问题可以在评论区留言,小羊一定认真认真修改,以后写出更好的文章。
在这里插入图片描述

相关文章:

『C语言进阶』指针进阶(一)

&#x1f525;博客主页&#xff1a; 小羊失眠啦 &#x1f516;系列专栏&#xff1a; C语言 &#x1f325;️每日语录&#xff1a;无论你怎么选&#xff0c;都难免会有遗憾。 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前言 在C语言初阶中&#xff0c;我们对指针有了一定的…...

2605. 从两个数字数组里生成最小数字(Java)

给你两个只包含 1 到 9 之间数字的数组 nums1 和 nums2 &#xff0c;每个数组中的元素 互不相同 &#xff0c;请你返回 最小 的数字&#xff0c;两个数组都 至少 包含这个数字的某个数位。 示例 1&#xff1a; 输入&#xff1a;nums1 [4,1,3], nums2 [5,7] 输出&#xff1a;1…...

深度解析 PostgreSQL Protocol v3.0(一)

引言 PostgreSQL 使用基于消息的协议在前端&#xff08;也可以称为客户端&#xff09;和后端&#xff08;也可以称为服务器&#xff09;之间进行通信。该协议通过 TCP/IP 和 Unix 域套接字支持。 《深度解析 PostgreSQL Protocol v3.0》系列技术贴&#xff0c;将带大家深度了…...

Mysql中having语句与where语句的用法与区别

分析&回答 我们在写sql语句的时候,经常会使用where语句,很少会用到having,其实在mysql中having子句也是设定条件的语句与where有相似之处但也有区别。having子句在查询过程中慢于聚合语句(sum,min,max,avg,count)。而where子句在查询过程中则快于聚合语句(sum,min,max,avg…...

基于qt软件的网上聊天室软件

1.服务器: 1).功能: 用于创建一个客户端&#xff0c;通过文本编辑器来获得端口号&#xff0c;根据获得的端口号创建服务器&#xff0c;等待客户端连接 创建成功会提示服务器创建成功 在收到客户端发送的信息时&#xff0c;把这条信息发送给其他所有客户端&#xff0c;实现群…...

本是同根生-双数据库集群keepalived virtual_route_id冲突导致连接故障

项目场景&#xff1a; 一企业近期陆续开始升级办公与大数据系统&#xff0c;新的承包商。原有的数据库是某国内大品牌A&#xff0c;现在新的功能准备陆续迁移到大品牌B上。系统部署后&#xff0c;A依旧承担比较轻松的财务、仓库管理&#xff0c;B承担实时的线上业务。项目验收…...

『力扣每日一题06』字符串中的第一个唯一字符

今天是学习新知识的一天&#xff0c;String 类中有太多细枝末节&#xff0c;需要我去学习跟掌握了。 话不多说&#xff0c;今天给大家带来一道字符串的题目~ 一、题目 给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&…...

selenium鼠标操作方法

1.0 selenium新版本封装驱动 from selenium.webdriver import Chrome from selenium.webdriver.chrome.options import ChromiumOptions from selenium.webdriver.chrome.service import Servicedef get_chrome_driver(driver_path):chrome_options ChromiumOptions()chrome_…...

医者无疆 | AI赋能大医精诚,医疗制药的进阶与突破

在历史的长河中&#xff0c;医学一直是人类文明的重要组成部分。从古希腊的希波克拉底到现代医学研究&#xff0c;医学始终与时俱进&#xff0c;为人类的健康和福祉做出了巨大的贡献。在互联网、大数据、5G等信息技术的迭代下&#xff0c;人工智能&#xff08;AI&#xff09;的…...

使用 Hue 玩转 Amazon EMR(SparkSQL, Phoenix) 和 Amazon Redshift

现状 Apache Hue 是一个基于 Web 的交互式 SQL 助手&#xff0c;通过它可以帮助大数据从业人员&#xff08;数仓工程师&#xff0c;数据分析师等&#xff09;与数据仓库进行 SQL 交互。在 Amazon EMR 集群启动时&#xff0c;通过勾选 Hue 进行安装。在 Hue 启用以后&#xff0…...

Unity中神秘的Transform和transform(小写)的关系

1.为什么Transform类是保护的不能通过new 来实例化对象,也没有静态函数,而Rotate()这种方法却属于它,该如何访问? Transform 类还是被保护的不允许用户修改! protected Transform(); 是一个受保护的构造函数,不能直接实例化 Transform 类。 2.为甚么transform可以访问Tr…...

【LeetCode-中等题】78. 子集

文章目录 题目方法一&#xff1a;动态规划方法二&#xff1a;递归加回溯(关键----startIndex) 题目 注意&#xff1a;这里的nums数组里面的元素是各不相同的&#xff0c;所以不存在去重操作 方法一&#xff1a;动态规划 public List<List<Integer>> subsets(int[]…...

学习设计模式之代理模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 代码同步更新到 github ,要是点个Star您就是我的神 目录 前言代理模式1.情景模拟1.1静态代理优点局限 1.2 动态代理 2.应用3.局限4.解决方…...

自学Python01-创建文件写入内容

此处省去安装和前言&#xff0c;需要两个东西 一个去下载安装python官方库 Welcome to Python.org 一个是编译器pycharm PyCharm 安装教程&#xff08;Windows&#xff09; | 菜鸟教程 PyCharm: the Python IDE for Professional Developers by JetBrains 第一节 练习print…...

Qt —UDP通信QUdpSocket 简介 +案例

1. UDP通信概述 UDP是无连接、不可靠、面向数据报&#xff08;datagram&#xff09;的协议&#xff0c;可以应用于对可靠性要求不高的场合。与TCP通信不同&#xff0c;UDP通信无需预先建立持久的socket连接&#xff0c;UDP每次发送数据报都需要指定目标地址和端口。 QUdpSocket…...

五大类注解和方法注解详解

五大类注解为Controller&#xff0c;Service&#xff0c;Repository&#xff0c;Configuration&#xff0c;Component,方法注解为Bean。 需要注意的是&#xff1a;Bean注解必须要在类注解修饰的类内才能正常使用。 一、与配置文件的关系 在spring原生项目中 如果你使用的spri…...

机器人中的数值优化(十)——线性共轭梯度法

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…...

数据结构与算法之贪心动态规划

一&#xff1a;思考 1.某天早上公司领导找你解决一个问题&#xff0c;明天公司有N个同等级的会议需要使用同一个会议室&#xff0c;现在给你这个N个会议的开始和结束 时间&#xff0c;你怎么样安排才能使会议室最大利用&#xff1f;即安排最多场次的会议&#xff1f;电影的话 那…...

【网络编程】网络基础概念

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…...

连接虚拟机报错 Could not connect to ‘192.168.xxx.xxx‘ (port 22): Connection failed.

使用xshell连接虚拟机报错 Connecting to 192.168.204.129:22… Could not connect to ‘192.168.204.129’ (port 22): Connection failed. Type help’ to learn how to use Xshell prompt. 按网上的方法 是否能ping通内外网 ping www.baidu.com防火墙是否关闭 firewal…...

数学建模--Topsis评价方法的Python实现

目录 1.算法流程简介 2.算法核心代码 3.算法效果展示 1.算法流程简介 """ TOPSIS(综合评价方法):主要是根据根据各测评对象与理想目标的接近程度进行排序. 然后在现有研究对象中进行相对优劣评价。 其基本原理就是求解计算各评价对象与最优解和最劣解的距离…...

超越时间与人力的软件开发智慧:《人月神话》

目录 1、写在前面2、沟通&#xff01;沟通&#xff01;沟通&#xff01;3、“银弹论”4、“人月神话”不能成立的原因5、影响力6、图书推荐 1、写在前面 《人月神话》是由计算机科学家弗雷德里克布鲁克斯所著的一本经典著作&#xff0c;首次出版于1975年。这本书以一个个小故事…...

Java Stream 流对象(实用技巧)

目录 一、InputStream & OutputStream 1.1、InputStream 和 OutputStream 一般使用 1.2、特殊使用 1.2.1、如何表示文件读取完毕&#xff1f;&#xff08;DataInputStream&#xff09; 1.2.2、字符读取/文本数据读取&#xff08;Scanner&#xff09; 1.2.3、文件的随机…...

【用unity实现100个游戏之8】用Unity制作一个炸弹人游戏

文章目录 前言素材开始一、绘制地图二、玩家设置三、玩家移动四、玩家四方向动画运动切换 五、放置炸弹六、生成爆炸效果七、墙壁和可破坏障碍物的判断八、道具生成和效果九、玩家死亡十、简单的敌人AI十一、简单敌人AI十二、随机绘制地图十三、虚拟摇杆 最终效果待续源码完结 …...

简易版人脸识别qt opencv

1、配置文件.pro #------------------------------------------------- # # Project created by QtCreator 2023-09-05T19:00:36 # #-------------------------------------------------QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsTARGET 01_face TEMP…...

如何系统地学习 JavaScript?

前言 在学习JavaScript前需要先将Html和Css的相关知识点弄清楚&#xff0c;Js的很多操作是要结合Html和Css&#xff0c;下面我总结了Html、Css和Js的相关学习知识点供参考&#xff0c;希望对你有所帮助喔~ Html 文档学习 【HTML 】w3school教程 :https://www.w3school.com.…...

对称二叉树(Leetcode 101)

题目 101. 对称二叉树 思路 使用层序遍历&#xff0c;遍历当前层的节点时&#xff0c;如该节点的左&#xff08;右&#xff09;孩子为空&#xff0c;在list中添加null&#xff0c;否则加入左&#xff08;右&#xff09;孩子的值。每遍历完一层则对当前list进行判断&#xff0c…...

动手学深度学习(2)-3.5 图像分类数据集

文章目录 引言正文图像分类数据集主要包介绍主要流程具体代码练习 总结 引言 这里主要是看一下如何加载数据集&#xff0c;并且生成批次训练的数据。最大的收获是&#xff0c;知道了如何在训练阶段提高模型训练的性能 增加batch_size增加num_worker数据预加载 正文 图像分类…...

C标准输入与标准输出——stdin,stdout

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是一套 C 语言趣味教学专栏&#xff0c;目前正在火热连载中&#xff0c;欢迎猛戳订阅&#…...

如何将home目录空间扩充到根目录下

目录 1、查看查看磁盘使用情况2、扩容思路3、卸载并删除/home4、扩大/root逻辑卷5、扩大/文件系统6、重建/home逻辑卷7、创建/home文件系统8、将新建的文件系统挂载到/home目录下9、恢复/home并删除备份10、再次查看看磁盘存储 系统&#xff1a;centos7.9 1、查看查看磁盘使用…...