当前位置: 首页 > 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…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

IGP(Interior Gateway Protocol,内部网关协议)

IGP&#xff08;Interior Gateway Protocol&#xff0c;内部网关协议&#xff09; 是一种用于在一个自治系统&#xff08;AS&#xff09;内部传递路由信息的路由协议&#xff0c;主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...