【C语言】指针(二)

目录

一、传值调用和传址调用

二、数组名的理解

三、通过指针访问数组

四、一维数组传参的本质

五、指针数组

六、指针数组模拟实现二维数组


一、传值调用和传址调用

指针可以用在哪里呢?我们看下面一段代码:

#include <stdio.h>void Swap(int x, int y)
{int z = x;x = y;y = z;
}
int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}

运行结果如下:

我们发现,并没有完成交换,调试发现:

出现这样的原因:a和b是实参(是真实传递给函数的),x和y是形参,当实参ab传给形参xy时候,形参把实参数据临时拷贝了一份,x,y创建自己的独立空间,因为有自己独立的空间,跟a,b无关,所以修改形参不会影响实参。这种交换方式也叫传值调用。

所以说:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。

措施:可以将a,b的地址传给Swap函数,Swap函数里通过地址间接的操作main函数中的a和b,达到交换的效果。也就是传址调用。

代码如下:

#include <stdio.h>void Swap(int* pa, int* pb)//用指针变量来接收
{int z = *pa;*pa = *pb;*pb = z;
}
int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap(&a, &b);//传地址printf("交换后:a=%d b=%d\n", a, b);return 0;
}

传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量。

  • 未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。
  • 如果函数内部要修改主调函数中的变量的值,就需要传址调用。

二、数组名的理解

数组名就是数组首元素(第一个元素)的地址。

代码如下:

但有两个例外:

  1. sizeof(数组名),sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
  2. &数组名,这里的数组名表示整个数组,所以&数组名取出的是整个数组的地址

除此之外,任何地方使用数组名,数组名都表示首元素的地址。

可能会有疑问,为什么首元素地址(arr)跟整个数组地址(&arr)相同呢?

代码如下:

从值的角度来讲,地址就是一个编号,它们打印出来的地址一模一样,但是意义却不相同,操作arr和&arr带来的结果也是不一样的。

如下代码:

可以看出,&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr都是首元素的地址,类型是int*,+1就是跳过一个整型(元素)。
但是&arr和&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。

也可以这么理解:

arr与&arr都是指针,指针有两个要素:

  • 第一个是地址值,也就指向的位置,打印出来的就是地址值,arr与&arr的地址值是一样的。
  • 第二个是类型(所指向的数据类型),arr指向数组第一个元素,&arr指向数组arr,arr+1后的地址值会偏移一个元素的长度,&arr+1后的地址值会偏移一整个数组的长度,所以arr与&arr类型是不一样的。

三、通过指针访问数组

#include <stdio.h>
int main()
{int arr[10] = { 0 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);int* p = arr;//p存放的数组首元素的地址for (i = 0; i < sz; i++){scanf("%d", p + i);//scanf("%d", arr+i);//也可以这样写}//输出for (i = 0; i < sz; i++){printf("%d ", *(p + i));//输出可以写成:// *(p+i) <==> arr[i] <==> *(arr+i) <==> *(i+arr) <==> i[arr]}return 0;
}

可以发现,数组的下标引用操作符([ ])效果相当于解引用操作符(*)

其实数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移量求出元素的地址,然后解引用来访问的。

四、一维数组传参的本质

之前我们都是在函数外部计算数组的元素个数,那可以把函数传给一个函数后,在函数内部求数组的元素个数吗?

我们来看一段代码:

#include <stdio.h>void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

运行结果如下:

发现sz1计算错误,函数内部没有正确获得数组的元素个数。

原因:

数组名是数组首元素地址,传递的数组名,本质上数组传参传递的是数组首元素地址。

所以函数的形参部分理论上应该用指针来接收首元素的地址。那么在函数内部写sizeof(arr)计算的是一个地址的大小(单位字节),而不是数组的大小(单位字节)。

正因为函数的参数部分本质是指针,所以在函数内部是没办法求数组元素个数的。

代码如下:

void test(int arr[10]) //==>arr[]  参数写成数组形式,本质上还是指针
{
printf("%d\n", sizeof(arr)); //计算⼀个指针变量的⼤⼩
}void test(int* arr) //参数写成指针形式
{
printf("%d\n", sizeof(arr));
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
test(arr);
return 0;
}

上面数组传参的本质是传递了数组首元素的地址,所以形参访问的数组和实参的数组是同一个数组。

形参的数组是不会单独再创建数组空间的,所以形参的数组是可以省略掉数组大小的。

