【进阶】C语言第二课:升级你的指针(1)

news2024/10/5 22:23:48

目录

🤩前言🤩:

一、字符指针🤯:

        1.字符指针的使用🦝:

        2.常量字符串🦊:

        3.相关面试题分析🐣:

二、指针数组🧐:

三、数组指针🤠:

        1.数组指针的定义🦌:

        2.&数组名VS数组名🦏:

        3.数组指针的使用🦨:

四、总结🥳:


🛰️博客主页:✈️努力学习的銮同学

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:💐【进阶】C语言学习

🏡🏡本文重点 🏡🏡

🚅  字符指针  🚃  指针数组  🚃  数组指针  🚏🚏

🤩前言🤩:

        在之前的初阶学习中,相信各位小伙伴们已经对指针有了相当的了解。那么从今天开始,我们将继续探讨指针的更高级主题,希望对大家的学习能够有所帮助!

一、字符指针🤯:

        1.字符指针的使用🦝:

        在一众指针类型中,我们知道存在着字符指针这种类型,并且我们一般这样去使用它:

int main()
{
	//第一种形式:
	char ch = 'w';
	char* pc = &ch;
	*pc = 'w';
	printf("%c\n", *pc);

	//第二种形式:
	const char* pstr = "hello bit.";
	//这里不是把一个字符串放到pstr指针变量里
	///其本质是把字符串 hello bit.的首字符的地址放到了pstr中,即将一个常量字符串的首字符' h '的地址存放到指针变量 pstr 中。
	printf("%s\n", pstr);

	return 0;
}

        这里第二种用法的本质是把常量字符串 ' hello bit. ' 的首字符 ' h ' 的地址放到了pstr中。

        2.常量字符串🦊:

        并且我们要注意,上面说到的常量字符串作为常量,它们不可被修改:

int main()
{
    char* p = "abcdef";
    //使指针指向常量区的常量字符串abcdef
    *p = 'A';
    //按照我们的理解,*p中存放的是首元素a的地址,我们尝试改变它
    //我们运行起来发现无法完成编译运行,程序会直接卡住
    //于是我们可以得出,当使用常量字符串时,常量字符串abcdef不可修改
    return 0;
}

        这些常量字符串中的常量字符,是原本就储存在常量区(只读数据区)的一些常量,不同于需要我们输入的字符变量。所以当使用字符指针直接指向常量字符串时,可以直接进行调用但无法对其进行修改

        当出现这种错误时,程序往往是可以正常编译运行但会卡住而得不出结果,我们往往很难发现问题的所在,会给我们的代码书写造成很大的困扰。为了尽可能的避免这种情况的发生,我们通常在指向常量字符串时,使用 const 对指针变量进行修饰,进行这样的书写操作之后,当我们试图对常量字符串进行改动时,将会直接报错而无法进行编译运行, 便于我们找到问题的所在:

        3.相关面试题分析🐣:

        我们再来看下面这道经典的面试题

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");
    }
    else
    {
        printf("str1 and str2 are not same\n");
    }

    //判断指针变量内容是否相同:
    if (str3 == str4)
    {
        printf("str3 and str4 are same\n");
    }
    else
    {
        printf("str3 and str4 are not same\n");
    }

    return 0;
}

        这道面试题中定义了两个字符型数组和两个字符型指针变量,将两个字符型数组进行对比,又将两个字符型指针变量尽行了对比,目的是为了验证它们在存储时内存的开辟

        这里 str3 str4 指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域(在我们的内存中存在着常量区用于存放一些常量),当几个指针指向同一个字符串的时候,他们实际会指向同一块内存。但是相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4不同:

 

二、指针数组🧐:

        在前面我们已经学习过的的《初阶指针》章节中,我们已经对指针数组有了一定程度的了解和认识。这里我们仅做回顾。

        在之前的学习中我们都知道,指针数组的本质是数组,是用于存放指针变量的数组

