C语言——小知识和小细节15

news2024/11/17 11:51:16

一、二维数组与指针

例一

下面的程序运行结果是什么:

#include <stdio.h>

int main()
{
	int arr[3][2] = { (1,2),(3,4),(5,6) };
	int* p = arr[0];
	printf("%d\n", *p);
	return 0;
}

运行结果:

实际上这里有个小细节,就是二维数组的初始化实际上是不完全初始换,因为,内部用的是小括号,所以这里的 (1,2) (3,4) (5,6) 都是逗号表达式,逗号表达式的结果是最后一个表达式的结果,所以这里的初始化相当于:

int arr[3][2] = { 2,4,6 };

 所以具体的初始化情况:

arr[0] 就代表二位数组第一个子数组的第一个元素的地址,所以 *p 就能访问到二位数组第一个子数组的第一个元素的地址,即为 arr[0][0] ,所以运行结果是2。

例二

下面的程序在32位平台运行的结果是什么:

#include <stdio.h>

int main()
{
	int arr[5][5];
	int(*p)[4];
	p = (int(*)[4])arr;
	printf("%p\n%d\n", &p[4][2] - &arr[4][2], &p[4][2] - &arr[4][2]);
	return 0;
}

运行结果:

下面我们来详细分析:

我们知道对于二维数组在内存中的存储依旧是连续的,就像一维数组那样,所以这里我们将其简化为这样(这里一个格子代表一个整型数据):

中间的空格为了方便看出每一个子数组。

在这一步:

int(*p)[4];
p = (int(*)[4])arr;

对于 p 是一个数组指针,类型是 int(*)[4] 然后对于 arr 就是二维数组首个子数组的地址,其类型是 int(*)[5] ,然后被强制转换为了 int(*)[4] 类型,然后赋给了 p ,假设这里的 p 中的数值是0x00ff1200:

但是由于 p 的类型是 int(*)[4] ,所以 p 一次是访问四个整型,对于 &p[4][2] 就相当于 &*(*(p + 4) + 2) ,前面的&与*可以相互抵消,所以还可以表示为 (*(p + 4) + 2) ,具体在图中就是:

然后对于 &arr[4][2] 就是二维数组第五行第三列的元素的地址,在途中就是这样:

我们可以看到这两个指针之间相差了四个整型数据,对于指针减指针,会返回指针之间的元素个数,较大的指针减较小的指针,会返回正数,反之,就返回负数,所以这里会返回-4。

这就可以解释第二个打印结果。

然而第一个结果为什么是0xFFFFFFFC呢?

这是因为%p是打印指针形式的数据,由于指针形式的数据都是非负的,就是打印十六进制非负数,而这里的-4又是负数,所以这里就被转换为正数了:

所以第一个打印结果是FFFFFFFC。

二、指针数组与指针

例一

下面的程序运行结果是什么:

#include <stdio.h>

int main()
{
	const char* str[] = { "hello","world","abc" };
	const char** p = str;
	p++;
	printf("%s\n", *p);
	return 0;
}

运行结果:

对于str数组是字符指针数组,只不过这里的这里的字符指针是指向只读段的字符串的指针,然后及将数组的首元素地址付给 p ,然后 p 自增一,对于某种指针自增一,就会跳过这个指针指向的数据类型的大小,所以这里会跳过一个指针的大小,所以是指向数组第二个元素的指针,所以*p就是访问数组的第二个元素,第二个元素是指向 “world” 字符串的第一个字符 'w' 的指针,所以会打印 world 。

例二

下面的代码运行结果是什么:

#include <stdio.h>

int main()
{
	const char* ps[] = { "hello","fgh","abcde","world"};
	const char** pps[] = { ps + 3,ps + 2,ps + 1,ps };
	const char*** ppps = pps;
	printf("%s\n", **++ppps );//abcde
	printf("%s\n", *-- * ++ppps + 3);//lo
	printf("%s\n", *ppps[-2] +  3);//ld
	printf("%s\n", ppps[-1][-1] + 1); //gh
	return 0;
}

