如果没有看过第一部分的话,推荐先看第二部分,然后再来看第三部分~~
在指针的类型中我们知道有一种指针类型为字符指针char*
;
我们这里定义了ch变量,里面存了个字符 w
然后我将这个变量的地址取出来放到pc里,它的类型是char*
,pc就是字符指针变量
int main()
{
char ch = 'w';
char* pc = &ch;
return 0;
}
char* p = "abcdefghi";
我们可以这样验证:
char* p = "abcdefghi";
printf("%c", *p);
const char* p = "abcdefghi";
那我想要打印一下这个字符串,怎么办?
我们就以%s
的方式来打印
const char* p = "abcdefghi";
printf("%s", p);
《剑指offer》中收录了一道和字符串相关的笔试题,我们一起来学习一下:
#include
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;
}
之前我们学习了指针数组,指针数组是一种数组,数组中存放的是地址(指针)。
数组指针变量是指针变量?还是数组?
答案是:指针变量
我们已经熟悉:
整形指针变量: int * pint;
存放的是整形变量的地址,能够指向整形数据的指针。
浮点型指针变量: float * pf;
存放浮点型变量的地址,能够指向浮点型数据的指针。
数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。
int *p1[10];
int (*p2)[10];
这两个是哪个呢?
数组指针变量
int (*p)[10];
解释: p先和*结合,说明p是一个指针变量变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫 数组指针。
这里要注意:[]
的优先级要高于*
号的,所以必须加上()
来保证p先和*结合。
&数组名
。int arr[10] = { 0 };
&arr;//得到的就是数组的地址
int(*p)[10] = &arr;
int arr[10] = { 0 };
arr; //数组首元素的地址 -- int*
&arr;//数组的地址 -- int(*)[10]
#include
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
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;
}
总结: 二维数组传参,形参的部分可以写成数组,也可以写成指针形式。
什么是函数指针变量呢?
那么函数是否有地址呢?
#include
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;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的
那我们是不是要进行使用,怎么使用呢?
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = &Add;
int r = (*pf)(3, 5);//调用函数指针
printf("r = %d\n", r);
return 0;
}
*
也行,但是写上就更容易理解,可读性更高一些~~int r = pf(3, 5);
函数指针类型解析:
代码1
(*(void (*)())0)();
代码2
void (*signal(int , void(*)(int)))(int);
signal
是一个函数的函数名,上面的代码是一次函数声明,声明的signal
函数有两个参数,第一个参数是int类型的,第二个参数是函数指针类型的,该函数指针指向的函数参数是int类型,返回类型是void
signal
函数的返回类型也是一个函数指针,该函数指针指向的函数,参数是int,返回类型也是void两段代码均出自:《C陷阱和缺陷》这本书
typedef 是用来类型重命名的,可以将复杂的类型,简单化。
比如,你觉得unsigned int
写起来不方便,如果能写成uint
就方便多了,那么我们可以使用:
typedef unsigned int uint;
//将unsigned int 重命名为uint
int*
重命名为ptr_t
,这样写:typedef int* ptr_t;
int(*)[5]
,需要重命名为parr_t
,那可以这样写:typedef int(*parr_t)[5]; //新的类型名必须在*的右边
void(*)(int)
类型重命名为pf_t
,就可以这样写:typedef void(*pfun_t)(int);//新的类型名必须在*的右边
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
比如:
int *arr[10];
//数组的每个元素是int*
int (*parr1[3])();
parr1
先和[]
结合,说明 parr1
是数组,数组的内容是什么呢?int (*)()
类型的函数指针。那么有用吗,有的!!,接下来就来到我们的转移表模块~~
函数指针数组的用途:转移表
#include
menu()
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
}
int add(int a, int b)
{
return a + b;
}
int 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 x, y;
int input = 1;
int ret = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
#include
void menu()
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
}
int add(int a, int b)
{
return a + b;
}
int 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 x, y;
int input = 1;
int ret = 0;
int(*pfArr[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
do
{
menu();
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = (*pfArr[input])(x, y);
printf("ret = %d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输入有误,请重新选择\n");
}
} while (input);
return 0;
}
好了,指针的第三部分就到这里就结束了~~
如果有什么问题可以私信我或者评论里交流~~
感谢大家的收看,希望我的文章可以帮助到正在阅读的你