c语言指针进阶(一)

news2024/11/14 18:04:08

        大家好,我是c语言boom成家宝。今天为大家分享的是c语言中很重要的一个知识点------指针的深入讲解。 

目录

指针     

指针数组

数组指针

·函数指针


什么是指针?

        首先,指针的本质是一个地址,指针在32位机器上的大小是4个字节,在64位机器上的大小是8个字节。指针也有各种类型,其格式如下:

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

           指针的类型可以决定指针解引用时能访问多少个字节的内容,例如int类型我们解引用以后可以调4个字节,char类型1个字节。知晓这个原理以后我们不妨来思考一下下面这几个例子的答案是多少

	  int a[] = { 1,2,3,4 };
	  printf("%d\n", sizeof(a));
      printf("%d\n", sizeof(a+0));
      printf("%d\n", sizeof(*a));
      printf("%d\n", sizeof(a+1));
      printf("%d\n", sizeof(a[1]));
      printf("%d\n", sizeof(&a));
      printf("%d\n", sizeof(*&a));
	  printf("%d\n", sizeof(&a+1));
	  printf("%d\n", sizeof(&a[0]));
	  printf("%d\n", sizeof(&a[0]+1));

                正确答案如下:  内容代码参考博主:初阳785

	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));//16 sizeof(数组名)-计算的是数组总大小-单位是字节
	printf("%d\n", sizeof(a+0));//4/8 这里a表示表示首元素地址 a+0 还是表示首元素地址 地址的大小就是4/8个字节
	printf("%d\n", sizeof(*a));//4 这里的a表示首元素地址 *a 解引用操作拿到第一个元素 数组的每个元素的类型是int int的大小是4个字节
	printf("%d\n", sizeof(a+1));//4/8 a表示首元素地址 a+1 表示第二个元素的地址 归根到底是一个地址 地址的大小就是4/8个字节
	printf("%d\n", sizeof(a[1]));//4 //计算第二个元素的大小。
	printf("%d\n", sizeof(&a));//4/8 &a表示整个元素的地址 但是整个元素的地址 还是个地址 而地址的大小就是4/8个字节
	printf("%d\n", sizeof(*&a));//16 &a表示整个数组的地址 *&a 解引用就拿到整个数组的元素 4*4=16
	printf("%d\n", sizeof(&a+1));//4/8 &a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,所以是4/8个字节
	printf("%d\n", sizeof(&a[0]));//4/8 第一个元素的地址
	printf("%d\n", sizeof(&a[0]+1));//4/8 第二个元素的地址

什么是指针数组?

        指针数组缩句就是数组,例如整型数组就是存放整型的数组,字符串数组就是存放字符串的数组,那么指针数组就是存放指针的数组。

        接下来我们可以使用指针数组来模拟二维数组的实现。代码如下:

int main() {
	int arr1[] = { 1,2,3 };
	int arr2[] = { 4,5,6 };
	int arr3[] = { 7,8,9 };
	int* arr[] = { arr1,arr2,arr3 };//数组指针的创建,类型是int*
	//遍历数组指针内容并打印
	int i =0 ;
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 3; j++) {
			printf("%d ", arr[i][j]);
		}
	}
	return 0;
}

 什么是数组指针?

        数组指针归根结底还是指针,例如整型指针就是存放整型变量地址的指针变量,字符型指针就是存放字符型变量地址的指针,那么数组指针就是存放数组地址的指针变量。

        这两行代码大家认为哪一个是数组指针呢?答案是第二个。第一个是指向int*的一个指针数组,第二个有括号括起来改变优先级的才是数组指针。以下是数组指针的一个简单用法实例。

int main() {
	int arr[5] = { 1,2,3,4,5 };

	//数组内容存放在数组指针中

	int(*p)[5] = &arr;
	return 0;
}

        那数组指针到底在什么场景下使用才方便一些呢?博主给出其中一个答案就是二维数组里面。 代码如下

void Print(int arr[3][5], int row, int col) {
	int i = 0;
	for (i = 0; i < 3; i++) {
		int j = 0;
		for (j = 0; j < 5; j++) {
			printf("%d ", arr[i][j]);//这是大家平时熟悉的正常遍历二维数组的方法
		}
		printf("\n");
	}
}

int main() {
	int arr[3][5] = { 1,2,3,4,5 ,6,7,8,9,10, 11,12,13,14,15 };
	Print(arr, 3, 5);//这里Print函数是自己创建的,不是库函数printf
	return 0;
}

        这是我们平熟悉的常用的遍历并打印二维数组的方法,那我们学习了数组指针过后又可以怎么让形参是指针去遍历二维数组呢?首先二维数组的数组名也是数组名,也表示首元素的地址。那二维数组可以理解为由若干个一维数组组成的数组,所以二维数组首元素的地址也就是第一个一维数组的地址,所以我们实参部分传过去的是一维数组的地址,那我们形参部分就应该用一个数组指针来接收,代码如下:

void Print(int(*p)[5], int row, int col) {
	int i = 0;
	for (i = 0; i < row; i++) {
		int j = 0;
		for (j = 0; j < col; j++) {
			printf("%d ", *(*(p+i)+j));//p+i拿到的就是那一行一维数组的地址,*(p+i)解引用过后就是一行数组的数据
			                             //*(p+i)+j就是挨个遍历,再用*解引用拿到数据

		}
		printf("\n");
	}
}

int main() {
	int arr[3][5] = { 1,2,3,4,5 ,6,7,8,9,10, 11,12,13,14,15 };
	Print(arr, 3, 5);//这里Print函数是自己创建的,不是库函数printf
	return 0;
}

编译结果如图:

        很多小伙伴看到这里或许会觉得很别扭,觉得我不如使用第一种常规的。这是因为接触的少了,看的代码看得少了所以会觉得很奇怪。这里博主强烈建议大家都去使用第二种方法,因为你自己在使用第一种方法的时候其实编译器在处理过程中它自己会转变成第二种来处理,所以直接写成这样在以后的编译中运行效率会更快,占用内存更少。

·什么是函数指针?

        数组指针是指向数组的指针,函数指针当然就是指向函数的指针了。小知识:函数名表示为函数的地址,&函数名也表示函数的地址。如下图

        那函数指针的形式该怎么写呢?举两个例子:如果函数形式是int add(int x,int y),那么函数指针就可以写成:int (*add)(int,int)=&add.    如果函数形式是 void test(char* pc,int arr[10]),那么函数指针可以写成 void (*p)(char* ,int [10])=&test,或者void (*p)(char* ,int *)=&test。函数指针第一个类型表示返回值的类型,然后(*p),然后(参数类型)。那么函数指针可以怎么使用呢,下面代码是一个简单的使用案例

int add(int x, int y) {
	return x + y;
}


int main() {
	int (*p)(int, int)=&add;//函数指针定义
	int r = add(3, 5);
	printf("%d\n", r);
//正常使用add函数进行计算

	int m = (*p)(3, 5);

//使用指针调用add函数

	printf("%d", m);

	return 0;
}

 

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

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

相关文章

python_day3_str

字符串str 按索引下标查找 str Hi, world, follow, admin print(str[0]) print(str[-1])index() str Hi, world, follow, admin print(str.index(world)) #首字母下标 print(str.index(w))字符串.replace&#xff08;字符串1&#xff0c;字符串2&#xff09;&#xff1a;…

【Linux】高级IO(二)

文章目录 高级IO&#xff08;二&#xff09;I/O多路转接之pollpoll服务器 I/O多路转接之epollepoll相关函数epoll工作原理epoll回调机制epoll服务器epoll的优点 高级IO&#xff08;二&#xff09; I/O多路转接之poll poll也是系统提供的一个多路转接接口 poll系统调用也可以…

ruoyi若依 组织架构设计--[ 部门管理 ]

ruoyi若依 组织架构设计--[ 部门管理 ] 部门管理部门查询部门新增部门修改部门删除 部门管理 部门查询 需要注意的是&#xff0c;部门管理也有数据权限&#xff0c;比如A用户分配的数据权限(通过角色分配)是深圳总公司&#xff0c;那么A用户登录后看到的部门也是深圳总公司&am…

2023年前端面试题汇总-数据结构(二叉树)

对于树这个结构,最常见的就是二叉树。我们除了需要了解二叉树的基本操作之外,还需要了解一些特殊的二叉树,比如二叉搜索树、平衡二叉树等,另外还要熟悉二叉树的遍历方式,比如前序遍历、中序遍历、后序遍历、层序遍历。另外还要知道二叉树的常用遍历的方式:深度优先遍历和…

非线性优化知识

这里列下最小二乘的四种解法的优缺点&#xff0e; #mermaid-svg-CLbQz6o8j7JMq9MM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-CLbQz6o8j7JMq9MM .error-icon{fill:#552222;}#mermaid-svg-CLbQz6o8j7JMq9MM .err…

前端开发中的单例模式

在前端开发中&#xff0c;单例模式是一种常见的设计模式&#xff0c;用于确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取该实例。 在JavaScript中&#xff0c;可以使用以下几种方式来实现单例模式&#xff1a; 字面量方式&#xff1a; const singleton {// …

JVM 调优测试Jmeter 压测

Jmeter 内存不足了&#xff0c;修个5个线程吧 测试结果&#xff1a; Jmeter配置参数 5个线程&#xff0c;每个线程1秒跑1000次 测试串行吞吐量 -XX:PrintGCDetails -Xmx128M -Xms128M -XX:HeapDumpOnOutOfMemoryError -XX:UseSerialGC -XX:PermSize32M GC回收4次 吞吐量138…