运行结果:

下面我们来具体分析:

具体的对应情况(这里的一个格子代表一个指针元素):

首先是第一句:

printf("%s\n", **++ppps );//abcde

++的优先级是大于*的,所以 ppps 先加加,最开始 ppps 指向 pps 的首元素,即 ppps 中是 pps 的首元素地址,然后加加后,就指向了 pps 的第二个元素,然后解引用就是 pps 的第二个元素 ps + 2,然后 ps + 2 就是 ps 的第三个元素的地址,所以 ps + 2 指向 ps 的第三个元素,然后解引用,就是 ps 的第三个元素,ps 的第三个元素是指向 "abcde" 这个字符串的第一个字符 'a' 的指针,所以会打印 abcde 这个字符串。

然后第二句:

printf("%s\n", *-- * ++ppps + 3);//lo

在上一句时因为加加,ppps 已经变成指向 pps 第二个元素的指针了,

然后这一句又有++,所以 ppps 指向的位置又向后面一了一个元素,所以这时 ppps 就指向 pps 的第三个元素了,

然后解引用,就访问到了 pps[2] ,然后就得到了 ps + 1 ,然后--,就变成了 ps ,这里的 pps[2] 中的 ps + 1 也变成了 ps ,

 ps 是数组 ps 的首元素的地址,所以 ps 指向数组 ps 的第一个元素,然后解引用,得到数组 ps 的第一个元素,即 ps[0] ,ps 的第一个元素是指向字符串 "hello" 的指针,然后因为 + 加操作符优先级在这里是最低的,所以最后进行,这时是 "hello" 字符串中第一个字符 'h' 的指针,然后进行加三操作,实际上会跳过三个字符,下图中每个格子代表一个字符数据:

这时指针指向 "hello" 中的第二个 'l' ,所以这里会打印 lo 。

然后第三句:

printf("%s\n", *ppps[-2] +  3);//ld

对于 ppps ,其在第二句完成后,就指向了 pps 的第三个元素了,我们知道 ppps[-2] 就相当于 *(ppps - 2) ,但这个操作不会使 ppps 指向的内容发生改变,因为没有对 ppps 造成改动,所以进行这个操作后,就得到了 pps 的第一个元素 ps + 3,ps + 3 指向数组 ps 的第四个元素,然后再解引用,就得到了 ps 的第四个元素,也就是 ps[3] ,ps[3] 是一个字符指针,指向字符串 "world" 第一个字符 'w' 的指针,然后对其进行加三操作,就会得到指向 "world" 的第四个字符 'l' 的指针,

所以会打印 ld 。

最后第四句:

printf("%s\n", ppps[-1][-1] + 1); //gh

第三句中没有改变 ppps 指向的内容,所以 ppps 还是指向 pps 的第三个元素,然后进行 ppps[-1][-1] 操作,这个操作就相当于 *(*(ppps - 1) - 1) ,里面的 *(ppps - 1) 的进行后就得到了 pps 的第二个元素了,即 pps[1] ,就是 ps + 2 ,然后外层减一,就变成了 ps + 1 ,ps + 1 指向数组 ps 的第二个元素,解引用后就得到了数组 ps 的第二个元素了,即 ps[1] ,而ps[1] 是一个指向字符串 "fgh" 第一个字符 'f' 的指针,然后进行加一操作,就指向了 "fgh" 的第二个字符 'g' ,

所以会打印 gh 。

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

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

相关文章

《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》【大模型思维链】

目录 前言一、思维链介绍1-1、指令1-2、逻辑依据1-3、示例 二、Cot一般分类2-1、Zero-Shot-CoT2-2、Few-Shot-CoT 三、Cot的好处&缺陷&适用3-1、Cot的好处3-2、Cot的缺陷3-3、Cot的适用 四、变体4-1、自我验证&#xff08;self-consistency checking&#xff09; 总结 …

