C语言:指针(二)

目录

  • 1.数组名的理解
  • 2.使用指针访问数组
  • 3.一维数组传参的本质
  • 4.二级指针
  • 5.指针数组
  • 6.字符指针变量
  • 7.数组指针变量
  • 8.二维数组传参的本质
  • 9.函数指针变量
  • 10.函数指针数组
  • 11.回调函数
  • 12.qsort函数
  • 13.使用回调函数模拟实现qsort函数

1.数组名的理解

int main() {int arr[] = { 1,2,3 };printf("%p\n", &arr[0]);printf("%p\n", arr);return 0;
}

在这里插入图片描述
从结果可以看出,&arr[0] == arr,这是用为数组名就是地址,而且是首元素的地址
但是,arr作为数组名在两种情况下不表示首元素的地址:

  • sizeof(数组名),sizeof中单独存放数组名表示求整个数组的大小,单位是字节
  • &arr,&arr是&后面直接加上一个数组名,它表示整个数组的地址。(&arr在数值上可能与&arr[0]相同,但是本质上是不一样的,即&arr[0] == arr != &arr )
    除此之外,数组名都表示首元素的地址。
    在这里插入图片描述
    其实arr与&arr的区别不在于直接打印的数值上,而在于运算上,
int main() {int arr[] = { 1,2,3 };printf("%p\n", &arr[0]);printf("%p\n", &arr[0]+1);printf("%p\n", arr);printf("%p\n", arr+1);printf("%p\n", &arr);printf("%p\n", &arr+1);return 0;
}

在这里插入图片描述
可以看出,arr和&arr[0]加一的结果都是跳过4个字节,而&arr则跳过12个字节(E8-F4 =(15 * 16 ^ 1 + 4 * 16 ^ 0)- ( 14*16^1 + 8 *16 ^0) =12).
&arr表示整个数组,加一表示跳过整个数组,数组一共3个int类型的数据,所以一次跳过12个字节。

2.使用指针访问数组

数组可以使用下标引用操作符来访问,比如:

int ret = arr[9];

既然数组名相当于地址,那么还可以这样访问:

int* p = &arr[9];
int ret = *p;

3.一维数组传参的本质

以前将数组作为参数传递给函数时需要将数组的数据个数一起传递给函数,那么,不传递数据个数可以吗?

