C语言——指针完全版

目录

一、指针的运算

1.1指针 +- 整数

1.2指针 - 指针

二、指针遍历数组

2.1指针遍历数组

1.了解数组名称的含义(&数组名和数组名的区别)。

2.用指针遍历数组 

三、指针数组、数组指针、函数指针

3.1指针数组

3.1.1指针数组的形式

3.1.2指针数组的使用案例

3.2数组指针

3.3函数指针

三、函数指针数组

3.1函数指针数组的形式

3.2函数指针数组的用途:转移表

四、数组作为函数体参数

五、函数中用数组作为返回值

5.1返回静态局部数组的地址

5.2返回文字常量区的字符串的地址

5.3返回堆内容的地址

5.4总结


一、指针的运算

1.1指针 +- 整数

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

1.2指针 - 指针

int main()
{int arr[10] = { 0 };printf("%d\n", &arr[9] - &arr[0]);return 0;
}

当我们想用两个指针相减时,从上图我们可以猜测一下,输出的到底是两地址之间的元素个数还是两个地址的差值(byte)呢?

通过运行我们可以知道,指针 - 指针的结果:指针和指针之间的元素个数。

那么任何两个指针都可以相减吗?从上面的答案我们就可以得到:

指针 - 指针的前提两个指针指向同一块区域,指针类型是相同的。

那么如果用小指针 - 大指针,我们的结果就成了 -9 .

所以我们可以得到更严谨一些的结论:

指针 - 指针的结果:其绝对值为指针与指针之间的元素个数。

二、指针遍历数组

2.1指针遍历数组

1.了解数组名称的含义(&数组名和数组名的区别)。

数组名是数组首元素的地址。有两个例外:
1. sizeof( 数组名 ) ,计算整个数组的大小, sizeof 内部单独放一个数组名,数组名表示整个数组。
2. & 数组名,取出的是数组的地址。 & 数组名,数组名表示整个数组。
除此 1,2 两种情况之外,所有的数组名都表示数组首元素的地址。

我们来看一段代码了解&数组名和数组名的差别。

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

根据上面的代码我们发现,其实 &arr arr ,虽然值是一样的,但是意义应该不一样的。
实际上: &arr 表示的是 数组的地址 ,而不是数组首元素的地址。
数组的地址 +1 ,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是 40.

2.用指针遍历数组 

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。

#include <stdio.h>
int main()
{int arr[] = {1,2,3,4,5,6,7,8,9,0};int *p = arr; //指针存放数组首元素的地址int sz = sizeof(arr)/sizeof(arr[0]);//数组元素个数for(int i = 0; i < sz; i++){printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p+i);}return 0;
}

 可以看到,我们可以通过指针遍历数组的每一个元素:

p+i 其实计算的是数组 arr 下标为i的地址
那么 *(p+1) 就可以访问数组 arr 的每一个元素

三、指针数组、数组指针、函数指针

3.1指针数组

指针数组是存放指针的数组。

3.1.1指针数组的形式

我们先来看一下指针数组的样子(其他类型同理):

int* arr[5];    //数组名称:arr  数组元素个数:5  数组元素的类型:int* 

那么知道指针数组有什么用呢?

3.1.2指针数组的使用案例

我们已经知道数组名在绝大多数情况下表示的是数组首元素的地址,那么我们就可以用指针数组模拟出一个二维数组。

int arr1[] = { 0,1,2,3,4,5 };
int arr2[] = { 1,2,3,4,5,6 };
int arr3[] = { 2,3,4,5,6,7 };int* arr[] = { arr1,arr2,arr3 };

那我们应该怎么去使用这个模拟出来的二维数组呢?

我们直接可以用它的下标进行访问。

区别:

我们模拟出这个数组和真正二维数组的区别其实就是真实的二维数组每个元素的元素地址都是连续的,而模拟出的二维数组它的每个一维数组地址并不是连续的。

3.2数组指针

数组指针是指向数组的指针。

int(*p)[10];/*解释:p先和 * 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。*///这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。

我们知道整形、全精度浮点型等等都有一个数据类型,int、double......                                            当然在这里,数组指针也有它的数据类型。

3.3函数指针

我们可以先来看一段代码

#include <stdio.h>
void test()
{printf("hello!\n");
}
int main()
{printf("%p\n", test);//打印test地址printf("%p\n", &test);//打印&test地址return 0;
}

从运行结果我们可以看出来,函数名和数组名其实具有一样的效果,但是,为了便于观察,以后在我们需要函数地址的时候,我们还是会用 &函数名 来实现

如果我们想用指针存储上面的test函数,我们应该怎么办呢?

void(*pf)() = &test;
pf1先和*结合,说明pf1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void。

