指针相关知识(3)

1. 字符指针变量
2. 数组指针变量
3. ⼆维数组传参的本质
4. 函数指针变量
5. 函数指针数组
1.字符指针变量:
1.在指针学习过程中我们学过了字符指针,就是存储字符的指针变量,char* char。
int main()
{
 char ch = 'w';
 char *pc = &ch;
 *pc = 'w';
 return 0;
}
还有一种使用方法
int main()
{
 const char* pstr = "hello bit.";//这⾥是把⼀个字符串放到pstr指针变量⾥了吗?
 printf("%s\n", pstr);
 return 0;
}

上面的代码里const char* pstr ="hello bit"并不是把字符串hello bit存入指针pstr里,而是把hello bit的首字符地址存入指针里,就是h的地址,详细如下:

《剑指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++会把常量存储到常量存储区中,所以指针str3和str4指向的是同一个常量字符串,所以str3==str4。str1和str2是两个数组,内存会分配地址给他们,所以str1和str2里的hello bit地址并不相同。

2.数组指针变量:

之前我们说过了指针数组,指针数组就是把n个指针存入数组里,那么数组指针变量是数组还是指针呢?答案是肯定的,就像字符指针变量是存放字符变量的地址,能够指向字符数据的指针,整形指针变量是存放整形变量的地址,能够指向整形数据的指针,数组指针变量当然就是存放数组的地址,能够指向数组的指针。

int * ptr=arr[10];                        int (*p)[10];                     思考一下ptr和p分别是什么?

int (*p)[10];

上面代码里的p就是数组指针变量,p先和*结合,意思p是指针变量,然后p指向的是数组大小是10的整形数组。这里的()是必要的,因为[ ]优先级比*高,如果不打括号,p会先和[ ]结合,这个p就变成了数组名p[10]了。

那么这里我们如何把数组的地址存入指针里呢?用到的就是之前比较过的&arr。 int (*p)[10]=&arr;这里调试可以看出来&arr和指针变量p的类型都是int [10]*。

3.二维数组传参的本质:

过去我们二维数组传参都是void test(int a[3][5], int r, int c),这里的实参是数组,形参也是数组,那么还有别的表达方式吗。要知道还有什么表达方式我们需要深度理解一下二维数组,我们可以把二维数组看成一维数组里存放了几个一维数组int arr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}},并且二维数组首元素地址就是第一行一维数组的地址,根据上面的解释,一维数组元素类型是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));
 }
 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.函数指针变量:

听名识曲,顾名思义,函数指针变量是存放函数地址的指针变量,可以调用函数。那么函数有地址吗?可以看出来函数是有地址的,并且函数名就是函数的地址,可以直接函数名也可以&函数名。

函数指针变量创建如下:

void test()
{
 printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)()= test;
int Add(int x, int y)
{
 return x+y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;

使用函数指针调用函数

typedef关键字:typedef是可以给类型重命名的

typedef unsigned int uint;
//将unsigned int 重命名为uint
typedef int* ptr_t;
//定义指针类型
typedef int(*parr_t)[5];
//定义数组指针类型
typedef void(*pfun_t)(int);
//定义函数指针类型

这里需要特殊观察的是数组指针和函数指针,新的类型名需要在*的右边。

5.函数指针数组:

经过我们一层层的套娃,也是来到了函数指针类型,函数指针类型顾名又思义是数组,数组里存放的是函数的指针(地址)。那么函数指针的数组该如何定义呢?给三种可能结果:

int (*parr1[ 3 ])();
int *parr2[ 3 ]();
int (*)() parr3[ 3 ];
答案是parr1,parr1先和[ ]结合意为数组,数组的类型是int(*)()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值