void test(int arr[]) {int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz2);
}
int main() {int arr[] = {1,2,3,4,5};int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

在这里插入图片描述
从结果来看是不行的,
其实,将数组作为参数是将数组的首元素的地址作为参数传递给函数
所以,在函数内部使用sizeof(arr)实际上计算的是一个地址的大小。正因为参数部分的本质是指针,所以不能不传数据个数

4.二级指针

指针变量也是变量,是变量就有地址,所以二级指针是用来存放一级指针变量的地址的
在这里插入图片描述
画图说明:
在这里插入图片描述
对于二级指针的运算:

  • *ppa通过对ppa中的地址解引用,找到的是pa,*ppa访问的就是p
  • **ppa先对ppa解引用得到pa然后对pa解引用得到a

5.指针数组

存放整型的数组叫做整型数组
存放字符的数组叫做字符数组
那么存放指针的数组就叫做指针数组

在这里插入图片描述

6.字符指针变量

在指针的类型中有一种指针类型叫做字符指针char*
在这里插入图片描述
还有一种使用方法:

int main() {const char* p = "abcdef";printf("%s\n", p);return 0;
}

这种表示方法相当于将字符串看作为一个字符数组,指针变量p存放的不是字符串而是首字符’a‘的地址。
如果两个指针指向同一个字符串,那么不会开辟两个空间来存放,也就是说两个指针指向的是同一个内存

7.数组指针变量

存放整型数据地址的指针叫做整型指针
存放字符型数据的指针叫做字符指针
那么存放数组的地址的指针叫做数组指针

指针数组是数组,而数组指针是变量

int (*P)[5];

p先于*结合说明p是一个指针,再于【】和 int结合说明他是一个数组指针,数组元素类型是int。

数组自指针的初始化:

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

在这里插入图片描述
&arr == p

8.二维数组传参的本质

当我们将二位数组作为参数传递给函数时,其实传递的是第一行的地址(不是第一个元素的地址)

void test(int(*p)[3], int r, int c) {for (int i = 0; i < r; i++) {for (int j = 0; j < c; j++) {printf("%d ", *(*(p + i) + j));}printf("\n");}
}
int main() {int arr[2][3] = { {1,2,3},{2,3,4} };test(arr, 2, 3);return 0;
}

因为传递的是第一行元素的地址,那么该地址就该用函数指针来接收。
在这里插入图片描述

9.函数指针变量

函数也有地址,那么该地址就可以使用指针变量来接受,那么该指针变量就是函数指针变量。

int (*p)(int, int);

在这里插入图片描述
可以看出函数名就是函数的地址,也可以使用&函数名来获得函数的地址。
要将函数的地址存放起来,就可以使用函数指针变量
在这里插入图片描述
可以使用函数指针变量来调用函数

void test() {printf("haha\n");
}
int main() {int(*p)() = test;p();return 0;
}

在这里插入图片描述

10.函数指针数组

函数指针是用来存放函数的地址的,那么有很多函数,要将它们的地址存放在一起,那么就可以使用函数指针数组。

int (*p[10])(int, int);

p先于【】结合说明是一个数组,那么数组的内容就是int (*)().

int Add(int x, int y) {return x + y;
}
int Sub(int x, int y) {return x - y;
}
int Mul(int x, int y) {return x * y;
}
int Div(int x, int y) {return x / y;
}
void Menu() {printf("**************************\n");printf("*****1.加法    2.减法*****\n");printf("*****3.乘法    4.除法*****\n");printf("*****0.退出          *****\n");printf("**************************\n");
}
int main() {int n = 0;int num1 = 0, num2 = 0;int(*p[5])(int, int) = { 0,Add,Sub,Mul,Div };do {Menu();printf("请输入要选择的功能:>");scanf("%d", &n);if (n >= 1 && n <= 4) {printf("\n请输入两个数用于计算:>");scanf("%d%d", &num1, &num2);printf("\n计算结果:%d\n", (*p[n])(num1, num2));}else if (n == 0) {printf("已退出\n");break;}else {printf("选择错误,重新选择:>");}} while (n);return 0;
}

这个代码实现了一个简单的计算器。
int( * p[5])(int, int) = { 0,Add,Sub,Mul,Div };
这段代码就是将四个函数的地址放在一个函数指针数组里面
( * p[n])(num1, num2);
这段代码函数指针数组来调用函数n表示想调用哪个函数,num1和num2就是传递给函数的参数

11.回调函数

回调函数就是一个通过函数指针调用的函数
如果将函数的指针作为一个参数传递给另一个函数,但这个指针被用来调用其所指的函数时,被调用的函数就是回调函数。

void test2() {printf("hahaha\n");
}
void test1(void (*test2)()) {printf("haha\n");test2();
}
int main() {test1(test2);return 0;
}

在这里插入图片描述
在main函数中,将test2的地址传递给test1,然后test1用函数指针变量来接收,然后调用test2函数,那么test2函数就是回调函数。

12.qsort函数

qsort函数的功能是将任意类型的数据排列,底层原理是快速排序。

#include<stdlib.h>void com_arr(const void* p1, const void* p2) {return *(int*)p1 - *(int*)p2;
}void print(int arr[], int sz) {for (int i = 0; i < sz; i++) {printf("%d ", arr[i]);}printf("\n");
}
int main() {int arr[] = { 5,2,1,7,3,4,6,14,8 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);qsort(arr, sz, 4, com_arr);print(arr, sz);return 0;
}

在这里插入图片描述
qsort函数需要4个参数,第一个参数是数组首元素的地址,第二个参数是数组中元素的个数,第三个参数是数组中数据类型的大小,第四个参数是一个函数,作用是实现排序这种数据的方法。
在上述代码中排序整型数组中的数据,那么第四个参数就可以让两个整数相减,返回负数表示第一个元素小于第二个元素,反之大于。

13.使用回调函数模拟实现qsort函数

我们可以采用冒泡排序的方式来实现qsort函数

