ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

深入理解指针(2)

深入理解指针(2)

目录:

1. 字符指针变量

2. 数组指针变量

3. ⼆维数组传参的本质

4. 函数指针变量

5. 函数指针数组

6. 转移表

1.字符指针变量

在指针的类型中我们知道有⼀种指针类型为字符指针 char* 

 这里我们有两种指针读取字符串的方式,但是第二种p2指向的是常量字符串不能修改,所以我们可以在前面添加一个const

下面我们来看一道题

#define _CRT_SECURE_NO_WARNINGS
#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"); elseprintf("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数组存储hello bit,先创建一块空间 str2数组存储hello bit又创建一块空间 ,但是这两块空间是截然不同的两块空间,而str3和str4都是指针变量,指向的是常量字符串,而常量字符串不可以改变,所以没有必要创建两份,所以创建一份还可以节省空间。

另外str1,str2,str3,str4都是创建在栈区的,而指向的hellobit.是在静态区的

2.数组指针变量

整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。

•浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。

那数组指针变量应该是:存放的应该是数组的地址,能够指向数组的指针变量。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int a = 10;int* p1 = &a;//整形指针int b = 'w';char* p2 = &b;//字符指针int arr[10] = { 0 };int(*p)[10] = &arr;//取出的是整个数组的地址arr;//数组首元素的地址int* p1[10];//p1是指针数组-存放指针的数组int(*p2)[10];//p2是指针变量-指向的是数组,数组指针return 0;
}

2.2 数组指针变量怎么初始化

如果要存放个数组的地址,就得存放在数组指针变量中

如果我们要用数组指针来访问数组就显得很麻烦,不建议使用

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int(*p)[10] = &arr;int i = 0;for (i = 0;i < 10;i++){printf("%d ", (*p)[i]);}return 0;
}

3. ⼆维数组传参的本质

我们很容易能利用for循环打印二维数组

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
print(int arr[3][5],int r,int c)
{int i = 0;for (i = 0;i < r;i++){int j = 0;for (j = 0;j < c;j++){printf("%d ", arr[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} };print(arr, 3, 5);return 0;
}

但我们有一个问题,二位数组的数组名也是首元素的地址,但是究竟是谁的地址呢?

首元素就是第一行,第一行的地址就是首元素的地址,第一行的地址就是数组指针的地址

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void print(int (*arr)[5], int r, int c)
{int i = 0;for (i = 0;i < r;i++){int j = 0;for (j = 0;j < c;j++){printf("%d ", *(*(arr + 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} };print(arr, 3, 5);return 0;
}

4. 函数指针变量

4.1 函数指针变量的创建

数组指针是指向数组的,那么函数指针是指向函数的,那么函数有没有地址呢?

我们发现函数名的地址和&函数名是一样的。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}int main()
{int (*pf)(int,int) = &Add;//pf是专门用来存放函数地址的,pf是函数指针变量printf("%p\n", &Add);printf("%p", Add);return 0;
}

4.2 函数指针变量的使⽤ 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}int main()
{int (*pf)(int,int) = &Add;//pf是专门用来存放函数地址的,pf是函数指针变量int c = Add(3, 5);printf("%d\n", c);int d = (*pf)(4, 5);printf("%d\n", d);int e = pf(5, 5);printf("%d\n", e);return 0;
}

以上这几种方法都是可以成功调用函数的

我们下面来看两个有趣的代码:

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

这里void(*)--函数指针类型

(void(*))--强制类型转换

(void(*)0 --将0强制转化为函数指针类型

这就意味着0处存放着无参,函数返回类型为void的类型

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

4.3.1 typedef关键字 

typedef 是⽤来类型重命名的,可以将复杂的类型,简单化。

 

5. 函数指针数组 

把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int Add(int x,int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int Mul(int x, int y)
{return x * y;
}
int Div(int x, int y)
{return x / y;
}
int main()
{int(*pf1)(int,int) = Add;int(*pf2[4])(int, int) = { Add,Sub,Mul,Div };//这里pf2就是函数指针数组int i = 0;for (i = 0;i < 4;i++){int ret = (*pf2[i])(8, 4);printf("%d ", ret);}return 0;
}

完!!!

返回列表