C语言进阶第二课-----------指针的进阶----------升级版

news2024/12/24 20:54:22

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


指针进阶

  • **作者前言**
    • 前提复习
  • 字符指针
    • 指针数组
    • 数组指针
    • 数组传参和指针传参
    • 函数指针

前提复习

  1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
  2. 指针(指针变量)的大小是固定的4/8个字节(32位平台/64位平台)。
  3. 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
  4. 指针的运算。(数组元素指针相减等于两者之间的元素个数)
  5. 内存单元是有编号的,编号 == 地址 ==指针

字符指针

用法一:

#include<stdio.h>
int main()
{
	char a = 'w';
	char* p = &a;
	return 0;
}

这里的地址使用很简单,下面还有一种用法

#include<stdio.h>
int main()
{
	const char* p = "abcdef";
	printf("%c", *p);
	printf("%s", p);
	return 0;
}

这里的p存储的是字符a的地址,我们可以想象成"abcdef"储存在一个数组中,传入p的值为数组名,也就是首元素的地址,就是a

还有一点需要注意的是"abcdef"是一个常量字符串,不能修改,但是会有些人通过*p来修改,这会造成程序崩溃,但是却不会报出警告,往往我们会加一个const 来把错误显示出来

指针数组

指针数组本质上就是一个数组,只是类型不一样而已
比如 字符数组–存放字符的数组
整形数组—存放整形的数组
指针数组—存放指针的数组,存放在数组中的元素都是指针类型
应用1:

#include<stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6 };
	int arr1[] = { 2,3,4,5,6,7 };
	int arr2[] = { 3,4,5,6,7,8 };
	int arr3[] = { 4,5,6,7,8,9 };
	int arr4[] = { 5,6,7,8,9,10 };
	int* arr5[] = { arr,arr1,arr2,arr3,arr4 };//指针数组
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		int j = 0;
		for (j = 0; j < 6; j++)
		{
			printf("%d ", arr5[i][j]);
		}
		printf("\n");
	}
	return 0;
}

上面代码的示意图

这种效果相当于写出了一个二维数组的效果

应用2:


```cpp
#include<stdio.h>
int main()
{
	char* arr[5] = { "hello bit", "hehe", "penggeC","nitejiuyeke", "C++" };
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%s\n", arr[i]);
	}
	return 0;
}

这里的效果就相当于写成了一个字符串组成的数组,原理就是数组arr元素保存的是字符串首字符地址,通过遍历取出来,然后一一打印出来

数组指针

指针数组是存放指针的数组,
数组指针是啥呢?,
我们可以想象一下,字符指针就是指向字符的指针, 整形指针就是指向整形的指针,所以,数组指针就是指向数组的指针

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;

	char b = 'q';
	char* pr = &b;

	int arr[10];
	int* pa = arr;
	//数组名是首元素的地址
	//存在两个例外
	//sizeof (arr)  这里的arr表示的是整个数组,sizeof(数组名)计算的是整个数组的大小
	// &arr 取出的是整个数组的地址


	return 0;
}

//数组名是首元素的地址
//存在两个例外
//sizeof (arr) 这里的arr表示的是整个数组,sizeof(数组名)计算的是整个数组的大小
// &arr 取出的是整个数组的地址,如果从值的方向考虑就会发现arr和&arr的值是一样的
数组地址是计算
可以看出数组名和 &数组名的差别,指针类型决定了指针+1 加了几个字节

#include<stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int(*p)[5] = &arr;//数组指针,里面的大小必须写 !!!!
	char arr1[100] = "123456";
	char(*pa)[100] = &arr1;//告诉我们pa是一个指针,指向的是char类型的数组地址
	char* arr2[5];
	char* (*pa2)[5] = &arr2;//告诉我们pa2是一个指针,指向的是char*类型的数组地址
	printf("%p\n", p);
	printf("%p\n", arr);
	return 0;
}

数组指针的写法就是 类型 (p)[数组大小,为了好理解我们可以理解为 char p[10],如果写出这样就会变成指针数组了,为了区分开来,才加()区分,指针类似还是char* 没有改变,只是写法不同而已

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int(*pa)[10] = &arr;
	int* p = arr;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d", (*pa)[i]);//如果使用pa[i] 等价于*(pa + i)
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d", p[i]);
	}
	return 0;

输出的时候我们可以这样理解 arr[i] 可以访问元素, p = arr 所以p[i]可以访问元素
但是pa是数组指针 *pa可以消除& 得到arr , (*pa)[i]可以访问元素

一般我们使用数组指针是在二维数组使用的
在使用之前我们回忆一下一维数组传参给函数时

#include<stdio.h>
void print(int* p, int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d ", p[i]); //p[i] == *(p + i)
	}

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


	return 0;
}

p[i] 等价于*(p + i), 所以打印地址一般用 arr + i 或者 &arr[i] 或者 &arr[0] + i

二维数组的应用

#include<stdio.h>
void print(int arr[][3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
void print1(int (*pa)[3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", pa[i][j]);//pa[i] == *(pa + i)
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][3] = { {1,2,3},{2,3,4},{3,4,5} };
	print(arr, 3, 3);
	print1(arr, 3, 3);

	return 0;
}

二维数组的分布
二维数组是一维数组的数组,我们可以想象一下二维数组arr里面的元素是一维数组,传参arr是首元素的地址,也就是把一维数组的整个地址传进去,
这里使用了数组指针pa ,如果要访问第二个元素可以写成 pa[1]

那我们就再扩展一下

int (*parr2)[10];
int (*parr3[10])[5];

第一行的意思就是,parr2是一个数组指针,指向的数组有10个元素,每个元素为整形
第二行代码的意思就是parr3是一个数组,进行存放数组指针的,可以存放10个数组指针,每个数组指针指向一个元素个数为5的数组,并且这个数组的元素类型为int

总结:这里我们要清楚数组指针的使用,及写法,比如 int (*pa)[10] = &arr
如果arr是一维数组,访问每个元素可以写成(pa)[i],不能写成pa[i],因为pa[i]
等价于
(pa + i) ,如果arr为二维数组,我们可以写成pa[i][j]访问每一个元素

数组传参和指针传参

一维数组传参
,数组传参本质上是,传递了首元素的地址数组传参,形参也可以是指针
在这里插入图片描述
数组传参,形参接收,形参的形式可以写成arr[] 或者 arr[大小] 或者 指针变量
如果碰见指针传参指针,我们就要思考要使用哪级指针接收,上图就是二级指针接收arr2数组首元素的地址,arr2数组首元素也是存储地址的

二维数传参
在这里插入图片描述
一级指针传参
在这里插入图片描述
二级指针传参
在这里插入图片描述
int* arr[5] int ** p = arr ,这个也可以
总结:指针传参有很多种传入方法,但是传入的意思是一样的

函数指针

数组指针是指向数组的指针,存放的是整个数组的地址 ----&数组名
那么函数指针是指向函数的指针,存放的是函数的地址,
那怎么得到函数的地址呢?

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	//&函数名就是函数的地址
	//函数名也是函数的地址
	//这两者没有区别
	printf("%p\n", &Add);
	printf("%p\n", Add);
	//函数指针
	int (*pA)(int, int) = Add;//意思就是pA为函数指针 ,指向的函数的类型为int 参数的类型也为int
	int (*pA1)(int, int) = &Add;
	printf("%p\n", pA);
	printf("%p\n", pA1);
	int tr = (*pA)(2, 3);// 解引用pA找到函数,并传入参数
	int re = pA(2, 3);
	printf("%d\n", tr);
	printf("%d\n", re);//这种写法是因为Add和&Add是一样的 ,我们调用函数是Add(2,3),所以pA存储Add,我们也可以使用pA(2,3)效果和调用函数是一样的
	return 0;
}

可以看出获取函数的地址有两种 &函数名或者函数名
我们调用函数除了使用函数名,还可以使用函数指针调用,使用函数指针调用,我们要熟悉函数调用的写法,Add(2,3),因为函数指针存储的是函数名 Add,所以通过函数指针调用函数,可以写成 pA (2,3),或者(*pA)(2,3)(可以理解为解引用找到函数并传参给函数)
在这里插入图片描述
从这个图中我们可以看出函数指针变量的类型

在这里插入图片描述
我们从这张图可以看出
代码1的意思就是 把0 强制类型转换成函数指针类型 ,并且解引用找到函数调用,这个函数没有参数
代码2 是一个函数声明,看到这里是不是很吃惊,那我们分析一下,
在这里插入图片描述
signal函数有两个参数,第一个参数的类型为int 第二个参数的类型是void()(int),因为不可能是函数调用,当我们吧函数去掉就会发现 void ()(int)是一个函数指针类型,如果我们换个类型就很好理解了 int signal( int, void(*)(int) ); 平时我们函数声明就是这样的,只是这个函数指针类型有写法有点特殊,但不改变这就是一个函数指针类型,

如果觉得这样写很麻烦,我们可以把这个函数指针类型重定义
在这里插入图片描述
typedef void(vi_int)(int);注意一下不要写成typedef void()(int) vi_int;这样是不行的

总结:这里我们要熟悉函数指针类型和指针传参 方式有很多但是意思是一样的

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

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

相关文章

腾讯云服务器配置选择方法

腾讯云服务器配置如何选择&#xff1f;CPU内存、带宽和系统盘怎么选择合适&#xff1f;个人用户可以选择轻量应用服务器&#xff0c;企业用户可以选择云服务器CVM&#xff0c;2核2G3M带宽轻量服务器95元一年、2核4G5M服务器168元一年&#xff0c;企业用户可以选择标准型S5云服务…

Gitlab CI/CD笔记-第二天-使用maven打包并且使用主机套接字进行构建并push镜像。

一、安装gitlab-runner 1.可以是linux也可以是docker的 2.本文说的是docker安装部署的。 二、直接上.gitlab-ci.yml stages: # List of stages for jobs, and their order of execution - build-image build-image-job: stage: build-image image: harbor.com:543/docke…

UEFI: 模块和包概述

UEFI规范中有两个最重要的概念&#xff1a;模块&#xff08;Module)和包&#xff08;Package&#xff09;。 模块 Module UEFI上最小的可单独编译的代码单元&#xff0c;或者是预编译的二进制文件比如efi执行文件。 包 Package 由模块、平台描述文件&#xff08;DSC)和包声明…

Leecode长度最小的子数组_209

209.长度最小的子数组 题目建议&#xff1a; 本题关键在于理解滑动窗口&#xff0c;这个滑动窗口看文字讲解 还挺难理解的&#xff0c;建议大家先看视频讲解。 拓展题目可以先不做。 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成…

exchange partition global index

EXCHANGE PARTITION with a Table having a UNIQUE INDEX and PK Constraint. (Doc ID 1620636.1)​编辑To Bottom In this Document Symptoms Changes Cause Solution References APPLIES TO: Oracle Database - Enterprise Edition - Version 11.2.0.3 and later Oracle Da…

day16:static、final、常量、抽象类

一、static 静态变量能否继承&#xff1f; 静态变量属于类&#xff0c;是共享的资源&#xff0c;不认为是被继承的 静态变量不可以定义在静态方法中&#xff0c; 静态方法中先于对象存在&#xff0c; 不能使用 this super 静态方法中可以直接调用静态方法。 静态方法不能直…

MySQL中基础查询语句

用户表user数据如下&#xff1a; iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543famale20北京大学Deijing42315female 23 浙江大学ZheJiang55432male25山东大学Shandong 1&#xff0c;写出ddl语句创建如上表&#xff0c;…

idea更改背景-给idea设置个性化背景

一&#xff0c;具体操作 按两次键盘Shift,打开快速查找/搜索功能 输入setb 选择Set Backgrounf Image 选择本地图片 二&#xff0c;推荐图片网站 Awesome Wallpapers - wallhaven.cc 该网站拥有大量免费高清图片可以白嫖

国内10大云服务器厂商,你用过几个?

国内排名前10的云服务器厂商如下&#xff1a; 1、阿里云。阿里云是国内最大的云计算服务商之一&#xff0c;其云服务器产品具有高可用性、高扩展性和高安全性等优势&#xff0c;深受广大用户的青睐。 2、腾讯云。腾讯云是国内领先的云计算服务商之一&#xff0c;其云服务器产品…

腾讯云轻量应用服务器端口打开方法

腾讯云轻量应用服务器端口放行在哪设置&#xff1f;在防火墙中可以开启端口号&#xff0c;腾讯云轻量应用服务器端口怎么开通&#xff1f;在轻量服务器管理控制台的防火墙中开启端口&#xff0c;如果是CVM云服务器在安全组中开通&#xff0c;腾讯云服务器网以轻量应用服务器开通…

C++——命名空间、输入、输出

在我们接触C之前&#xff0c;C语言中有时候会有使用全局变量&#xff0c;全局变量在使用过程中可能会发生冲突&#xff0c;这个冲突有时会是我们与库之间的冲突&#xff0c;有时又会是我们自己定义的之间的冲突&#xff0c;那么这时候命名空间的出现将很好的解决这个问题&#…

美国访问学者签证怎么样申请成功率高?

近年来&#xff0c;越来越多的人选择申请美国访问学者签证&#xff0c;以便在美国深造、交流学术知识以及拓展国际视野。那么&#xff0c;如何提高申请美国访问学者签证的成功率呢&#xff1f;以下是知识人网小编整理的一些成功申请的建议供您参考。 1.提前准备&#xff1a;提交…

Vue--》打造个性化医疗服务的医院预约系统(五)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

Javascript进阶[面向对象编程]

作者&#xff1a;20岁爱吃必胜客&#xff08;坤制作人&#xff09;&#xff0c;近十年开发经验, 跨域学习者&#xff0c;目前于海外某世界知名高校就读计算机相关专业。荣誉&#xff1a;阿里云博客专家认证、腾讯开发者社区优质创作者&#xff0c;在CTF省赛校赛多次取得好成绩。…

【MySQL】MySQL 数据类型

目录 1. tinyint 类型 2. bit 类型 3. 小数类型 1、float 类型 2、decimal 类型 3. 字符串类型 1、char 类型 2、varchar 类型 4. 日期类型 5. enum和set 1、枚举和集合类型语法 2、枚举和集合类型的查找 6、find_in_set 函数 写在最后&#xff1a; 1. tinyint …

关于Java反射

JAVA反射机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意一个方法和属性&#xff1b;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 要想解…

MyBatis Plus-个人笔记

前言 学习视频 尚硅谷-Mybatis-Plus教程学习主要内容 本文章记录尚硅谷-Mybatis-Plus教程内容&#xff0c;只是作为自己学习笔记&#xff0c;如有侵扰请联系删除 一、MyBatis-Plus简介 1、简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#…

BGP基础实验建邻+宣告实验

实验题目如下&#xff1a; 实验拓扑如下&#xff1a; 实验要求如下&#xff1a; 【1】除R5的5.5.5.0环回外&#xff0c;其他所有的环回均可互相访问 实验思路如下&#xff1a; &#xff08;1&#xff09;合理的IP配置 &#xff08;2&#xff09;合理的BGP配置 &#xff08;…

监控Kubernetes Node组件的关键指标

所有的 Kubernetes 组件&#xff0c;都提供了 /metrics 接口用来暴露监控数据&#xff0c;Kube-Proxy 也不例外。通过 ss 或者 netstat 命令可以看到 Kube-Proxy 监听的端口&#xff0c;一个是 10249&#xff0c;用来暴露监控指标&#xff0c;一个是 10256 &#xff0c;作为…

【IC萌新虚拟项目】代码覆盖率收集与反馈

关于整个虚拟项目&#xff0c;请参考&#xff1a; 【IC萌新虚拟项目】Package Process Unit项目全流程目录_尼德兰的喵的博客-CSDN博客 前言 实际参与过项目的同学一定对质量活动这四个字深恶痛绝&#xff0c;项目进入质量活动阶段时&#xff0c;意味着RTL的时序和面积功耗等主…