总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

五、指针数组

数组是一组相同类型元素的集合。数组有整形数组,字符数组.....

指针数组:存放指针(地址)的数组。

int* arr1[6];//存放整型指针的数组
char* arr2[10];//存放字符指针的数组

如下图:

指针数组的每个元素是地址,又可以指向一块区域。

六、指针数组模拟实现二维数组

代码如下:

#include <stdio.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 2,3,4,5,6 };int arr3[] = { 3,4,5,6,7 };//数组名是数组首元素的地址,类型是int*的,可以存放在parr数组中int* parr[3] = { arr1, arr2, arr3 };int i = 0;int j = 0;for (i = 0; i < 3; i++){for (j = 0; j < 5; j++){printf("%d ", parr[i][j]);//parr[i][j]<==>*(parr[i]+j)<==>*(*(parr+i)+j)}printf("\n");}return 0;
}

parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数组中的元素。

上述的代码模拟出二维数组的效果,本质上其实不是二维数组。

因为二维数组在内存中是连续存放的,而这三个数组在内存可不一定连续存放。

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

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

相关文章

基于Spring封装一个websocket工具类使用事件发布进行解耦和管理

最近工作中&#xff0c;需要将原先的Http请求换成WebSocket&#xff0c;故此需要使用到WebSocket与前端交互。故此这边需要研究一下WebSocket到底有何优点和不可替代性&#xff1a; WebSocket优点&#xff1a; WebSocket 协议提供了一种在客户端和服务器之间进行全双工通信的…

如何在MATALB中调用libMR

​ 因为个人项目原因,我曾将参考OpenMax源码GitHub - abhijitbendale/OSDN: Code and data for the research paper “Towards Open Set Deep Networks” A Bendale, T Boult, CVPR 2016将其转换到MATLAB使用。 OpenMax 使用极值理论实现对开放集的筛选,在计算得分时需要用l…

异地组网群晖不能访问怎么办?

在日常使用群晖网络储存设备时&#xff0c;我们常常会遇到无法访问的情况&#xff0c;特别是在异地组网时。这个问题很常见&#xff0c;但也很让人困扰。本文将针对异地组网群晖无法访问的问题进行详细解答和分析。 异地组网的问题 在异地组网中&#xff0c;群晖设备无法访问的…

Unity | Spine动画动态加载

一、准备工作 Spine插件及基本知识可查看这篇文章&#xff1a;Unity | Spine动画记录-CSDN博客 二、Spine资源动态加载 1.官方说明 官方文档指出不建议这种操作。但spine-unity API允许在运行时从SkeletonDataAsset或甚至直接从三个导出的资产实例化SkeletonAnimation和Skel…

被耽误了的发明家

高三的某一天&#xff0c;数学焦老师在黑板上推公式&#xff0c;突然花屁股&#xff08;见另一篇博文《数学老师们》&#xff09;上出现了一个光圈。我心里一乐&#xff0c;有人在玩镜子。本来大家对于焦老师的花屁股已经司空见惯了&#xff0c;可以不受干扰地听课&#xff0c;…

HNU-算法设计与分析-作业3

第三次作业【动态规划】 文章目录 第三次作业【动态规划】<1>算法实现题 3-1 独立任务最优解问题<2>算法实现题 3-4 数字三角形问题<3>算法实现题 3-8 最小m段和问题<4>算法实现题 3-25 m处理器问题 <1>算法实现题 3-1 独立任务最优解问题 ▲问…

postgresql安装及性能测试

postgresql安装及性能测试 1. Postgresql介绍 Postgresql是一款功能强大的开源对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;&#xff0c;以其稳定性、扩展性和标准的SQL支持而闻名。它支持复杂查询、外键、触发器、视图、事务完整性、多版本并发控制&#xff08;MV…

Linux(七) 动静态库

目录 一、动静态库的概念 二、静态库的打包与使用 2.1 静态库的打包 2.2 静态库的使用 三、动态库的打包与使用 3.1 动态库的打包 3.2 动态库的使用 3.3 运行动态库的四种方法 四、总makefile 一、动静态库的概念 静态库&#xff1a; Linux下&#xff0c;以.a为后缀的…

Python专题:十五、JSON数据格式

