指针系列三

devtools/2024/9/23 17:27:00/

文章目录

  • 1.字符指针:
  • 2.数组指针:
  • 3.二维数组传参的本质
  • 4.函数指针变量
    • typedef 关键字
  • 5.函数指针数组
  • 6.转移表

在这里插入图片描述

1.字符指针:

字符指针,也称为字符串指针,是指向内存中的字符或字符串的指针。
在C语言中,字符串被表示为以空字符 '\0' 结尾的字符数组。

#include <stdio.h>int main() 
{// 字符指针的声明和初始化char *str = "Hello, bit!";// 使用字符指针打印字符串printf("字符串: %s\n", str);// 使用指针算术运算访问单个字符printf("第一个字符: %c\n", *str);printf("第二个字符: %c\n", *(str + 1));return 0;
}

解释:

  • 我们声明一个字符指针 str 并将其初始化为字符串 "Hello, bit!"。本质是把字符串hello world的首地址放到了str中。
  • 然后使用 %s 格式说明符打印整个字符串。
  • 使用指针算术运算,我们访问并打印字符串的单个字符。
    在这里插入图片描述
    来看一道字符串相关的笔试题 ——from《剑指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");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}

在这里插入图片描述

2.数组指针:

数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量

int *p1[10];
//p是一个指针变量数组(数组的元素类型都是指针),指针指向整型数组
int (*p2)[10];
//p是一个指针变量,然后指向的是大小为10的整型数组
//(数组元素10个,每个元素类型是int)

[]的优先级是要高于*的,所以必须加上( )来保证p*先结合
在这里插入图片描述

#include <stdio.h>int main() 
{// 声明并初始化整型数组int arr[] = {1, 2, 3, 4, 5};// 声明一个数组指针int *ptr;// 使用数组的基地址初始化数组指针ptr = arr;// 使用数组指针访问数组元素printf("数组元素: ");for (int i = 0; i < 5; i++){printf("%d ", *(ptr + i));}printf("\n");return 0;
}

运行结果
在这里插入图片描述

#include <stdio.h>int main()
{// 声明并初始化整型数组int arr[5] = { 1, 2, 3, 4, 5 };// 声明一个数组指针int (*ptr)[5]=&arr;//得到的是数组地址return 0;
}

在这里插入图片描述

在这里插入图片描述

解释:

  • 我们声明一个整型数组 arr 并将其初始化为一些值。
  • 我们声明一个数组指针 ptr
  • 使用数组 arr 的基地址初始化数组指针 ptr
  • 使用指针算术,我们访问并打印数组的元素。

字符指针和数组指针的区别:

  1. 数据类型:

    • 字符指针(char *)用于指向字符或字符串。
    • 数组指针(int *float *等)用于指向数组的第一个元素。
  2. 用途:

    • 字符指针通常用于字符串的操作和处理。
    • 数组指针用于高效访问数组的元素。

3.二维数组传参的本质

先看不用指针怎么实现二维数组的传参

#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;
}

在这里插入图片描述
这里实参是二维数组,形参也可以写出二维数组
那么用指针怎么写捏
首先我们要明确,二维数组名表示的是第一行的地址
我们可以知道一维数组的类型是int[5],所以第一行第地址数组类型就是int(*)[5]
那就意味着二维数组传参的本质是传递了地址,传递的是这个一维数组的地址

所以我们可以这么写

#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));//*(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;
}

总结:二维数组传参,形参可以写成数组,也可以写成指针
在这里插入图片描述

4.函数指针变量

先看一段代码

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

在这里插入图片描述

所以为了存放函数地址,就有了函数指针变量

void test()
{printf("hehe\n");
}
void(*pf1)() = &test;
void (*pf2)() = test;int Add(int x, int y)
{return x + y;
}
void(*pf3)(int, int) = Add;
void(*pf4)(int x, int y) = &Add;//x和y写上和省略都是可以的

在这里插入图片描述
一个例子

#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陷阱和缺陷》

typedef 关键字

在这里插入图片描述
如果是指针类型,能否重命名呢?其实也是可以的,⽐如,将int*重命名为 ptr_t,这样写:
在这里插入图片描述
但是对于数组指针和函数指针稍微有点区别:
⽐如我们有数组指针类型int(*)[5] ,需要重命名为parr_t,那可以这样写
在这里插入图片描述
新类型名 要在*右边
函数指针类型的重命名也是⼀样的,⽐如,将 void(*)(int)类型重命名为 pf_t,就可以这样写:

在这里插入图片描述

在这里插入图片描述
上面第二段有趣代码的简化

5.函数指针数组

以下哪个会是正确写法呢
在这里插入图片描述
答案是:parr1
parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
int (*)()类型的函数指针。

6.转移表

在这里插入图片描述

函数指针用途:转移表
举例:计算器的一般实现

#include <stdio.h>int add(int a, int b)
{return a + b;
}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 ret = 0;int input= 1;int X, Y;do{printf("1:add 2:sub 3:mul 4:div 0:exit\n");scanf("%d", &input);printf("Enter the value of X: ");scanf("%d", &X);printf("Enter the value of Y: ");scanf("%d", &Y);switch (input) {case 1:ret = add(X, Y);break;case 2:ret = sub(X, Y);break;case 3:ret = mul(X, Y);break;case 4:ret = div(X, Y);break;case 0:printf("退出程序\n");break;default:printf("Invalid option");break;}printf("%d\n", ret);}while(input);return 0;
} 

使用函数指针数组来实现

#include <stdio.h>int add(int a, int b)
{return a + b;
}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 ret = 0;int input = 1;int x, y;int(*p[5])(int x, int y) = { 0,add,sub,mul,div };do{printf("1:add 2:sub 3:mul 4:div 0:exit\n");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("请输入操作数\n");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;
}

未完待续…
在这里插入图片描述
在这里插入图片描述


http://www.ppmy.cn/devtools/39513.html

相关文章

推荐4个可用的github国内镜像

Github是全球最大的代码托管云平台&#xff0c;超过1亿用户在平台上分享代码及数据&#xff0c;深受生物信息学软件开发者的喜爱&#xff0c;并且现在发表文章&#xff0c;若涉及到代码&#xff0c;编辑还要求我们把代码及数据存放在github上&#xff0c;以便检查数据的真实性和…

Android RecyclerView

RecyclerView核心实现官方文档 Once you determine your layout, you need to implement your Adapter and ViewHolder. These two classes work together to define how your data is displayed. The ViewHolder is a wrapper around a View that contains the layout for an…

idea使用前的全局配置,一次配置,多次使用

前提&#xff1a;每次导入一个新的项目&#xff0c;就需要重新设置编码、maven、jdk、git版本等信息。实际每个项目所用到的配置信息是一致的&#xff0c;除非换一家公司&#xff0c;不然不会改动到这些内容。 idea版本&#xff1a;2024.1.1 1.1、全局Maven配置 IDEA启动页面…

使用nginx部署Vue项目

前提是后端已经跨域&#xff01; 下载nginx&#xff0c;在路径下使用cmd打开nginx&#xff0c;关闭nginx使用任务管理器details end task 把dist中的文件都放到html文件夹中 打开conf&#xff0c;找到nginx.conf&#xff0c;编辑以下内容 location就是刚才放dist文件的那个文…

7-zip的介绍

7-Zip 是一款开源的文件压缩工具&#xff0c;它支持多种压缩格式&#xff0c;包括其自己的.7z格式&#xff0c;以及.zip、.tar、.gz、.bzip2等。7-Zip 以其高压缩比和强大的功能而闻名&#xff0c;尤其是在处理.7z格式时&#xff0c;它提供了比传统.zip格式更高的压缩率。 以下…

uniapp开发微信小程序,选择地理位置uni.chooseLocation

<view click"toCommunity">点击选择位置</view>toCommunity() {const that thisuni.getSetting({success: (res) > {const status res.authSetting// 如果当前设置是&#xff1a;不允许&#xff0c;则需要弹框提醒客户&#xff0c;需要前往设置页面…

ios实现拍摄视频与显示在界面上

1、添加录音和拍摄权限 NSMicrophoneUsageDescription Privacy - Camera Usage Description 2、代码 #import "ViewController.h" #import <AVFoundation/AVFoundation.h> #import <MobileCoreServices/MobileCoreServices.h>// 接下来是你的 ViewCont…

部署达梦数据库主从配置详细操作DM8

服务器配置 主库 192.168.81.128 实例名 dm-1 从库 192.168.81.129 实例名 dm-2 以下安装部署主从服务器都操作 关闭防火墙 systemctl stop firewalld && systemctl disable firewalld 注意安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。…