首发!Llama3纯本地部署攻略!中文方法!

引言 llama3在4月19日刚刚发布&#xff0c;官方的对比结果中在开源模型中堪称世界第一&#xff0c;整好周六日有时间&#xff0c;在魔搭社区上测试一下 一、启动环境 登录魔搭社区&#xff0c;到自己的机器资源&#xff0c;可以看到&#xff0c;可选的机器配置&#xff0c; …

UE5 GAS开发P31 将hud绑定在自己的角色上

在WidgetController内新建一个OverlayAuraWidgetController,然后修改HUD的初始状态 AuraHUD // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/HUD.h" #…

Ubuntu系统下 Nvidia驱动 + cuda驱动 + CuDNN安装与卸载

Ubuntu系统下 Nvidia驱动 cuda驱动 CuDNN安装与卸载 一、NVIDIA驱动与CUDA驱动的区别二、NVIDIA驱动安装与卸载1. 查看系统内核版本2. 查看显卡型号3. 查看是否有显卡驱动4. 禁用nouveau并重启5. 卸载旧版本6. 安装&#xff11;&#xff1a;使用标准Ubuntu仓库进行自动化安装…

四川易点慧电子商务抖音小店:安全正规,购物新选择

在当今互联网高速发展的时代&#xff0c;电子商务已经成为人们日常购物的重要组成部分。四川易点慧电子商务抖音小店作为新兴的电商平台&#xff0c;凭借其安全正规的经营理念和便捷高效的购物体验&#xff0c;正逐渐赢得消费者的信赖和喜爱。 一、平台背景实力雄厚 四川易点慧…

面试十八、容器适配器

容器适配器是一种特殊类型的容器&#xff0c;它们提供了一种不同于常规容器的接口和行为。容器适配器通常是建立在其他容器之上&#xff0c;通过改变接口或添加限制来满足特定的需求或解决特定的问题。 在 C 中&#xff0c;标准库提供了三种常见的容器适配器&#xff1a; 栈&am…

在PostgreSQL中如何处理大对象(Large Objects),例如存储和检索二进制文件?

文章目录 存储二进制文件为大对象步骤 1&#xff1a;创建一个大对象步骤 2&#xff1a;写入数据到大对象 检索大对象为二进制文件步骤 1&#xff1a;打开大对象以进行读取步骤 2&#xff1a;从大对象读取数据 注意事项 PostgreSQL 提供了对大对象&#xff08;Large Objects&…

JavaSE-15笔记【注解(+2024新)】

文章目录 1.注解概述2.几个常用的JDK内置的注解2.1 Deprecated2.2 Override2.3 SuppressWarnings2.4 FunctionalInterface 3.自定义注解3.1 注解也可以定义属性3.2 注解的使用规则补充 4.元注解4.1 Retention4.2 Target4.3 Documented4.4 Inherited4.5 Repeatable 5.通过反射获…

修改npm源--多种方式

2024年&#xff0c;1月22日 npm.taobao.org 域名证书已到期下线。 重置官方源 npm config set registry https://registry.npmjs.org/ 淘宝源&#xff0c;使用最新版&#xff0c;旧版停止了 npm config set registry https://registry.npmmirror.com 查看当前镜像源 npm …

精心整理的不同操作系统不同实现方案网络安全中的权限提升117种提权手法

精心整理的不同操作系统不同实现方案网络安全中的权限提升117种提权手法。 什么是网络安全中的权限提升&#xff1f; 在网络安全领域&#xff0c;了解威胁至关重要&#xff0c;而最关键的威胁之一就是特权升级的概念。从本质上讲&#xff0c;权限升级是指攻击者获得通常为高级用…

阿斯达年代记怎么下载 阿斯达年代记三强争霸下载教程

