第13讲:深入理解指针(3)

科普:printf格式化打印

1.深入理解字符串

2.字符指针变量

3.数组指针变量

4.函数指针变量

5.函数指针数组

6.函数指针数组的应用

科普:printf格式化打印

%d打印a的地址,打印出随机值(err)

%d打印字符a(arr是a的地址,解引用后就是a),正常打印a的ascll码

%c打印a的地址,打印错误(err)

%c打印字符a,打印出a

%s打印a地址(字符串打印时,printf遇到\0才停),正常打印

%s打印字符a,打印错误(err)

所以,在%d,%c打印时,应传字符,%s打印时,应传地址

1.深入理解字符串

字符串可以理解成一个只读字符数组,数组就是数组名,所以,“abcd”,像这样的形式都可以理解成数组名,而数组名是首元素的地址,所以"abcd"是首元素a的地址。并且,字符串“abcde”是只读数组,所以在内存上是占着一块空间的(代码段)

我们用代码验证:

"abcde"是a的地址,解引用后%c打印字符‘a’

我们站在在个新的角度,重新理解一下这个代码,"abcde"是字符串,字符串是只读字符数组,数组是数组名,数组名是首元素地址,所以,“abcde”是字符‘a’的地址,所以%s从'a'开始打印,打印到字符‘e’,然后遇到‘\0’,打印停止。

单字符是不会有地址的,

字符串中字符的地址,实际上是字符串的地址,

字符变量中的字符的地址,实际上是字符变量的地址

字符数组中字符的地址,实际上是数组的地址

我在文章中常常说某字符的地址,其实是指那个地址装着该字符(直接说第几个元素的地址不好理解),这么说只是方便讲述

例题:结果是什么?

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

str1,str2是两个不同的数组,在内存上占据着不同的空间,其首元素的地址自然不同

“hello bit.” 是字符串,字符串是数组,数组是数组名,“hello bit”是一个数组名

下面的“hello bit”也是数组名,而且和上面的名字相同,所以,这两个字符串表示同一个数组首元素的地址,所以,str3和str4相同。

讲完字符指针变量,会有例题详解!

2.字符指针变量

什么是字符指针变量?

字符指针变量是一个变量,这个变量里装的是指向字符的指针。

根据前几节的知识,不难想出这个代码,pc就是字符指针变量,里面装着字符变量ch的地址。

我们还可以这么玩:

“abcde”是a的地址所以“abcde”是指向字符‘a’的指针,所以“abcde”是字符指针

第五行实际上是把字符串中字符‘a’的地址传给了字符指针变量pc,%s从‘a’开始打印,直到‘e’,遇到\0,停止打印。

有了这些知识,我们现在看几个例题:

第六行:“abcd”是字符串,字符串是只读字符数组,数组是数组名,【2】用方括号下标访问第3个元素,所以是c

第七行:1.公式转化:arr[i]=*(arr+i),arr是数组名,“abcd”也是数组名,所以可以用该公式直接转换

第八行:2.“abcd”是首元素a的地址,+2跳过两个元素,指向c,解引用后,%c打印出c

3.数组指针变量

什么是数组指针变量?

数组指针变量是变量,里面装着指向数组的指针。

这里p1和p2分别代表什么?

p1:[]的优先级高于*,p1先于[10]结合,成为数组,数组的元素是int*类型的

p2:()的优先级高于[],p2先于*结合,*说明p2是指针,p2再与[10]结合,使得p2指向数组,[10]说明指针p2指向的数组有十个元素,int表示p2指向的数组的元素是int型的。

数组指针变量里装的是指向数组的指针,如何获取数组的地址?

&arr(用&+数组名直接取出数组的地址)

初始化方法:

​​​​​​​

数组指针类型:去掉数组名,剩下的就是类型p2的类型是int(*)[10].

4.函数指针变量

函数指针变量是变量,里面装着指向函数的指针。

