当前位置: 首页 > news >正文

【理解指针(四)】

文章目录

  • 一、指针数组
  • 二、指针数组来模拟二维数组
  • 三、字符指针变量
          • 注意:
      • 字符串的例子(曾经的一道笔试题)
  • 四、数组指针变量
    • 1、什么是数组指针变量
    • 2、数组指针怎么初始化
  • 五、二维数组传参的本质
  • 六、函数指针
    • 1、什么是函数指针变量
    • 2、函数的地址
    • 3、使用
    • 4、 `typedef`关键字
  • 结束语

一、指针数组

我们可以先来回顾一下整形数组和字符数组。

  1. 整形数组:

是存放整形的数组
在这里插入图片描述

  1. 字符数组:
    在这里插入图片描述

是指存放字符的数组

类比上面两个例子之后,我们可以知道指针数组就是存放指针的数组,指针数组的每一个元素都是用来存放地址(指针)的。

在这里插入图片描述

二、指针数组来模拟二维数组

首先我们需要知道数组名是指数组首元素的地址

#include<stdio.h>
int main()
{int str[] = { 1,2,3,4,5 };int str1[] = { 3,4,5,6,7 };int str2[] = { 5,6,7,8,9 };int* pa[3] = { str,str1,str2 };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", *(*(pa + i)) + j);}printf("\n");}return 0;
}

我们可以得到如下的结果:
在这里插入图片描述
第一次的for循环是循环的行,第二次的dor循环也就是列,数组名就是数组的首元素,我们这里的pa[i]找到数组元素指向的是整形一维数组,pa[i][j]就是指向整形一维数组的元素。

模拟出⼆维数组的效果,实际上并非完全是⼆维数组,因为每⼀行并非是连续的

画个图方便大家理解:
在这里插入图片描述

三、字符指针变量

我们知道字符指针是char*
常如下使用:

#include<stdio.h>
int main()
{char p = 'e';char* s = &p;printf("%c\n", *s);*s = 't';printf("%c\n", *s);return 0;
}

结果会分别打印出:e 和 t 。

当然还有其他适用方式:

#include<stdio.h>
int main()
{char str[] = "hello world!!!";char* pa = str;printf("%s\n", pa);return 0;
}
注意:

这里的hello world!!!并没有放在指针变量pa中,而是把这个字符串的首字符的地址放在了pa中。
在这里插入图片描述
pa也就是调用字符串中首字符的地址,而字符串的地址也是首字符元素的地址。

字符串的例子(曾经的一道笔试题)

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

这题的答案是str1 and str2 are not samestr3 and str4 are same

我们大致来分析一下:

str1str2都是存的相同的字符串内容,在内存中str1str2是开辟了不同的空间存放相同的内容的,实质上完全没有必要存相同的内容开辟两个空间,两个空间的地址完全不一样,所以会打印出str1 and str2 are not same;而str3str4指向的是⼀个同⼀个常量字符串,C/C++会把常量字符串存储到单独的⼀个内存区域,指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存,所以这里会打印出str3 and str4 are same

四、数组指针变量

1、什么是数组指针变量

首先我们可以来回顾一下:整形指针变量和浮点型指针变量

  1. 整形指针变量:
    存放的是整型变量的指针,能够指向整形数据的指针。
    形如:int* pa

  2. 浮点型指针变量:
    存放的是浮点型变量的指针,能够指向浮点型数据的指针。
    形如:float* pa

那么数组指针变量就是存放的是数组的地址,指向数组数据的指针。
形如:int(*p)[10]

这里的p是自己命名,10 也是根据自己写的代码来写。
p先和*结合,所以p是一个指针变量,指向的是一个大小为10个整形的数组。

综上:p是一个指针,指向一个数组,这就是数组指针。

2、数组指针怎么初始化

数组指针变量是⽤来存放数组地址的

int arr[5]={0};
&arr得到的就是数组的地址
int (*p)[5]=&arr//这个数组的地址存放在数组指针变量中

在这里插入图片描述

五、二维数组传参的本质

(二维数组我们可以看成许多一维数组的组成)

首先我们知道数组名是数组首元素的地址,那么⼆维数组的数组名表示的就是第⼀行的地址,也就是一维数组的地址,⼆维数组传参本质上也是传递了地址,传递的是第一行这个⼀维数组的地址
在这里插入图片描述
我们形参用指针写的形式如下:

#include<stdio.h>
void Shuzu(int(* pa)[5], int a, int b)
{for (int i = 0; i < a; i++){for (int j = 0; j < b; j++){printf("%d ", *(*(pa + 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} };Shuzu(arr, 3, 5);return 0;
}

当然形参我们也可以数组的形式写:

#include<stdio.h>
void Shuzu(int p[][5], int s, int c)
{for (int i = 0; i < s; i++){for (int j = 0; j < c; j++){printf("%d ", 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} };Shuzu(arr, 3, 5);return 0;
}

六、函数指针

1、什么是函数指针变量

通过上面的种种类比我们知道了什么是数组指针,整形指针,那么我们可以知道函数指针变量就是用来存放函数地址的。

2、函数的地址

首先我们可以简单的写一个代码,看看函数是否有地址:

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

在这里插入图片描述
由结果我们可以知道函数有地址,函数名就是我们的地址

如果我们要将函数的地址存放起来,就得创建函数指针变量:

#include<stdio.h>
int Add(int x, int y)
{return x + y;
}int(*pa)(int , int ) = Add;//&Add

在这里插入图片描述
其中==int(*)(int,int)==就是pa函数指针变量的类型。

3、使用

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

可以得出答案是6和11。

为什么第二个打印pa1可以不解引用?

因为pa1这个指针变量存放的是Add的地址,&符号与*相互直接抵消了,所以可以不使用解引用符号。

4、 typedef关键字

typedef是用来类型重命名的

比如:

singed int 可能你觉得每次书写比较麻烦,你就可以直接有时候typedef来重命名
也就是:typedef singed int ty_t,这个时候,想要再使用singed int 就可以直接用ty_t替换,
本质上是一样的

1.但是函数指针的重命名有些许区别:

比如,我们想要把int(*pa)(int )重命名为pa_t:

typedef int(*pa_t)(int);  //新类型的名字必须在*号的右边

2.数组指针重命名也是如此:

比如:我们需要把int(*pc)[10]重命名为py_y

typedef int(*py_y)[10];  //新类型的名字也需要在*号的右边

结束语

这次的内容可能有些多,但是比较好理解,希望大家可以拿到自己想要的offer,最后,如果文章有什么打错字的地方,希望大家不要介意,也希望大家可以给我提出来。
最后,祝大家每天都开开心心,我们下次再见
在这里插入图片描述

http://www.lryc.cn/news/328415.html

相关文章:

  • Ribbon简介
  • 【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
  • 通过 Docker 实现国产数据库 OpenGauss 开发环境搭建
  • 【Java】LinkedList模拟实现
  • ubuntu下mysql常用命令
  • 燃气官网安全运行监测系统-阀井燃气监测仪-旭华智能
  • vue 文件预览(docx、.xlsx、pdf)
  • 云架构(二) 大使模式
  • .NET Path类库的特殊方法
  • 【JVM】JVM常用性能调优参数详细介绍
  • React中的受控组件与非受控组件
  • uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题
  • react native 使用ScrollView实现下拉更新,上拉加载更多
  • vue2完结
  • 前端网页之间传递参数
  • 【常见面试题】Golang中,协程数最多可以开多少个?
  • RabbitMQ基础笔记
  • 大型项目管理神器:掌握yarn monorepo的安装和使用
  • 算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
  • 2013年认证杯SPSSPRO杯数学建模A题(第一阶段)护岸框架全过程文档及程序
  • 【3】3道链表力扣题:删除链表中的节点、反转链表、判断一个链表是否有环
  • mongodb sharding分片模式的集群数据库,日志治理缺失导致写入数据库报错MongoWriteConcernException的问题总结(上)
  • 苹果Mac OS系统上安装brew
  • 应用侧渲染流程
  • 学生党开放式运动耳机怎么选?五款超高销量高性价比品牌推荐
  • 服务器中有g++,但是查询不到,Command ‘g++‘ not found
  • count(“0“),split() ,sys.stdin.readline() ,matrix.append, input().strip()
  • Flink on Kubernetes (flink-operator) 部署Flink
  • 代码随想录算法训练营第三十二天|122.买卖股票的最佳时机II、55. 跳跃游戏、45.跳跃游戏II
  • 常见数据库分类介绍及其适用场景