int Method(const void* p1, const void* p2) {//用以判断两个数时候该交换return (*(int*)p1 - *(int*)p2);
}void Swap(void* p1, void* p2 ,int sz) {for (int i = 0; i < sz; i++) {char tmp = *((char*)p1 + i);*((char*)p1 + i) = *((char*)p2 + i);*((char*)p2 + i) = tmp;}
}
void Maopao(void* arr, int sz, size_t num, int (*method)(void*, void*)) {for (int i = 0; i < sz - 1; i++) {for (int j = 0; j < sz - 1 - i; j++) {if (method((char*)arr + j * num, (char*)arr + (j+1) * num) > 0){Swap((char*)arr + j * num, (char*)arr + (j+1) * num, num);}}}
}
int main() {int arr[] = { 4,2,6,1,7,5,9,8 };int sz = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < sz; i++) {printf("%d ", arr[i]);}printf("\n");Maopao(arr, sz, sizeof(arr[0]), Method);for (int i = 0; i < sz; i++) {printf("%d ", arr[i]);}return 0;
}

在这里插入图片描述

/考研势在必行/

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

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

相关文章

Unity(第十八部)物理力学,碰撞,触发、关节和材质

1、重力 刚体组件 英文中文描述RigidBody刚体组件physics->rigidbody &#xff0c;刚体组件使一个物体有了质量&#xff0c;重力等。&#xff0c;use gravity 勾选后&#xff0c;物体才会受到重力&#xff0c;会自动下落&#xff0c;取消勾选就不会。&#xff0c;&#xf…

selenuim[1]($x(‘xpath语法’)、WebDriverWait())

文章目录 初学selenuim记录1、执行driver webdriver.Chrome()后很久才打开浏览器2、浏览器多元素定位 $x(‘xpath语法’)3、打开浏览器driver.get("网址")执行了很久才开始定位元素&#xff1a;等待&#xff08;1&#xff09;driver.set_page_load_timeout(t)&#…

超越CPU和GPU:引领AI进化的LPU

什么是CPU CPU&#xff08;Central Processing Unit&#xff09;是由数十亿个晶体管构成的&#xff0c;可以拥有多个处理核心&#xff0c;通常被称为计算机的“大脑”。它对所有现代计算系统至关重要&#xff0c;因为它执行计算机和操作系统所需的命令和进程。CPU在决定程序运…

【Linux C | 网络编程】gethostbyaddr 函数详解及C语言例子

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

JavaSE面试——hashcode和equals

对象调用 hashCode 方法后&#xff0c;会返回一串 int 类型的数字码 java 规定&#xff1a; 1. 两个对象的 hashCode() 相等&#xff0c;那他们的 equals() 不一定相等 2. 两个对象的 equals() 相等&#xff0c;那他们的 hashCode() 必定相等 3. 重写 equals() 方法时一定要…

三天学会阿里分布式事务框架Seata-SpringCloud Alibaba分布式基础案例搭建

锋哥原创的分布式事务框架Seata视频教程&#xff1a; 实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;_哔哩哔哩_bilibili实战阿里分布式事务框架Seata视频教程&#xff08;无废话&#xff0c;通俗易懂版&#xff09;共计10条视频&…

日志到filebeat-->logstash-->elastic-->kibana

1、日志到filebeat。 cat /etc/filebeat/filebeat.yml filebeat.inputs: - type: syslog format: rfc3164 protocol.udp: host: "0.0.0.0:514" output.logstash: hosts: ["localhost:5044"] 验证方式: tcpdump -i 网卡名称 udp port 514 2、…

瑞吉苍穹外卖如何拓展?已经经过不同公司多轮面试。项目中会问到哪些问题?以及问题如何解决?

别催了&#xff0c;别催了&#xff0c;先收藏吧。 作者大大正在加班加点完成。 文章会尽快发布&#xff0c;关注收藏&#xff0c;尽请期待。 想要加入并查阅作者的知识库可以联系作者 不要白嫖&#xff0c;通过后&#xff0c;附上关注和收藏截图。 已有众多小伙伴加入 目前…

QtCreator报Failed to parse qmlimportscanner output解决

错误如下: 定位错误位置 增加错误信息打印 打印执行命令 执行打印输出的命令,成功返回JSON 但输出的JSON对象不是json格式,而是命令 增加$$成功输出JSON 使用QtCreator12编译一次后,再使用QtCreator13成功编译通过,问题解决

初学者如何使用QT新建一个包含UI界面的C++项目

文章目录 一、下载并安装QT51、下载安装包2、注册/登录账号3、安装qt6 二、新建QT Widget项目1、新建项目并且运行2、易错点&#xff1a;可能运行成功得到UI界面但是会报错&#xff08;原因是使用了中文路径&#xff09; 一、下载并安装QT5 1、下载安装包 进入下载网址 Windo…

