C语言指针精简版(三)

news2024/11/17 4:44:58

目录

字符指针变量

剑指offer中经典题:

数组指针变量

⼆维数组传参的本质

函数指针变量

typedef关键字

函数指针数组

什么是函数指针数组?

为什么要使用函数指针数组?

转移表

计算器的⼀般实现:

使用函数指针实现: 


字符指针变量

我们先看一行代码: 

const char* pstr = "hello bit.";//这⾥是把⼀个字符串放到pstr指针变量⾥了吗?

事实上它的本质是把⼀个字符串常量hello bit的⾸字符 h 的地址存放到指针变量 pstr 中。

剑指offer中经典题:

#include <stdio.h>
int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const char *str4 = "hello bit.";
 if(str1 ==str2)
 printf("str1 and str2 are same\n");
 else
 printf("str1 and str2 are not same\n");
 
 if(str3 ==str4)
 printf("str3 and str4 are same\n");
 else
 printf("str3 and str4 are not same\n");
 
 return 0;
}

会出现以上的结果是因为: C/C++会把常量字符串存储到单独的⼀个内存区域,当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。 所以str1和str2不同,str3和str4相同。

数组指针变量

学习数组指针变量之前请先记住以下两点:

数组指针  !=  指针数组

指针数组是存放指针的数组,数组指针是存放整个数组的地址,而非数组首元素地址

格式:数组类型(*数组指针变量名)[数组元素个数] = &数组名

!!!一定要加上(),否则就会变成int* p[10],这是指针数组而不是数组指针!!!

作用:存放整个数组的地址

实例:

Int arr[10];

Int(*p)[10] = &arr;

        加上()是因为[]的优先级要⾼于*号,所以必须加上()来保证p先和*结合形成(*p),此时p为数组指针变量,指向的是一个元素个数为10个的整型数组

#include <stdio.h>
int main()
{
    int arr[10] = { 0 };
    int(*p)[10] = &arr;
    return 0;
}

调试也能看到数组指针变量p存储了整型数组arr的地址,且二者的类型也是一样的......

⼆维数组传参的本质

过去我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们是这样写的:

#include <stdio.h>
void test(int a[3][5], int r, int c)
{
 int i = 0;
 int j = 0;
 for(i=0; i<r; i++)
 {
 for(j=0; j<c; j++)
 {
 printf("%d ", a[i][j]);
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
 test(arr, 3, 5);
 return 0;
}

上述代码的写法是实参是⼆维数组,形参也写成⼆维数组的形式,那还有什么其他的写法吗?是否可以利用之前学过的数组指针变量的知识来写?

关于第二种传参方式的书写思路如下:

①⼆维数组的⾸元素即第⼀⾏的⼀维数组

②由于数组名是数组⾸元素的地址,故⼆维数组的数组名表⽰的就是第一个⼀维数组首元素的地址

③我们用一个数组指针变量指向二维数组的数组名,这样就可以遍历二维数组中的每一个元素

#include <stdio.h>
void test(int (*p)[5], int r, int c)
{
 int i = 0;
 int j = 0;
 for(i=0; i<r; i++)
 {
     for(j=0; j<c; j++)
     {
         printf("%d ", *(*(p+i)+j));
         //等价于printf("%d ", p[i][j]);
     }
     printf("\n");
 }
}

int main()
{
 int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
 test(arr, 3, 5);
 return 0;
}

结论:⼆维数组传参,形参的部分可以写成数组或指针的形式

函数指针变量

格式:函数类型(指针变量)(函数形参类型) =  函数名

只需要写函数形参类型即可,不需要再写形参名

我们先来看一段代码:

#include <stdio.h>
void test()
{
	printf("hehe\n");
}
int main()
{
	printf("test: %p\n", test);
	printf("&test: %p\n", &test);
	return 0;
}

通过上述代码我们可以发现:函数是有地址的,函数名就是函数的地址 

        与之前的数组指针变量类似,函数指针变量应该是⽤来存放函数地址的,后续可以通过地址来调⽤函数的:

#include <stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int(*pf3)(int, int) = Add;
	printf("%d\n", (*pf3)(2, 3));
	printf("%d\n", pf3(3, 5));
	return 0;
}

上述代码就是对函数指针变量的使用了......

《C陷阱和缺陷》中有这样一段代码:

Void (* signal(int ,void(*)(int) ) (int)

        首先我们可以理解的是signal是一个函数名,(int , void(*)(int))是signal函数的两个参数,一个是int型,另一个是函数指针类型,该函数指针类型指向的函数参数是int型,返回类型是void,signal(int,void(*)(int))就相当于对signal函数的声明,如果我们把这个函数声明的整体假设为m,那么这行代码就会变成void(* m)(int),*m就是一个新的函数指针,该函数指针指向的函数参数是int型,返回的类型为void型。

typedef关键字

作用:类型重命名的,可以将复杂的类型简单化

⽐如,你觉得 unsigned int 写起来不⽅便,如果能写成 uint 就⽅便多了,那么我们可以使⽤:

typedef unsigned int uint;
//将unsigned int 重命名为uint

同样的我们也可以将指针类型重命名,将 int* 重命名为 ptr_t ,这样写:

 Typedef  int* ptr_t;

但是对于数组指针和函数指针稍微有点区别,⽐如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t ,那可以这样写:

typedef int(*parr_t)[5]; //新的类型名必须在*的右边

函数指针类型的重命名也是⼀样的,⽐如将 void(*)(int) 类型重命名为 pf_t ,就可以这样写:

typedef void(*pfun_t)(int);//新的类型名必须在*的右边

函数指针数组

什么是函数指针数组?

函数指针数组就是把多个函数的地址存放在一个数组中

格式:返回类型(*数组名[函数个数])(形参类型,形参类型) = (函数名,函数名)

int (*parr1[3])(int,int) = (Add,Sub);

        其中,parr1 [3]表示一个有三个元素的数组,数组类型就是 int (*)(int,int) ,指向(int,int)返回值是int型的函数指针变量,数组元素为Add 和 Sub

为什么要使用函数指针数组?

当函数的返回值一样时为了简化代码可以将函数指针放在指向同一个指针类型的数组中,比如:

#include <stdio.h>
int Add(int x, int y)
{
        return x + y;
}

int Sub(int x, int y)
{
        return x - y;
}

int main()
{        
        int* arr[10];
        int (*pArr[4])(int, int) = { Add,Sub };
        return 0;
}

转移表

计算器的⼀般实现:

#include <stdio.h>
int add(int a, int b)
{
        return a + b;
}

int sub(int a, int b)
{
        return a - b;
}

int mul(int a, int b)
{
        return a * b;
}

int div(int a, int b)
{
        return a / b;
}

int main()
{
int x, y;
int input = 1;
int ret = 0;
do
        {
        printf("*************************\n");
        printf(" 1:add 2:sub \n");
        printf(" 3:mul 4:div \n");
        printf(" 0:exit \n");
        printf("*************************\n");
        printf("请选择:");
        scanf("%d", &input);
        switch (input)
          {
             case 1:
                printf("输⼊操作数:");
                scanf("%d %d", &x, &y);
                ret = add(x, y);
                printf("ret = %d\n", ret);
                break;
             case 2:
                printf("输⼊操作数:");
                scanf("%d %d", &x, &y);
                ret = sub(x, y);
                printf("ret = %d\n", ret);
                break;
             case 3:
                printf("输⼊操作数:");
                scanf("%d %d", &x, &y);
                ret = mul(x, y);
                printf("ret = %d\n", ret);
                break;
             case 4:
                printf("输⼊操作数:");
                scanf("%d %d", &x, &y);
                ret = div(x, y);
                printf("ret = %d\n", ret);
                break;
             case 0:
                printf("退出程序\n");
                break;
             default:
                printf("选择错误\n");
                break;
          }
       } while (input);

return 0;

}

使用函数指针实现: 

//使⽤函数指针数组的实现:
#include <stdio.h>
int add(int a, int b)
{
        return a + b;
}

int sub(int a, int b)
{
       return a - b;
}

int mul(int a, int b)
{
        return a*b;
}

int div(int a, int b)
{
        return a / b;
}

int main()
{
int x, y;
int input = 1;
int ret = 0;
int(*p[])(int x, int y) = { 0, add, sub, mul, div }; //转移表
        do
        {
        printf("*************************\n");
        printf(" 1:add 2:sub \n");
        printf(" 3:mul 4:div \n");
        printf        (" 0:exit \n");
        printf("*************************\n");
        printf( "请选择:" );
        scanf("%d", &input);
        if ((input <= 4 && input >= 1))
                {
                        printf( "输⼊操作数:" );
                        scanf( "%d %d", &x, &y);
                        ret = p[input](x, y);
                        printf( "ret = %d\n", ret);
                }
        else if(input == 0)
                {
                        printf("退出计算器\n");
                }
        else
                {
                        printf( "输⼊有误\n" );
               }
         }while (input);  
 return 0;
}

~over~
 

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

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

相关文章

MyBatisPlus(二十二)代码生成器

使用场景 使用代码生成器&#xff0c;根据数据库表&#xff0c;自动生成对应的 Entity&#xff0c;Mapper&#xff0c;Service&#xff0c;Controller 。 代码 依赖 两个依赖&#xff1a; 生成器依赖模板依赖 <dependency><groupId>com.baomidou</groupId&…

思维导图Xmind2023安装教程分享

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;xmind 获取 1、解压压缩包得到以下文件。 2、如果“winmm.dll”被系统删除不见&#xff0c;打开屏幕右下角处“windows安全中心”&#xff0c;在历史记录里将已删除的还原即可。 3、以管理员身份打开“Setup”。 4、…

Win10如何彻底关闭wsappx进程?

Win10如何彻底关闭wsappx进程&#xff1f;在Win10电脑中&#xff0c;用户看到了wsappx进程占用了大量的系统资源&#xff0c;所以想结束wsappx进程&#xff0c;提升电脑的运行速度。但是&#xff0c;用户们不知道彻底关闭掉wsappx进程的方法&#xff0c;那么接下来小编就给大家…

windows编译zlmediakit

开发环境搭建 使用visual studio 2022 打开360软件管家 &#xff0c;选择宝库&#xff0c;输入2022 点击安装 选择下图中的选择项目进行安装&#xff0c;安装路径可以修改为d盘 等待安装完成 打开源码进行编译 双击打开 选择打开文件夹 选择代码文件夹 配置如下&#xff…

视频播放音画同步处理

一、视频播放流程 播放一个视频&#xff0c;一般分一下几步完成 解复用&#xff08;Demux&#xff09;&#xff1a;在媒体文件中将音频数据、视频数据、字母数据分离出来。 二、播放参数说明 视频帧率&#xff1a;一秒钟需要显示的画面&#xff0c;比如25FPS&#xff0c;意思就…

sql注入的其他注入

1.宽字节注入 原因 绕过单双引号转义 ?id1 ?id1 1\ 服务器会把单引号转义&#xff0c;单引号由原来的定义字符串的特殊字符被转义为普通字符。 315c27 非常强烈的暗示 代码 单双引号转义 并且编码变成了gbk 上编码 表 这个是GBK编码表&#xff1a;https://…

可变参数模板+lambda

目录 可变参数模板 引入 介绍 展开参数包的方法 递归 逗号表达式 整体使用 emplace 介绍 ​编辑 使用 模拟实现 代码 示例 lambda 引入 介绍 格式 使用 传参 捕捉 原理 可变参数模板 引入 还记得c语言中的printf吗,可以传入任意数量的变量来打印,非常…

pytorch,tf维度理解RNN

input_t input_t.squeeze(1) 这行代码用于从 input_t 中去除尺寸为1的维度。在深度学习中&#xff0c;经常会出现具有额外尺寸为1的维度&#xff0c;这些维度通常是为了匹配模型的期望输入维度而添加的。 在这里&#xff0c;input_t可能具有形状 (batch_size, 1, feature_dim…

青否数字人SaaS系统5.0发布,支持真人接管实时驱动!

青否数字人SaaS系统5.0正式发布&#xff0c;提供口播视频批量制作7*24小时直播全套解决方案。同时直播间支持真人开麦/输入文字选择音色接管&#xff0c;实时驱动直播间数字人回复。 7*24小时直播 青否数字人客户端选择克隆好的数字人主播&#xff0c;克隆好的声音&#xff0…

实现vue项目和springboot项目前后端数据交互

1、安装node.js 太高版本的win7不支持 这里安装node-v12.16.2-x64.msi&#xff0c;指定安装位置后直接按下一步就可以。npm是node内置的工具 这里配置npm的镜像cnpm&#xff08;提高下载速度&#xff0c;以后用到npm的命令都可以用cnpm命令替换&#xff09;不指定cnpm版本使用…

Tuxera2023最新版本新功能特性

当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。Tuxera 的 Microsoft NTFS for Mac 是一款易于使用的软件&#xff0c;可以在 Mac 上打开、编辑、复制、移动或删…

【论文阅读笔记】 Curated Pacific Northwest AI-ready Seismic Dataset

Curated Pacific Northwest AI-ready Seismic Dataset 太平洋西北部人工智能地震数据集 摘要 描述了一个AI就绪地震数据集包括各种地震事件参数 仪器元数据 地震波行描述地震目录和事件属性&#xff08;事件震级类型&#xff0c;信道类型&#xff0c;波形极性&#xff0c;信…

【框架源码篇 02】Spring源码-手写DI

Spring源码手写篇-手写DI 简单回顾前面的手写IoC的内容。 一、DI介绍 DI(Dependency injection)依赖注入。对象之间的依赖由容器在运行期决定&#xff0c;即容器动态的将某个依赖注入到对象之中。说的直白点就是给Bean对象的成员变量赋值。 在这里我们就需要明白几个问题。 1.…

【进阶C语言】C语言文件操作

1. 为什么使用文件 2. 什么是文件 3. 文件的打开和关闭 4. 文件的顺序读写 5. 文件的随机读写 6. 文本文件和二进制文件 7. 文件读取结束的判定 8. 文件缓冲区 一、文件与文件的意义 1.文件的意义 文件的意义&#xff0c;无非就是为什么要使用文件&#xff1f; &#xff08;1&…

当中国走进全球化的“深水区”,亚马逊云科技解码云时代的中国式跃升

中国跨境贸易中支付金融与服务领域的综合创新型企业连连国际的联席CEO沈恩光发现&#xff0c;眼下&#xff0c;很多跨境电商的出海方式已发生了变化。几年前&#xff0c;它们还主要借助第三方电商平台&#xff0c;而现在&#xff0c;更多公司开始选择通过自主渠道进入海外市场&…

线性代数-Python-01:向量的基本运算 - 手写Vector及numpy的基本用法

文章目录 一、代码仓库二、向量的基本运算2.1 加法2.2 数量乘法2.3 向量运算的基本性质2.4 零向量2.5 向量的长度2.6 单位向量2.7 点乘/内积&#xff1a;两个向量的乘法 --答案是一个标量 三、手写Vector代码3.1 在控制台测试__repr__和__str__方法3.2 创建实例测试代码3.3 完整…

磁盘显示脱机状态如何处理

问题描述&#xff1a; 在磁盘管理可以看到磁盘1是脱机状态 脱机&#xff08;由于管理员设置的策略&#xff0c;该磁盘处于脱机状态&#xff09; 解决方法一&#xff1a;CMD窗口处理 1.打开CMD&#xff0c;运行diskpart 2.输入san&#xff0c;打开san策略&#xff0c; 输入san…

2防火墙:基础知识

看了一下相关视频&#xff0c;感觉要会防火墙&#xff0c;还是得补一下网络基础。看一下谢希仁的《计算机网络》&#xff0c;应该主要看网络层就可以。网络以前学的还可以&#xff0c;但现在也就能记得不到50%&#xff0c;正好重新学习一下&#xff0c;或许会有新的感受。 看完…

S4.2.4.3 Electrical Idle Sequence(EIOS)

一 本章节主讲知识点 1.1 EIOS的具体码型 1.2 EIOS的识别规则 1.3 EIEOS的具体码型 二 本章节原文翻译 当某种状态下,发送器想要进入电器空闲状态的时候,发送器必须发送EIOSQ,也既是:电器Electrical Idle Odered Set Sequence。当然,除非在某些情况下,特殊制定,也是…