数组名表示数组首元素的地址

函数名表示函数的地址

看下面的代码:

函数名表示函数的地址,test是函数名,test是函数的地址,所以函数调用时可以写地址

&test也是函数的地址,可以用于函数调用,上图得证!

先看第9和第10行,p1先于*结合说明p1是指针,再与()结合,说明p1指向函数,右边的()交代指针指向的函数的参数,void表示p1指向的函数的返回值类型。p2同理,test就是test的地址,所以要得到函数的地址,加不加&都一样,p1和p2是一样的,看结果得证!

看第11行和第12行,调用函数时,可以使用函数的地址,所以两种写法都一样,都可以成功调用函数!看结果得证!!!

 函数指针类型解析:

还有另一种写法,图中的x,y是可以省略的,这两种写法是一个意思,后续的博客大多会采用省略的写法。

我们学过很多类型,有整型,实型(浮点型),无符号整型等等

今天,我们看到了数组指针类型,函数指针类型

它们有个共同点,都是类型,所以,它们都是用来修饰变量的

它们是类型,意味着它们能够参与类型强转

我们看看下面这个代码(可跳过,很难)

(*(void(*)())0))();

0是一个整型常量,我们用(void(*)())这个函数指针类型将0强转,使其变为函数指针,再解引用,找到这个函数,最后函数与()结合,进行函数调用。

void(*signal(int,void(*)(int)))(int);

void(*)(int)是函数指针类型,是一个类型,int是整型,也是一个类型,signal先与()结合,说明这是函数声明,去掉signal(int,void(*)(int)),剩下的是返回值类型。

void(*(*signal)(int ,void(*)(int)))(int);

signal先与*结合,说明signal是指针,右边的(int,void(*)(int))交代了函数参数,所以signal是函数指针变量,去掉(*signal)(int ,void(*)(int)),剩下的void(*)(int)是signal指针指向的函数的类型。

typedef关键字

例如:unsigned int写着不方便

我们可以:typedef unsigned int uint;

这样,unit也能表示无符号整型,可以替换unsigned int,注意:typedef重命名后,原来的名字是可以用的,就比如现在,unsigned int和uint都是可以用的,且效果一样!

typedef重命名时,新的名字写在原来的名字创建变量时变量的位置

举几个例子:

typedef int(*ptr_t)[5];

ptr_t就是int(*)[5]这个类型的新名字,使用简化的名字创建变量时,只需将变量写在类型名的右边即可

int(*p1)[5];等价于ptr_t p1;

typedef void(*pfun_t)(int);

void(*p1)(int);等价于void(*p1)(int);

5.函数指针数组

函数指针数组是数组,里面存放的是函数的指针。

int (*parr[3])();

int *parr[3]();err

int(*)() parr[3];err

parr是数组,要先于[]结合,然后将parr【3】想象成数组的元素,数组的元素是函数指针变量,函数指针变量与*结合,说明该变量是指针,再与()结合,说明数组元素指向函数,右边的()交代了函数指针变量指向的函数的参数,去掉(*parr[3])(),剩下的int是函数指针变量指向的函数的返回值类型。

6.函数指针数组的应用

题目,使用函数指针数组实现计算机的功能。

#include<stdio.h>
double add(double x, double y)
{
	return x + y;
}
double jian(double x, double y)
{
	return x - y;
}
double cheng(double x, double y)
{
	return x * y;
}
double chu(double x, double y)
{
	return x / y;
}
int main()
{
	double x, y;
	int input;
	scanf("%lf%lf", &x, &y);
	printf("+(1),-(2),*(3),/(4)\n");
	double(*arr[5])(double, double) = { 0,add,jian,cheng,chu };
	scanf("%d", &input);
	printf("%.2lf", arr[input](x, y));
	return 0;
}

  • 27
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

INUYACHA

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

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

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

打赏作者

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

抵扣说明:

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

余额充值