由上面我们可以得到:

int max(int a, int b)
{if (a > b)return a;elsereturn b;
}
int main()
{int (*pf2)(int, int) = &max;return 0;
}

这样我们就可以清楚的了解到函数指针的形式。

三、函数指针数组

3.1函数指针数组的形式

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,
比如:
int * arr [ 10 ];
// 数组的每个元素是 int*
那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?
(以上述 int max(int a, int b) 为例,假设函数指针数组存放的都是此类函数)
int( * parr[ 10])( int, int);
parr先和 [ ] 结合,表面parr是个数组。
数组的内容是什么呢?
int (*)(int, int) 类型的函数指针。

3.2函数指针数组的用途:转移表

我们以一个简单的计算器为例,来看看使用函数指针数组的便捷。
准备内容:
未使用函数指针数组时,我们需要根据用户输入情况,一个函数一个函数的调用:
使用函数数组后,我们只需要把准备阶段的四个函数全部封装到一个函数指针数组中:

再接下来使用的时候,我们就可以灵活运用:

是不是简化了非常多!

四、数组作为函数体参数

定义函数体时,当参数为数组时,既可以用数组接收,也可以用指针接收,其中用数组接收与数组的元素下标无关。

五、函数中用数组作为返回值

返回数组其实就是返回指针。

char* fun()
{char str[100] = "hello world!";return str;
}
int main()
{char* pf;pf = fun();printf("%s\n", pf);return 0;
}

5.1返回静态局部数组的地址

上述代码有个明显缺陷:

str 在 fun 函数体内创建,为临时变量,当我们在 main 函数中想用pf接收的时候, str 就已经被销毁了,这时候,我们就可以在 fun 函数内用 static 修饰我们的 str ,来延长它的生命周期。

运行如图:

5.2返回文字常量区的字符串的地址

常量字符串是个常量,一直存在。

5.3返回堆内容的地址

malloc的头文件:

#include<stdlib.h>

malloc 为 str 动态申请内存,大小为100,单位是字节。                                                                动态申请的内存在函数结束后也不会被释放。

堆区内容一直存在,直到 free 才释放。

5.4总结

返回的地址,地址指向的内存的内容得存在,才有意义。

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

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

相关文章

【力扣每日一题】2023.9.7 修车的最少时间

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一个数值&#xff0c;数组里每个元素表示一个老师傅&#xff0c;老师傅修车花费的时间等于数值乘上车辆数的平方。 问我们修理…

编程语言排行榜

以下是2023年的编程语言排行榜&#xff08;按照流行度排序&#xff09;&#xff1a; Python&#xff1a;Python一直以来都是非常受欢迎的编程语言&#xff0c;它简洁、易读且功能强大。在数据科学、机器学习、人工智能等领域有广泛应用。 JavaScript&#xff1a;作为前端开发…

idea:java: Compilation failed: internal java compiler error

java: Compilation failed: internal java compiler error错误 检查下面2个即可&#xff1a;

docker 生成镜像的几个问题

docker 生成镜像的几个问题 根据jdk8.tar.gz 打包Jdk8 镜像失败运行镜像报错差不多是网络ip错误,在网上说重启docker即可解决运行mysql5.7.25 镜像失败向daemon.json文件添加内容导致docker重启失败docker run 命令常用参数根据jdk8.tar.gz 打包Jdk8 镜像失败 首选做准备工作…

卡牌类游戏推荐,卡牌类三国手游排行榜

以下是小编要推荐给大家的关于卡牌类三国手游排行榜的内容。这里有来自各个历史阶段的名将和美女&#xff0c;让你体验最真实的三国战役。你可以将各种战略思维运用到其中&#xff0c;感受步步为营的喜悦&#xff0c;最终赢得战火纷飞的三国&#xff0c;如果想了解每个游戏的具…

浅谈安科瑞ADL200仪表在爱尔兰工厂的应用

摘要&#xff1a;用户端消耗着整个电网80%的电能&#xff0c;用户端智能化用电管理对用户可靠、安全、节约用电有十分重要的意义。构建智能用电服务体系&#xff0c;推广用户端智能多功能仪表、智能用电管理终端等设备用电管理解决方案&#xff0c;实现电网与用户的双向良性互动…

失效的访问控制及漏洞复现

文章目录 渗透测试漏洞原理失效的访问控制1. 失效的访问控制1.1 OWASP TOP 101.1.1 A5:2017-Broken Access Control1.1.2 A01:2021-Broken Access Control 1.2 失效的访问控制类别1.2.1 水平越权1.2.2 垂直越权 1.3 攻防案例1.3.1 DVWA越权 1.4 相关漏洞1.4.1 目录遍历1.4.2 未…

