壹 字符指针变量
printf("%c\n", *p);
输出为 a
所以,
- 我们可以把字符串想象为一个字符数组,但这个数组是不能修改的(相当于常量字符串)
- 当常量字符串出现在表达式中的时候,他的值是第一个字符的地址
printf("%c\n", "abcdef"[3]); 等价于 printf("%c\n", p[3]);
"abcdef"[ ] 不可修改,所以我们可以把它写成更严谨的形式
const char* p = "abcdef";
这样就可以通过 p 访问 “abcdef” 中的内容了,但是不能更改,放入新的值
源码如下:
#include<stdio.h>
int main()
{
char str1[] = "hello";
char str2[] = "hello";
char* str3 = "hello";
char* str4 = "hello";
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;
}
贰 数组指针变量
2.1 什么叫数组指针变量
类比:
整型指针 —— 指向整型的指针(存放的就是整型的地址)
字符型指针 —— 指向字符的指针(存放的就是字符型的地址)
浮点型指针 —— 指向浮点型的指针(存放的就是浮点型的地址)
数组指针 —— 指向数组的指针(存放的就是数组的地址)【是一种指针变量】
ps:指针数组:是数组,存放指针的数组
判断:
①:int * p1 [10] ;
p1 是数组,数组10个元素,每个元素的类型是 int * ,所以 p1 是指针数组。
②:int (*p2) [10] ;
p2 是指针,指针指向的是数组,数组有10个元素,每个元素的类型是 int,
p2 是指向数组的指针,数组指针
int (*parr) [10] = &arr; //取出的是数组的地址
int (*) [10] 把 parr 去掉就是他的类型
对指针来说,去掉名字就是类型
注:[ ] 的优先级要高于 *号,所以必须加上()来保证 p 先和 * 结合。
2.2 数组指针变量初始化
获得地址:&arr
存放数组地址:得存放在指针变量中
*p == *&arr == arr(解引用和取地址抵消)
(*p)[i] <——> arr[i]
叁 二维数组传参的本质
一维数组传参,形参可以说是数组,也可以是指针,为什么?
答:①写成数组更加直观,为了方便理解
②写成指针是因为数组传参,传递的是数组首元素的地址
示例:int arr[10];
test1(arr,10);
函数可以写成 void test1(int arr[10], int sz);
test2(arr,10);
函数可以写成 void test2(int *arr, int sz);
二维数组传参,形参也可以写成数组,非常直观易理解,当然写成指针也是一样的效果。
二维数组的元素是一维数组,一维数组的元素是数组
对于二维数组,首元素其实就是第一行,首元素的地址就是第一个行的地址
一维数组的地址应该是一个指向数组的指针才能够接收。
void Print(int *arr[5], int r, int c)
这里的 *arr[5]就是二维数组第一行的地址
arr[i][j] 等价于 *(*(arr + i) + j);
肆 函数指针变量
4.1 函数指针变量的创建
数组名 —— 数组首元素的地址
&数组名 —— 整个数组的地址
函数名:函数的地址
&函数名:函数的地址
示例:
存在一个Add函数:int Add(int x, int y) { return x + y; }
函数指针变量创建:int (*pf) (int, int) = &Add; //pf就是函数指针变量
函数调用:int ret1 = Add(2,3); 或者 int ret2 = (*pf) (2,3);
保存一个函数的地址:
#include<stdio.h>
char * test(int a, char c)
{
......
return NULL;
}
int main()
{
char* (*p)(int, char) = test; //当然 char * (*p)(int a, char c) = test; 写法也是正确的
return 0;
}
展开分析 char * (*p)(int a, char c) = test;
4.2 函数指针变量的使用
通过函数指针调用指针指向的函数。
如果不注意写成了 *p(2,4) , p就先对函数调用,再对返回值解引用,编译器也会报错。
伍 函数指针数组
指针数组举例:
char* arr[5]; —— 字符指针数组
int* arr[6]; —— 整型指针数组
可以把指针放在数组中
那么函数指针也是指针,当然也可以放在数组中
陆 转移表
函数指针数组的应用/用途举例:
<计算器的实现>
int (*pfArr[ ])(int, int) = { NULL,Add,Sub,Mul,Div };
#include<stdio.h>
//使用函数指针数组改进计算器
//该函数指针被称为——转移表
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 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()
{
Menu();
int input = 0;
int x = 0, y = 0;
do
{
printf("请选择:\n");
scanf("%d", &input);
if (input == 0)
{
printf("已成功退出计算器\n");
}
else if (input > 0 && input < 5)
{
int (*pfArr[])(int, int) = { NULL, Add,Sub,Mul,Div };
printf("请输入两个整型操作数:\n");
scanf("%d %d", &x, &y);
printf("%d\n", pfArr[input](x, y));
}
else
{
printf("输入有误,请重新输入!");
}
} while (input);
return 0;
}