阿斯达年代记怎么下载 阿斯达年代记三强争霸下载教程 阿斯达年代记是一款三国争霸类型的游戏&#xff0c;在游戏中大家可以体验到三权争霸的刺激场景&#xff0c;在战场中大家不仅可以体验到体验到文化交织还可以感受到战场的残酷&#xff0c;本期小编将会给大家带来阿斯达年代…

vue-manage-system 版本更新,让开发更加简单

vue-manage-system 近期进行了一次版本升级&#xff0c;主要是支持了更多功能、升级依赖版本和优化样式&#xff0c;并且上线了官方文档网站&#xff0c;大部分功能都有文档或者使用示例&#xff0c;更加适合新手上手开发&#xff0c;只需要根据实际业务简单修改&#xff0c;就…

记录:阿里云服务器网站搭建(3)

Docker安装配置Tomcat 拉取镜像 docker pull tomcat:8启动一个tomcat容器用于拷贝配置文件 docker run -d -p 8080:8080 --name tomcat tomcat:8拷贝容器内tomcat配置文件和日志到本地准备映射 docker cp tomcat:/usr/local/tomcat/conf /mydata/tomcat/confdocker cp tomca…

【Linux系统化学习】线程控制

目录 前言 POSIX线程库 线程控制 创建线程 线程终止 pthread_exit()函数 pthread_cancel()函数&#xff08;会在下面线程等待部分详解&#xff09; 线程等待 pthread_join()函数 获取线程退出码 分离线程 线程取消(pthread_cancel()函数&#xff09; 线程ID及进程…

http 3.0 有哪些新特性

HTTP/3 是超文本传输协议&#xff08;HTTP&#xff09;的最新主要版本&#xff0c;其显著特点是放弃了传统的TCP作为传输层协议&#xff0c;转而采用基于UDP的QUIC&#xff08;Quick UDP Internet Connections&#xff09;协议。以下是HTTP/3利用QUIC实现高性能传输的关键特性&…

街道社区信息宣传工作做的好这个投稿方法不能少

作为一名刚刚接手街道社区信息宣传工作的新人,伊始对于如何有效地向各大媒体平台投稿我可谓是一头雾水。那时的日子充满了曲折与挑战,每一步都似乎布满了荆棘。为了让更多居民了解社区的工作动态和服务亮点,我怀揣着满腔热情,着手撰写一篇篇生动详实的新闻稿件。然而,投稿的过程…

mac上VMware fusion net模式无法正常使用的问题

更新时间&#xff1a;2024年04月22日21:39:04 1. 问题 环境&#xff1a; intel芯片的macbook pro VMware fusion 13.5.1 无法将“Ethernet0”连接到虚拟网络“/dev/vmnet8”。在这里显示这个之后&#xff0c;应该是vmnet8的网段发生了冲突&#xff0c;所以导致无法正常使用…

HTML 如何实现一个带间隙的圆环

实际效果&#xff1a; ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5e634cedded9424d96fbe6d46f34f61a.png#pic_center 代码实现&#xff1a; HTML部分&#xff1a; <svg width"500" height"500" viewBox"0 0 100 100">&…

【机器学习-17】数据变换---小波变换特征提取及应用案列介绍

引言 在机器学习领域&#xff0c;数据变换是一种常见且重要的预处理步骤。通过对原始数据进行变换&#xff0c;我们可以提取出更有意义的特征&#xff0c;提高模型的性能。在众多数据变换方法中&#xff0c;小波变换是一种非常有效的方法&#xff0c;尤其适用于处理非平稳信号和…

科学中的概率大师:Avi Wigderson 教授的图灵奖探索

文章目录 前言一、图灵奖的新星二、揭秘计算随机性三、Wigderson 的研究突破四、学术与产业的共鸣五、荣誉与责任总结 前言 在计算机科学的辽阔星空中&#xff0c;随机性与伪随机性犹如迷人的双子星座&#xff0c;挑战着我们的智力边界。Avi Wigderson&#xff0c;普林斯顿大学…