int main()
{
    //创建变量:
    int a = 1;
    int b = 2;
    int c = 3;

    //创建指针数组,用于存放指针(即变量的地址):
    int* arr[3] = { &a,&b,&c }; 

    //打印验证内容:
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("%p\n", arr[i]);
    }

    //也可以通过指针数组(存放的是各个变量的地址)来访问变量内容:
    for (i = 0; i < 3; i++)
    {
        printf("%d\n", *(arr[i]));
    }
    return 0;
}

        以上这是我们所知道的,所学习过的最普通的使用方式,而我们以后在工作中更常用的却是另外一种情况

int main()
{
    //创建数组:
    int arr1[3] = { 1,2,3 };
    int arr2[3] = { 4,5,6 };
    int arr3[3] = { 7,8,9 };

    //创建指针数组:
    int* parr[3] = { arr1,arr2,arr3 };
    //我们都知道,数组名即为数组内首元素地址
    //即此处的数组名为地址,故可以存放在指针变量内

    //验证指针数组内存放数据:
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("整型数组arr%d[3]首元素地址为:%p\n", i + 1, parr[i]);
    }
    printf("\n");

    //通过指针数组访问整型数组内的数据:
    for (i = 0; i < 3; i++)
    {
        printf("arr%d[3]中存储的数据为:", i + 1);
        int j = 0;
        for (j = 0; j < 3; j++)
        {
            printf("%d ", *(parr[i] + j));
        }
        printf("\n");
    }
    return 0;
}

        要注意的是,这样的形式与前面的基础示例存储和访问原理完全相同

 

三、数组指针🤠:

        1.数组指针的定义🦌:

        各位小伙伴们千万千万区别于指针数组,数组指针的本质是指针。不同于其他指针,数组指针指向的不是地址而是数组

int main()
{
    int* p1[10];
    //p1是数组,数组指针

    int(*p2)[10];
    //p2是指针。数组指针
    return 0;
}

        上面的示例中,p2先和*进行结合,说明p2是一个指针变量,再指向大小为10的整型数组。即p2是一个指向数组的指针,叫做数组指针。简单来说,数组指针就是专门用来存放一个数组的地址的指针。

        2.&数组名VS数组名🦏:

        我们都知道,除一些特殊情况外,大多数的数组名都表示数组首元素的地址,那么既然数组名已经是地址了,&+数组名的组合又代表着什么呢?我们来看一段代码:

int main()
{
    int arr[5] = { 0 };

    printf("arr :%p\n", arr);
    printf("&arr:%p\n", &arr);
    return 0;
}

        我们如果通过打印,会发现 arr 的打印结果与 &arr 相同

        难道它们真的是一回事吗?那么 &arr 的存在又有什么意义呢?

        我们说,不是这样的,arr 与 &arr 不一样。我们将上面这段代码进行改写:

int main()
{
    int arr[5] = { 0 };

    printf("arr :%p\n", arr);
    printf("&arr:%p\n", &arr);

    printf("\n");

    printf("arr+1 = %p\n", arr + 1);
    printf("&arr+1= %p\n", &arr + 1);
    return 0;
}

        我们使 arr 与 &arr 同时向后走一步,这时我们看到了不一样的结果:

        实际上,&arr 表示的是整个数组的地址,而 arr 仅表示其中首元素的地址,这就导致了我们在使它们在向后走的时候,它们向后走的步幅不同,&arr 跨过了整个数组的长度而 arr 仅仅只跳过了一个数据元素

        3.数组指针的使用🦨:

        在上面的介绍中,我们看到了数组指针的最基础用法:

int arr[10] = { 0 };
int (*p2)[10] = &arr;

        但是事实上,我们在真正的工程项目中却很少会这样去使用它。更多的是在我们进行函数调用,进行数组传参时,可以通过数组指针来进行接收

void print_arr1(int arr[3][5], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++)
        {
            printf("%02d ", arr[i][j]);
        }
        printf("\n");
    }
}