Python的数据处理&#xff1a;JOSN 计算机的主要工作&#xff1a;处理数据 最容易处理的数据就是结构化数据 非结构化数据&#xff1a;视频&#xff0c;文件等 近些年的大数据、数据挖掘就是对互联网中的各种非结构化的数据的分析和处理 半结构化数据 明确的结构属性&…

陪诊服务运用预约小程序的效果是什么

在中高型城市里&#xff0c;陪诊师近些年也很有热度&#xff0c;已经衍生成为一个新的小众行业&#xff0c;不同医院/不同科目等其它情况针对不同群体往往很难完善&#xff0c;比如部分老年人腿脚不便、不认识字、外地语言难以沟通等&#xff0c;陪诊师的作用就尤为凸显. 对相…

[Bootloader][uboot]code总结

文章目录 1、U_BOOT_DRIVER2、DM框架dm_scan_platdatadm_extended_scan_fdt 1、U_BOOT_DRIVER 使用这个宏可以定义一个驱动实例&#xff0c;宏定义是 其中使用的struct driver结构体 使用的ll_entry_declare宏定义是 归结为 2、DM框架 1、 DM框架 DM模型抽象出了以下四个…

16.投影矩阵,最小二乘

文章目录 1. 投影矩阵1.1 投影矩阵P1.2 投影向量 1. 投影矩阵 1.1 投影矩阵P 根据上节知识&#xff0c;我们知道当我们在解 A X b AXb AXb的时候&#xff0c;发现当向量b不在矩阵A的列空间的时候&#xff0c;我们希望的是通过投影&#xff0c;将向量b投影到矩阵A的列空间中&…

ModuleNotFoundError: No module named ‘sklearn‘

ModuleNotFoundError: No module named sklearn 解决办法&#xff1a; pip install scikit-learn

7B2 PRO主题5.4.2免授权直接安装

B2 PRO 5.4.2 最新免授权版不再需要改hosts&#xff0c;直接在wordpress上传安装即可

网站接入百度云防护CDN后回源率非常高原因

最近&#xff0c;有站长反馈网站接入百度云防护后&#xff0c;网站回源率非常高。 今天百度云来给大家讲解下&#xff0c;CDN回源高的原因&#xff1a; 1.动态请求比较多 网站的动态请求很多&#xff0c;一般是回源率高的主要原因&#xff0c;因为CDN对待动态请求是每个请求…

Vue的学习 —— <网络请求库Axios>

目录 前言 正文 一、Axios基本概念 二、安装Axios 三、Axios使用方法 四、向服务器发送请求 前言 在之前的开发案例中&#xff0c;我们通常直接在组件中定义数据。但在实际的项目开发中&#xff0c;我们需要从服务器获取数据。当其他用户希望访问我们自己编写的网页时&a…

定档 11.2-3,COSCon'24 第九届中国开源年会暨开源社十周年嘉年华正式启动!

中国开源年会 COSCon 是业界最具影响力的开源盛会之一&#xff0c;由开源社在2015年首次发起&#xff0c;今年将举办第九届。 以其独特定位及日益增加的影响力&#xff0c;COSCon 吸引了越来越多的国内外企业、高校、开源组织/社区的大力支持。与一般企业、IT 媒体、行业协会举…

网络安全快速入门(十三)linux及vmware软件的网络配置

13.1 前言 在通过我们前面的了解&#xff0c;我们现在已经对Linux的基础知识有了大致的了解&#xff0c;今天我们来大概讲一下关于linux系统及vmware的网络配置问题&#xff0c;在这之前&#xff0c;我们需要对网络有一个大概的认识和了解&#xff0c;话不多说&#xff0c;我们…

01记-“计算机基础知识”

感觉媒体: 直接作用于人的感觉器官&#xff0c;使人产生直接感觉的媒体&#xff1a;声音、图形、图像、动画等。 表示媒体: 为了加工、处理和传输感觉媒体而人为研究、构造出来的一种媒体&#xff0c;常见的有各种编码方式&#xff0c;如文本编码、图像编码和声音编码等。 …

Java中静态方法为什么不能调用非静态成员?

在Java面试中&#xff0c;这个问题经常被问到&#xff0c;因为它不仅涉及到Java的基本语法规则&#xff0c;还深入到了JVM的工作机制。理解这个问题可以帮助面试者更好地掌握Java的静态和非静态成员的区别以及它们在内存中的分配和使用。 静态成员 vs 非静态成员 首先&#x…