【C语言进阶】指针和数组(指针与数组名;指针数组,数组指针;数组传参,指针传参;字符指针,函数指针,函数指针数组,回调函数)

目录

 一、数组

1.数组名

2.数组的内存布局

二、指针

三、指针与数组

1.使用方法上的相似点:

2.指针与数组名的区别:

3.数组传参

4.C语言为什么要将指针和数组的访问方式设计成通用的?

5.多维数组与指针

6.两道经典例题

四、字符指针

五、指针数组

六、数组指针

七、数组传参、指针传参

八、函数指针

九、函数指针数组——无限套娃

  十、回调函数


 一、数组

1.数组名

1.大多数情况数组名都代表的是数组首元素的地址,除了:

>>>Sizeof(数组名) —— 数组名表示整个数组 ——计算的是整个数组的大小,单位是字节

>>>&数组名 —— 数组名表示整个数组 ——取出的是整个数组的地址

举例验证:

2.数组只能够进行整体初始化,不能整体赋值(数组名是地址常量不能作为左值)。

2.数组的内存布局

1.普通单一局部变量的地址从高往低发展(栈区空间的特点)。 

2.数组整体开辟空间,不同数组的地址从高往低发展。

3.数组内部元素的地址连续且随下标递增


二、指针

1.32位电脑有32根地址线,每根地址线有通(1)断(0)两种状况。因此,32位电脑最多可以访问2^32个地址,每个地址需要32bit == 4byte 存放。又因为一个地址对应一个字节内存,所以32位电脑最大可以访问 2^32byte == 2^10*2^10*2^10*2^2 == 4GB 大小的内存空间。

2.指针类型的意义:

>>>决定指针解引用的权限有多大(能操作几个字节)

>>>决定了指针走一步的步长有多大

3.指针-指针得到的是两个指针之间元素的个数

4.变量的地址是所占内存空间地址最低的字节的地址

5.指针的多种表示形式

Int arr[10]={0};

Int* p=arr;

//arr[2]-->*(arr+2)-->*(2+arr)-->2[arr]

//p[2]-->*(p+2)-->*(2+p)-->2[p]


三、指针与数组

首先声明一点,指针与数组是两套不同的概念,只是因为在使用方法上有相似之处所以经常被初学者搞混。

1.使用方法上的相似点:

指针与数组,在访问多个连续元素的时候,既可以采用指针解引用的方式,也可以采用 [中括号]的 方式。

2.指针与数组名的区别:

>>>数据类型不同:指针是保存地址的变量;数组是相同类型数据的集合。

>>>访问数据的方式:

        利用指针访问数据属于间接寻址,本质上是先取p的内容然后加上i*sizeof(类型)字节作为数据真正的地址;

        数组名访问数组元素是直接寻址,本质上是arr所代表数组首元素的地址(地址常量)加上i*sizeof(类型)字节作为数据真正的地址。

>>>常用场合:指针通常用于动态数据结构;数组通常用于存储固定数目且数据类型相同的元素。

3.数组传参

1.数组传参,需要降维成指针。如果不降维,就要发生数组拷贝,函数调用效率降低。

2.所有的数组,传参都会降维成指针,降维成为指向其内部元素类型的指针

3.函数形参列表中的数组会被解释成指向其内部元素类型的指针,因此最高维[中括号]中的数字会被忽略,其他维度是指针的类型,不能省略。

4.C语言为什么要将指针和数组的访问方式设计成通用的?

C语言是面向过程的语言,函数是其核心概念。而在函数调用的过程中数组传参为提高效率,会降维成指针。

假设指针和数组访问元素的方式不通用,程序员需要不断在不同的代码片段处进行习惯的切换,增加代码出错的概率。

为了让程序员统一使用数组,减少出错概率,数组和指针的访问方式才设计成通用的。

5.多维数组与指针

1.在理解上,我们甚至可以将所有的数组都当成“一维数组”。三维数组的元素是二维数组,二维数组的元素是一维数组......

2.多维数组的内存布局也  是“线性连续且递增的”

6.两道经典例题

1.二维数组的元素是一维数组

   a[i] <---> *(a+i)

   取地址&和解引用*互为逆运算可以相互抵消

2.指针加 i 跳过  i*sizeof(类型) 个字节

   指针相减,代表两个指针之间元素的个数

答案:FFFFFFFC,-4


四、字符指针

1.两个不同的字符数组在内存中占两块不同的存储空间,数组名指向的首元素的地址就不同

2.完全相同的常量字符串只开辟一块存储空间,因此不同的字符指针指向的地址相同。

3.字符数组中的元素是可以改变的,而字符串常量是不能改变的


五、指针数组

1.指针数组的定义

        指针数组是数组——元素是指针的数组

        Int *arrp[10];——arrp就是一个指针数组,其中的每一个元素都是指针。

2.让指针数组中每一个元素都指向一个字符串常量,统一处理这些字符串。

3..让指针数组中每一个元素都指向一个数组首元素的地址,就可以模拟二维数组,访问这些数组中的元素。将相同类型的一维数组串联起来。


六、数组指针

1.数组指针的定义

        数组指针是指针——执向数组的指针

        Int (*parr)[10]=&arr;——parr就是一个数组指针,其中存放的是数组的地址

4.数组指针的使用

所有的数组,传参都会降维成指针,降维成为指向其内部元素类型的指针

在理解上,我们甚至可以将所有的数组都当成“一维数组”。三维数组的元素是二维数组,二维数组的元素是一维数组......多维数组传参,降维成数组指针。


七、数组传参、指针传参

1.一维数组传参

实参

形参

Int arr1[10];

Int arr[10](形式)

Int arr1[10];

Int arr[](形式)

Int arr1[10];

Int* arr(本质)

Int* arr2[20];

Int* arr[20](形式)

Int* arr2[20];

Int* arr[](形式)

Int* arr2[20];

Int** arr(本质)

2.二维数组传参

实参

形参

Int arr[3][5];

Int arr[3][5](形式)

Int arr[3][5];

Int arr[][5](形式)

Int arr[3][5];

Int (*arr) [5](本质)

3.当函数的参数为一级指针的时候,可以接受的参数:

相应变量的地址(&a)

相应一维数组的数组名(arr)

一级指针(p)

4.当函数的参数为二级指针的时候,可以接受的参数:

一级指针的地址(&p)

二级指针(pp)

指针数组的数组名(arrp)


八、函数指针

1.存放函数地址的指针

2.数组名VS函数名

>>>&数组名 != 数组名

>>>&函数名 == 函数名

3.定义函数指针:

返回类型 (*pf)(参数类型……)

Int (*pf)(int ,int)=&add(或add);

4.使用函数指针调用函数

>>>Int ret = add(3,5);//使用函数名调用函数

>>>Int ret = (*pf)(3,5);//'*'无实际意义

>>>Int ret = pf(3,5);//常用

5.有趣的代码:

 对类型重定义简化函数声明


九、函数指针数组——无限套娃

1.存放函数指针的数组;

  int(* pfarr[5])(int,int);(在函数指针的基础上加"[  ]")

2.指向函数指针数组的指针


  十、回调函数

举例:库函数qsort

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芥末虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值