目录
一、字符指针变量
二、数组指针变量
三、二维数组传参的本质
四、函数指针变量
五、 typedef关键字
六、函数指针数组
七、转移表(函数指针数组的实践)
一、字符指针变量
1. 字符指针变量是指里面存放的是字符变量地址的指针变量,对这个字符指针变量解引用就可以找到其所指向的字符变量。
2. 拓展用法:字符指针变量可以存放常量字符串的首地址。
解释说明:常量字符串与其他常量相比,编译器有给它提供内存空间存储常量字符串中的每个字符,存放这个常量字符串的地址是固定的,如图1的代码的验证,整个常量字符串表示常量字符串首元素的地址,我们可以将它的地址存放在字符指针中,并通过解引用和指针的偏移找到这个常量字符串中的每个字符,但我们是没有权限通过对指针解引用去修改常量字符串中元素的数据的。
3. 注意理解:当我们想要访问一个数组每个元素时,可以利用数组首元素地址arr或存有数组首元素地址的指针p+ [i],表示利用数组首元素地址偏移并解引用找到地址所指向的变量,arr[i] == p[i],或写成 i[arr]==i[arr];也可以写成这种形式 *(arr+i)=*(p+i) 。
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");//打印not same
//
if(str3 == str4)
printf("str3 and str4 are same\n");//打印same
else
printf("str3 and str4 are not same\n");
return 0;
}
int main()
{
//字符指针变量的普通应用
char arr = 'B';
char* p = &arr;
*p = 'W';
printf("%c\n", arr);
//字符指针变量存放常量字符串
char* ptr = "ABCDE";
printf("%c\n", *ptr);//A
printf("%c\n", *(ptr + 1));//B
printf("%c\n", ptr[2]);//C //数组首元素地址加[]和下标表示地址偏移并解引用
printf("%c\n", "ABCDE"[2]);//C
return 0;
}
二、数组指针变量
1. 数组指针变量是指里面存放的是数组地址的指针变量(不是数组首元素的地址),对数组指针变量解引用就可以找到其所指向的整个数组,注意这里相当于得到了所指向数组的变量名。
2. 数组指针变量初始化就是将一个数组的地址存入数组指针变量即可,或则置NULL。
3.数组指针变量类型的理解:以int (*p)[10]为例,(*)表示p是一个指针变量,[10]表示这个指针变量所指向的对象是一个有10个元素的一维数组,int表示所指向的一位数组中的每个元素的类型是int类型。(注意区分指针数组和数组指针变量)
4. 数组指针一般不会在一维数组里使用,要使用也会在二维及以上数组中使用,通常用于二维数组传参。
//数组指针变量的创建
int mian()
{
int n1 = 10;
int* p1 = &n1;//整型指针变量
char n2 = 'a';
char* p2 = &n2;//字符指针变量
float n3 = 12.8f;
float* p3 = &n3;//单精度浮点型指针变量
int arr[10] = { 0 };
int(*p4)[10] = &arr;//数组指针变量
//指针变量p4的类型是int (*)[10]
return 0;
}
//使用数组指针变量访问数组中的每一个元素(一般不会采取这样的方式访问)
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int(*p)[10] = &arr;//p是数组指针变量
int i = 0;
//如果想通过数组指针访问数组中的所有元素:
for (i = 0; i < sz; i++)
{
printf("%d ", (*p)[i]);//*p可以找到p所指向的整个数组arr,
//整个数组的数组名又是数组首元素的地址
//换句话说对整个数组的地址同时&和*等同于无效操作
//对数组首元素地址进行地址偏移和解引用即可找到数组中的所有元素
}
return 0;
}
三、二维数组传参的本质
1. ⼆维数组传参传递的是二维数组第⼀⾏⼀维数组的地址。
2. 二维数组的行和列的大小和一维数组一样只能在自己被创建的函数中求。
3. 二维数组传参,形参的部分也有两种写法:① 直接写成二维数组的形式,② 也可以写成数组指针的形式,但形参的本质都是二维数组第⼀⾏⼀维数组的地址,只是不同写法而已。
4. 注意理解:二维数组传参也属于传址调用。
//使用自定义函数打印二维数组中每一个元素
void Print(int(*p)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", *(*(p + i) + j));//==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 } };
Print(arr, 3, 5);//数组名是数组首元素的地址,这里的二维数组,首元素是一个一维数组
//所以二维数组传参其实是传的数组指针变量
return 0;
}
四、函数指针变量
1. 函数指针变量是指里面存放的是函数地址的指针变量,对函数指针变量解引用就可以找到其所指向的函数,并且我们可以通过传递实参达到调用这个函数的效果。
2. Add==&Add(和数组不同,函数名和&地址函数名都是表示这个函数的地址)
3. 函数指针变量类型的理解,以int (*p) (int x, int y)为例,(*)表示p是一个指针变量,(intx,inty)表示指针变量p所指向的函数的参数有几个,分别是什么类型的,int表示指针变量所指向的函数的返回类型是int类型。
4. 函数指针变量的使用:可以写成(*指针)+(),表示通过解引用指针变量找到函数,并对函数进行传参;也可以直接指针+(),因为函数调用时()左边的就时函数的地址。
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 10, b = 20;
int (*p)(int x, int y) = Add;//x和y可以不写int (*p)(int, int)
int ret1 = p(a, b);
printf("%d\n", ret1);//30
int ret2 = (*p)(a, b);
printf("%d\n", ret2);//30
return 0;
}
五、 typedef关键字
1. typedef 是⽤来类型重命名的,可以将复杂的类型简单化。
typedef unsigned int uint;
//将unsigned int 重命名为uint
typedef int* ptr_t;
//将指针类型int* 重命名维ptr_t
//对数组指针和函数指针重命名
typedef int(*parr_t)[5]; //新的类型名必须在*的右边
typedef void(*pfun_t)(int);//新的类型名必须在*的右边
六、函数指针数组
1. 函数指针数组是存放函数指针的数组,函数指针数组里的元素全都是函数指针。
2. 函数指针数组的类型由数组中每个元素的类型决定,但写法比较独特,具体见下方代码。
即把函数指针类型中写指针名称的地方写成函数指针数组名和数组大小,去掉数组名称剩下的就是函数指针数组类型。
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 main()
{
int (*arr[3])(int, int) = { Add, Sub, Mul };//函数指针数组
//arr是数组名,[3]表示数组大小
//int ret = (arr+1)(2, 3);//err
//int ret = (*(arr + 1))(2, 3);
int ret = arr[1](2, 3);//下标直接访问
printf("%d\n", ret);
return 0;
}
七、转移表(函数指针数组的实践)
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 }; //转移表
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if ((input <= 4 && input >= 1))
{
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = p[input](x, y);
printf("ret = %d\n", ret);
}
else if (input == 0)
{
printf("退出计算器\n");
}
else
{
printf("输⼊有误\n");
}
} while (input);
return 0;
}