面试经典150题【41-50】

文章目录 面试经典150题【41-50】49.字母异位词分组1. 两数之和202.快乐数219. 存在重复元素II128.最长连续序列228. 汇总区间56.合并区间&#xff08;华为面试题&#xff09;57.插入区间452.用最少的箭引爆气球20.有效的括号 面试经典150题【41-50】 49.字母异位词分组 用这种…

TensorBoard的使用,add_image()的使用。

在TensorBoard中&#xff0c;add_image()函数用于将图像数据添加到可视化中。它可以用于显示模型输入、输出、中间特征图等图像数据&#xff0c;以帮助开发者理解模型的运行情况。 add_image()的用法&#xff1a; 使用ctrl点击add_image() 注意&#xff1a;图片类型要求为 t…

机器学习笔记 YOLOv9模型相关论文简读

一、YOLOv9简述 自 2015 年 Yolov1 推出以来,已经出现了多个版本。 基于Darknet的YOLOv2、YOLOv3和YOLOv4 YOLOv5 YOLOv8 基于 Ultralytics。 SCALED-YOLOv4 使用 Pytorch 而不是 Darknet。 YOLOR是YOLOv4的改进。 YOLOX是YOLOv3的改进。 YOLOv6专注于工业应用。 YOLOv7 来自 …

哇去,有了这篇文章,项目中引入了再多的字体包,我都不怕了!!!

通常情况下&#xff0c;我们在开发一个新项目的时候&#xff0c;项目那边通常都会提供一些项目所需的字体包&#xff0c;来满足项目对字体展示的特殊需求。 这部分大家都比较熟悉&#xff0c;就不详细讲了&#xff0c;直接上代码&#xff1a; /* 引入字体包 */ font-face {fo…

异常处理(黑马学习笔记)

当前问题 登录功能和登录校验功能我们都实现了&#xff0c;下面我们学习下今天最后一块技术点&#xff1a;异常处理。首先我们先来看一下系统出现异常之后会发生什么现象&#xff0c;再来介绍异常处理的方案。 我们打开浏览器&#xff0c;访问系统中的新增部门操作&#xff0…

模型优化_如何提高网络/模型的泛化能力?(全面)

目录 1. 以数据为中心的泛化方法 1.1 使用更多数据 1.2 做好数据预处理 特征工程 1.3 数据增强 1.4 调整数据分布 2. 以模型为中心的泛化方法 2.1 使用更大批次 超参数调优 2.2 调整目标函数 2.3 调整网络结构 2.4 屏蔽网络节点 2.5 权值正则化 2.6 偏差-方差权衡…

全国夜间灯光指数数据、GDP密度分布、人口密度分布、土地利用数据、降雨量数据

引言 DMSP/OLS的1992-2013年全球遥感影像&#xff0c;包括三种非辐射定标的夜间灯光影像。三种全年平均影像分别是&#xff1a;无云观测频数影像、平均灯光影像和稳定灯光影像。目前地理遥感生态网可提供全国稳定灯光影像免费下载。稳定灯光影像是标定夜间平均灯光强度的年度栅…

【论文阅读笔记】Explicit Visual Prompting for Low-Level Structure Segmentations

1.介绍 Explicit Visual Prompting for Low-Level Structure Segmentations 低级结构分割的显式视觉提示 2023年发表在IEEE CVPR Paper Code 2.摘要 检测图像中低级结构&#xff08;低层特征&#xff09;一般包括分割操纵部分、识别失焦像素、分离阴影区域和检测隐藏对象。虽…

人造太阳光热模拟能量密度太阳模拟器

人造太阳模拟器其他名称&#xff1a;能量密度太阳能光热模拟能量密度太阳模拟器、能流密度太阳光模拟器、高通量太阳模拟器 高通量能留密度太阳能炉和太阳光模拟器产生高度集中的太阳能和人造光&#xff0c;用于新技术和材料的研究和测试。这使研究人员能够进行制氢实验、太阳…

备战蓝桥杯---线段树基础1

引入&#xff1a;RMQ问题&#xff1a; 什么是RMQ&#xff1f; 显然&#xff0c;我们无法用前缀维护&#xff0c;因此&#xff0c;我们需要用到线段树的知识&#xff1a; 什么是线段树&#xff1f; 线段树是用一种树状结构存储一个连续区间信息的数据结构 下面我们用图解释用…