//使用数组指针来进行接收:
void print_arr2(int(*arr)[5], int row, int col)
{
    int i = 0;
    for (i = 0; i < row; i++)
    {
        int j = 0;
        for (j = 0; j < col; j++)
        {
            printf("%02d ", arr[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
    print_arr1(arr, 3, 5);
    //数组名arr,表示首元素的地址
    //但是二维数组的首元素是二维数组的第一行,所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
    printf("\n");

    //可以使用数组指针来进行接收:
    print_arr2(arr, 3, 5);
    return 0;
}

        我们很明显可以看到,

 

四、总结🥳:

        今天我们对指针的知识又有了新的了解,只要大家踏实肯学,我相信到最后,所有的小伙伴都一定会有所收获、有所成就,也衷心的祝愿各位小伙伴们在不久的将来能够拿到一份让自己满意的大厂offer🎉🎉

        😠​​​​​​​😠​​​​​​​有一种落差是,你配不上自己的野心,也辜负了所受的苦难!!!😠😠

        辛苦各位小伙伴们动动小手,三连走一走 ~ ~ ~  最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

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

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

相关文章

vue+nodejs公益图书借阅捐赠管理系统

公益图书捐赠管理系统 用户信息&#xff1a;id、用户名、密码、捐书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;、上传电子书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;、借阅图书数量&#xff08;管理员端可以点击跳转查看详情&#xff09;&am…

利用全长转录组多重阵列测序检测同源异构体

哈佛大学和麻省理工学院近期发表了“High-throughput RNA isoform sequencing using programmable cDNA concatenation.”研究论文中&#xff0c;将 cDNA 串联成可用于长读长测序最佳的单分子的技术应用于肿瘤浸润 T 细胞的单细胞 RNA 测序,提高了寻找可变剪接基因的准确度&…

秒懂:JCTool 的 Mpsc 高性能无锁队列 (史上最全+10W字长文)

文章很长&#xff0c;而且持续更新&#xff0c;建议收藏起来&#xff0c;慢慢读&#xff01;疯狂创客圈总目录 博客园版 为您奉上珍贵的学习资源 &#xff1a; 免费赠送 :《尼恩Java面试宝典》 持续更新 史上最全 面试必备 2000页 面试必备 大厂必备 涨薪必备 免费赠送 经典…

C# 修饰符

一 访问控制符 二 static 1 static 的字段、方法、属性是属于整个类的 ① static方法中&#xff0c;不能访问实例变量&#xff1b; ② 调用static方法时&#xff0c;直接用类名访问 Console.Write();Math.Sqrt(); Convert.ToDateTime();DateTime.Parse String.Copy(a);Strin…

【JavaSE】javaSE练习项目——>《简易图书管理系统》

目录 前言&#xff1a; 1、项目实现要求 2、设计思路流程 设计思路&#xff1a; 登录后菜单的实现效果&#xff1a; 3、代码实现&#xff08;大体框架&#xff09; Main类 book包 Book类 BookList类 user包 User类 AdminUser(管理员)类 NormalUser&#xff08;普通…

Hibernate Validator 使用详解

目录 Hibernate Validator的依赖 Hibernate Validator 支持注解 空与非空检查 Boolean值检查 日期检查 数值检查 其他 Hibernate-validator扩展约束 Hibernate Validator 校验 简单对象校验 嵌套对象校验 Hibernate Validator 分组校验 静态分组 动态分组 动态分…

【软件测试】刚入职后,快速适应新的工作需要做啥?

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 入职一家新公司后&a…

基于AD8226的环境光传感器电路

人们越来越多地认为环境光是一种能源,可用于驱动心率监控器、浴室灯具、远程天气传感器和其他低功耗器件。对于能量采集系统,最关键的是精确测量环境光的能力。本设计思路将描述一种简单的低成本电路,可以根据环境光的强度按一定比例提供电压。 所用传感器是一款光敏电阻(L…

spring framework 容器

org.springframework.beans 和 org.springframework.context 包是 Spring Framework 的 IoC 容器的基础。 这里需掌握两个体系结构&#xff0c;BeanFactory 和 ApplicationContext。 BeanFactory 主要接口&#xff0c;可分为三级&#xff1a; BeanFactory 是顶层容器&#xf…

Nacos 配置中心之主动拉取

客户端 客户端的配置有两种方式来维持,一是客户端主动拉取,而是客户端长轮询更新 配置文件的种类 1、本地配置文件: 本地就已经存在的配置文件 2、 本地缓存文件: 从服务端获取的保存在了本地 (本地生成了文件) 3、 cacheData 缓存数据: 内存中缓存的配置文件数据 客户端主动获…

【分享】学浪PC端登录分析及实现

本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!学浪PC端登录分析及实现 环境 win10Fiddlerchrome学浪PC端登录:aHR0cHM6Ly9zdHVkZW50LWFwaS5peWluY2Fpc2…

AE 动效制作和交付方案

在界面设计中&#xff0c;设计师利用动效让整个界面更加活泼&#xff0c;给界面元素带来生命力&#xff0c;解决功能上的问题&#xff0c;在更好地展示产品功能的基础上&#xff0c;凸显品牌的特色。而作为用户&#xff0c;动效增强了体验者的审美感受、情感需要&#xff0c;让…

德才论

目录 1015:德才论 输入格式&#xff1a; 输出格式&#xff1a; 输入样例&#xff1a; 输出样例&#xff1a; 思路: 1.技巧&#xff1a; 1.2结构体代码: 2.分类: 1.德才分类 1.2德才分类代码: 2.cmp函数 2.1 cmp函数代码: 3.超时问题(易错&#xff0c;算法要优化) 总代码…

神经网络优化

提升深度神经网络&#xff1a;超参数调节&#xff0c;正则化&#xff0c;优化 之前已经学习了如何构建神经网络&#xff0c;本章将继续学习如何有效运行神经网络&#xff0c;内容涉及超参数调优&#xff0c;如何构建数据以及如何确保优化算法快速运行&#xff0c;从而使学习算…

LVM卷在线扩容报错:resize would cause inodes_count overflow

一、问题描述 某次在线环境&#xff0c;存储使用率告警在线扩容时&#xff0c;文件系统扩容失败&#xff0c;报错如下&#xff1a; Size of logical volume sihua/video changed from <162.00 TiB (42467321 extents) to <258.00 TiB (67633142 extents).Logical volu…

[附源码]计算机毕业设计付费自习室管理小程序Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis MavenVue等等组成&#xff0c;B/S模式…

【JDBC上篇】什么是JDBC

文章目录1、对JDBC本质的理解2、代码模拟JDBC的本质3、JDBC编程的六步4、通过类加载的方式注册驱动5、属性配置文件与JDBC6、处理查询结果集1、对JDBC本质的理解 Java DataBase Connectivity&#xff08;Java语言连接数据库&#xff09;&#xff0c;其本质是SUN公司指定的一套…

CSP22.3 T4通信系统管理

之前在CCF CSP认证2022年3月完整题解这篇博客记录了自己花了两天时间乱搞出来的方法&#xff0c;但是实际上动态维护区间最值&#xff0c;通过setsetset实现会更简洁&#xff0c;用优先队列需要额外开数组记录堆中节点的有效性。 而且在处理额度失效上&#xff0c;我也使用了最…

教你用响应式建站平台搭建网站

响应式网站搭建大家知道是什么吗&#xff1f;我们可以经常听到PC端网站、移动端网站&#xff0c;这些就是为特定终端而制作的网站版本&#xff0c;而响应式网站就是一个网站能够兼容多个终端&#xff0c;而不是为每个终端做一个特定的版本。那么我们怎么用响应式建站平台搭建网…

基于极限学习机(ELM)进行多变量用电量预测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f389;作者研究&#xff1a;&#x1f3c5;&#x1f3c5;&#x1f3c5;本科计算机专业&#xff0c;研究生电气学硕…