【Redis】Bitmap 使用及应用场景

前言&#xff1a;bitmap 占用空间小&#xff0c;查询效率高&#xff0c;在一些场景中使用 bitmap 是一个很好的选择。 一、bitmap 相关命令 SETBIT - 设置指定位置的比特值&#xff0c;可以设为 1 或 0 例如 SETBIT key 10 1&#xff0c;将在 key 对应的 bitmap 中第10位设置为…

explain 实战-----查看hive sql执行计划

目录 1.join/left join/full join 语句会过滤关联字段 null 的值吗&#xff1f; &#xff08;1&#xff09;join &#xff08;2&#xff09; left join /full join 2.group by 分组语句会进行排序吗&#xff1f; 1.join/left join/full join 语句会过滤关联字段 null 的值吗…

【java】【SSM框架系列】【一】Spring

目录 一、简介 1.1 为什么学 1.2 学什么 1.3 怎么学 1.4 初识Spring 1.5 Spring发展史 1.6 Spring Framework系统架构图 1.7 Spring Framework学习线路 二、核心概念&#xff08;IoC/DI&#xff0c;IoC容器&#xff0c;Bean&#xff09; 2.1 概念 2.2 IoC入门案例 …

CH06_第一组重构(上)

提取函数&#xff08;Extract Function |106&#xff09; 曾用名&#xff1a;提炼函数&#xff08;Extract Function&#xff09; 反向重构&#xff1a;内联函数&#xff08;115&#xff09; 示例代码 function printOwing(invoice) {printBanner();let outstanding calcul…

API安全学习 - crAPI漏洞靶场与API测试思路

crAPI漏洞靶场与解题思路 1. 前置基础1.1 认识crAPI1.2 环境搭建1.3 API的分类与鉴别 2. 漏洞验证2.1 失效的对象级别授权挑战1&#xff1a;访问其它用户车辆的详细信息挑战2&#xff1a;访问其它用户的机械报告 2.2 失效的用户身份验证挑战3&#xff1a;重置其它用户的密码 2.…

NIFI实现JSON转SQL并插入到数据库表中

说明 本文中的NIFI是使用docker进行安装的&#xff0c;所有的配置参考&#xff1a;docker安装Apache NIFI 需求背景 现在有一个文件&#xff0c;里面存储的是一些json格式的数据&#xff0c;要求将文件中的数据存入数据库表中&#xff0c;以下是一些模拟的数据和对应的数据库…

centos7使用docker-compose一键搭建mysql高可用主从集群

docker部署 环境准备 卸载旧版本 yum remove -y docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-selinux \docker-engine-selinux \docker-engine 安装依赖 yum install -y yum-utils \…

伪微分反馈控制(Pesudo-Drivative Feedback Control——PDF)

运动控制-单轴伺服控制带宽分析&#xff08;二&#xff09; - 知乎 (zhihu.com) 伪微分反馈控制_百度百科 (baidu.com) 伺服电机控制器的参数整定_老马过河hhh的博客-CSDN博客 伪微分PIIP控制_yukee10的博客-CSDN博客

docker搭建个人网盘和私有仓库Harbor

目录 1、使用mysql:5.7和 owncloud 镜像&#xff0c;构建一个个人网盘 2、安装搭建私有仓库 Harbor 1、使用mysql:5.7和owncloud&#xff0c;构建一个个人网盘 1.拉取mysql:5.6镜像&#xff0c;并且运行mysql容器 [rootnode8 ~]# docker pull mysql:5.7 [rootnode8 ~]# doc…

Excel VSTO开发10 -自定义任务面板

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 10 自定义任务面板 自定义任务面板&#xff08;有些地方称为侧边面板&#xff09;即CustomTaskPane&#xff0c;这个类在Microsoft…

leetcode 第 361 场周赛

2843. 统计对称整数的数目 核心思想&#xff1a;枚举每一个数是否是对称整数,第一种写法为python写法&#xff0c;第二种为一般写法我觉得更好&#xff0c;非常有思想性。 2844. 生成特殊数字的最少操作 核心思想&#xff1a;枚举特殊数字结尾的几种可能。其实自己做的时候一…

2023/09/07 c++qt day2

#include <iostream>using namespace std; //封装一个学生类 struct stu { private://存放学生的成绩int stu_score[256];//记录学生个数int stu_num; public://用于设置学生个数void setNum(){cout<<"请输入学生的个数"<<" ";cin>&g…

Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作

Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作 目录 Stable Diffuse 之 本地环境部署 WebUI 进行汉化操作 一、简单介绍 二、汉化操作 附录&#xff1a; 一、Install from URL 中出现 Failed to connect to 127.0.0.1 port 7890: Connection refused 错误&#xf…