目录
5.2.1 分析 ( * ( void ( * ) ( ) ) 0 ) ( );代码
5.2.2 分析 void ( * signal ( int , void ( * ) ( int ) ) ) ( int ); 代码
一、字符指针
在定义字符指针的时候,有两种写法:
//第一种 char ch[] = "hello";//定义一个常量字符串 char* ptr = &ch; //取出ch的地址,存到字符指针ptr中 //第二种 char* str = "hello";//直接让字符指针指向常量字符串
可能在接触字符指针的时候,有过这样的想法——既然将字符串存入指针变量里,那么对它解引用操作应该就是原样输出,但事实并非如此,其本质是将字符串的首字符的地址存到了指针变量里,指针就通过这个地址能够找到这块连续的空间并对其访问;
通过下面的代码解答疑惑:
#include <stdio.h>
int main()
{
char ch[] = "hello";
char* ptr = &ch;
char* str = "hello";
printf("%c\n", *ptr);
printf("%c\n", *(ptr+1));
printf("%c\n", *str);
printf("%c\n", *(str + 1));
return 0;
}
从运行结果来看,对其解引用打印出来的结果是h,说明ptr指针和str指针存的是h的地址,*(ptr+1)打印出来的结果是e,说明字符串也是通过下标去访问的(连续的空间);
二、指针数组
概念:有一个数组,数组里存放的元素是指针(地址) ;
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* arr[3] = { &a,&b,&c };//这就是指针数组的定义方法
printf("%d\n", *arr[0]);//或**arr
//**arr---arr是数组名也就是首元素的地址,解引用后得到 &a ,再解引用得到10
return 0;
}
三、数组指针
3.1数组指针的定义
数组指针是指针还是数组?(答案是:指针)
对比下面两个代码:
int* p1[5];//指针数组 int (*p2)[5];//数组指针(行指针)
( )的优先级别比 [ ] 要高; [ ] 的优先级别比 * 要高;
1. p1先与 [ ] 结合表名p是数组,这个数组有5个元素,每个元素的类型是int*;
2. p2先与 * 结合,表明p2是指针,指向了一个数组,每个素组有5个元素,每个元素的类型是int;
3.2&数组名和数组名
数组名表示数组首元素的地址,那么&数组名表示什么?
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr+1);
printf("&arr+1= %p\n", &arr+1);
return 0;
}
3.3数组指针的使用
常常用于二维数组
#include <stdio.h>
int main()
{
int arr[2][5] = { 0,1,2,3,4,5,6,7,8,9 };
int(*parr)[5] = &arr;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", parr[i][j]);
//printf("%d ", (*(parr+i))[j]);
//printf("%d ", *(parr[i] + j));
//printf("%d ", *(*(parr + i)+j));
}
printf("\n");
}
return 0;
}
parr[ i ] [ j ] = ( * ( parr + i ) ) [ j ] ) = * ( parr [ i ] + j ) = * ( * ( parr + i ) + j );
四、指针的传参
传参:本质含义就是传递者与接受者类型是一样的或接受者属于接受任意类型(如:void)
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{//这是常见的二维数组传参,传参时注意点行可以省略但是列不可以
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print_arr2(int(*arr)[5], int row, int col)
{//这里将二维数组的第一行的地址传个数组指针
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr1(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
print_arr2(arr, 3, 5);
return 0;
}}
五、函数指针
本质含义:就是把函数的地址存到了一个指针变量里;
5.1代码介绍
#include <stdio.h>
int Add(int a, int b)
{
return a + b;
}
int main()
{
int a = 10;
int b = 20;
int (*pa)(int, int) = Add;
int ret = pa(a, b);
printf("%d\n", ret);
return 0;
}
int (*pa)(int, int) = Add;
Add是函数名,就是函数的地址,Add的类型是int (int a, int b);把它存到指针变量里,这个指针变量的类型也应该是 int ( * ) (int a, int b),也可以写成 int( * ) (int , int )
切不可写成 int *pa(int, int) = Add;这个代码中pa就表示为函数了,类型就是int*,所以括号是很重要的
int ret = pa(a, b);pa存的是Add函数的地址,这里用pa来调用Add函数,并给它传参;
5.2感受函数指针带来的快乐
5.2.1 分析 ( * ( void ( * ) ( ) ) 0 ) ( );代码
5.2.2 分析 void ( * signal ( int , void ( * ) ( int ) ) ) ( int ); 代码
六、函数指针数组
含义:本质上是一个数组,数组中的元素是函数指针;简单的说,有一个数组存放了许多函数的地址
int (*p[5])(int,int);
p[ 5 ]表明是数组,它的类型是 int ( * )( int , int );
在没有接触函数指针数组时,如果要编写一个代码实现加减乘除的计算器,我们可以利用到switch语句进行函数功能的选择,代码如下;
#include <stdio.h>
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
{
printf("*************************\n");
printf("****1:add 2:sub****\n");
printf("****3:mul 4:div****\n");
printf("*************************\n");
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 <stdio.h>
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(*p[5])(int x, int y) = { 0, add, sub, mul, div };
while (input)
{
printf("*************************\n");
printf("****1.add 2.sub****\n");
printf("****3.mul 4.div****\n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输入操作数:");
scanf("%d %d", &x, &y);
ret = (*p[input])(x, y);//输入的input分别对应着函数指针里对应函数的下标
}
else
printf("输入有误\n");
printf("ret = %d\n", ret);
}
return 0;
}
七、 指向函数指针数组的指针
如何定义:
//函数指针p
int (*p)(int x,int y);
//函数指针的数组p1
int (*p1[5])(int x,int y)=&p;
//指向函数指针数组p1的指针p2
int (*(*p2)[5])(int x,int y) = &p1;
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
//函数指针p
int (*p)(int x, int y) = add;
//函数指针的数组p1
int (*p1[4])(int x, int y) = { p };//这里也可以把减法、乘法、除法函数的地址保存进去
//指向函数指针数组p1的指针p2
int (*(*p2)[4])(int x, int y) = &p1;
//利用指向函数指针数组的指针实现两数相加
int ret = (*(*p2[0]))(10, 5);
printf("ret=%d\n", ret);
return 0;
}
八、总结
以上指针进阶的全部内容,本文对于指针的理解都以笔者自述为主,并未采用专业的解释,希望看完这两篇指针能够给大家带来帮助。