SQL Server 2008每天自动备份数据库

在SQL Server 2008数据库中。为了防止数据的丢失我们就需要按时的来备份数据库了。要是每天都要备份的话&#xff0c;人工备份会很麻烦的&#xff0c;自动备份的话就不需要那么麻烦了&#xff0c;只要设置好了&#xff0c;数据库就会自动在你设置的时间段里备份。那么自动备份要…

ihrm项目结构详解

大体介绍 云服务的三种模式 Iaas&#xff1a;基础设施即服务 Pass&#xff1a;平台即服务 Saas&#xff1a;软件即服务 系统设计 主键id生成策略 lombok data setter getter noArgs&#xff08;无参构造&#xff09; 模块搭建 1 企业得增删改查 2 全局异常处理器 3 跨域…

选择排序算法介绍

算法介绍 选择排序&#xff08;Selection Sort&#xff09;是一种简单直观的排序算法。它的基本思想是每次从待排序的元素中选取最小&#xff08;或最大&#xff09;的元素&#xff0c;放到已排序部分的末尾&#xff0c;直到全部元素排序完毕。 以下是选择排序的详细步骤&…

【实战】 六、用户体验优化 - 加载中和错误状态处理(下) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十)

文章目录 一、项目起航&#xff1a;项目初始化与配置二、React 与 Hook 应用&#xff1a;实现项目列表三、TS 应用&#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理1~234.用useAs…

java实现一个简单的webSocket聊天demo

java实现一个简单的webSocket聊天demo 一、依赖二、配置准备三、demo代码编写四、启动测试五、编写业务 一、依赖 添加pom文件依赖 <!-- websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter…

IDEA环境配置汇总

1、配置项目编码 2、配置运行看板Services IDEA开启并配置Services窗口 这里已经配置好了&#xff0c;如果没有&#xff0c;就点击&#xff0c;点击Run Configuration Type&#xff0c;选择所需要的&#xff0c;点击即可。 配置spring与docker看板(按照上面的方法来配置&am…

【Python】查询SQL并用柱状图展示

需求&#xff1a; 查询2022年各月订单量&#xff0c;并用柱状图展示 SQL&#xff1a; select date_format(create_time,%Y-%m) as mon ,count(distinct order_id) as ord_cnt from prod.order_info where date_format(create_time,%Y-%m) between 2022-01 and 2022-12 group…

Mac OS装Windows系统开启虚拟化

目录 引言前提macOS开启虚拟化mac下的Windows开启虚拟化双系统开启虚拟化修改启动管理程序开启虚拟化 注意事项 引言 在开发工作中&#xff0c;很多软件需要用到virtual box&#xff0c;但是使用virtual box需要开启虚拟化&#xff0c;而有些苹果笔记本虚拟化是关闭的&#xf…

【GitHub】一条命令快速部署 Kubernetes(k8s) 集群的工具-sealos

Sealos 是一个GitHub上优秀的开源项目&#xff0c;目前项目点赞数已达&#xff1a;10.2k&#xff0c;核心特性&#xff1a; 管理集群生命周期下载和使用完全兼容 OCI 标准的分布式应用定制化分布式应用Sealos Cloud 项目开源协议&#xff1a;Apache-2.0 项目主开发语言&…

NSS [SWPUCTF 2022 新生赛]funny_web

NSS [SWPUCTF 2022 新生赛]funny_web 账号NSS 密码2122693401 私货不去细细研究了&#xff0c;直接看题。 num不等于12345&#xff0c;但是intval&#xff08;num&#xff09;等于12345 ①intval():可以获取变量的整数值intval()中有一个特性&#xff0c;其中若传入1e4&…

tensorboard与torchinfo的使用

目录 1. tensorboard1.1 本地使用1.2 远程服务器使用 2. torchinfoRef 1. tensorboard 1.1 本地使用 只需要掌握一个 torch.utils.tensorboard.writer.SummaryWriter 接口即可。 在初始化 SummaryWriter 的时候&#xff0c;通常需要指定log的存放路径。这个路径默认是 runs/…

Python脚本小工具之文件与内容搜索

目录 一、前言 二、代码 三、结果 一、前言 ​日常工作中&#xff0c;经常需要在指定路径下查找指定类型的文件&#xff0c;或者是指定内容的查找&#xff0c;在window环境中&#xff0c;即可以使用一些工具如notepad或everything&#xff0c;也可以使用python脚本。但在l…

【C++进阶】bitset位图介绍以及模拟实现

文章目录 位图介绍一、位图的引入二、位图的概念 位图模拟实现一、构造函数二、set&#xff0c;reset&#xff0c;test函数三、代码测试四、完整代码 位图介绍 一、位图的引入 先来看下边一道面试题&#xff1a; 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符…