1.字符指针
2. 数组指针
3.指针数组
4.数组传参和指针传参
5. 函数指针
6. 函数指针数组
7. 指向函数指针数组的指针
8.相关的练习
指针的主题,我们在初级阶段的《指针》已经接触过了,我们知道了指针的概念:
1.指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2.指针的大小是固定的4/8个字节(32位平台/64位平台)。
3.指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。
4.指针的运算。
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 2,3,4,5,6 };
int arr3[] = { 3,4,5,6,7 };
int* parr[3] = { arr1, arr2, arr3 };
//0 1 2
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%d ",*(parr[i]+j));
}
printf("\n");
}
return 0:
}
3.数组指针
3.1数组指针的定义
数组指针是指针?还是数组?
答案是:指针。
我们已经熟悉:
整形指针:int* pint;能够指向整形数据的指针。
浮点型指针:float*pf;能够指向浮点型数据的指针。
那数组指针应该是:能够指向数组的指针。
下面代码哪个是数组指针?
int *p1[10];
int (*p2)[10];
//p1,p2分别是什么?
p2的类型是数组指针 ->int (*)[10]
写成int* p=&arr会报警告,一个数组的地址不能用整型指针接收
int main()
{
char* arr[5] = { 0 };
char* (*pc)[5] = &arr;
return 0;
}
pc是数组指针,数组类型是char*
二级指针是存放一级指针的地址
要写清楚有几个元素
指针数组常用用法
void print(int(*p)[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 ", *(((*p) + i) + 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 };
print(arr, 3, 5);//二维数组的首元素地址是他的第一行的地址
return 0;
}
*(p+i)相当于p[ i ]; 二维数组的数组名是它第一行的地址;所以arr相当于一个一维数组的地址
parr3存放的是类型为int (*)[ 5 ]的数组指针的数组,存放的数组指针指向的数组有5个int 类型的元素
parr3有10个数组指针的元素
4.数组参数,指针参数
4.1一维数组传参
#include <stdio.h>
void test(int arr[])
{}
void test(int arr[10])
{}
void test(int *arr)
{}
void test2(int *arr[20])
{}
void test2(int ** arr)
{}
int main()
{
int arr[10] = {0};
int *arr2[20] = {0};
test(arr);
test2(arr2);
}
arr2存放的是int* 的地址,可以用一个二级指针来接收
二维数组的数组名,表示首元素的地址,其实是第一行的地址
第一行是一个一维数组的!
5.函数指针
函数定义了就有地址
int add(int x, int y)
{
return x + y;
}
int main()
{
int arr[5] = { 0 };
int(*p)[5] = &arr;
int (*pc)(int, int) = &add;
//int ret = (*pc)(2, 3);*可以省略不写,只是摆设
int ret = pc(2, 3);
int ret = add(2, 3);//pc存的是add的地址,两种写法是一样的
printf("%d ", ret);
return 0;
}
分析(*(void(*)())0)()是个什么鬼?(出自《C语言陷阱与缺陷》)
void (*)()是函数指针类型(我自己只能分析到这里,害~)
void menu()
{
printf("****1.jia 2.jian******\n");
printf("****3.cheng 4.chu*******\n");
printf("****0.exit *******\n");
}
int jia(int x, int y)
{
return x + y;
}
int jian(int x, int y)
{
return x - y;
}
int cheng(int x, int y)
{
return x * y;
}
int chu(int x, int y)
{
return x / y;
}
void yiti(int (*pf)(int x, int y))
{
int ret = 0;
int x = 0;
int y = 0;
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret=pf(x, y);
printf("%d\n", ret);
}
//实现一个计算器,可以加减乘除
int main()
{
int input = 0;
do
{
menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
yiti(jia);
break;
case 2:
yiti(jian);
break;
case 3:
yiti(cheng);
break;
case 4:
yiti(chu);
break;
case 0:
break;
default:
printf("选择错误\n");
}
} while (input);
return 0;
}
这样就避免了很多冗余的代码
int (*arr[4])(int, int) = { jia,jian,cheng,chu };函数指针数组,用来存放函数指针
arr[4]数组的元素类型是int (*)(int,int)
函数指针数组的用法
int main()
{
int x = 0;
int y = 0;
int ret = 0;
int (*arr[5])(int, int) = { 0,jia,jian,cheng,chu };
int input = 0;
do
{
menu();
scanf("%d", &input);
if (input == 0)
{
printf("退出程序\n");
}
else if (input >= 1 && input <= 4)
{
printf("请输入两个操作数:\n");
scanf("%d %d", &x, &y);
ret = arr[input](x, y);
printf("%d", ret);
}
else
printf("选择错误\n");
} while (input);
return 0;
}
这样更加简洁
还有指向函数指针数组的指针
int main()
{
int (*parr[5])(int,int) = {0,jia,jian,cheng,chu};
int (*(*pparr)[5])(int, int) = &parr;
return 0;
}
qsort是标准库提供的排序函数
int cmp_int(void* e1, void* e2)//参数是指向两个整型的指针
{
return *(int*)e1 > *(int*)e2;//先强制类型转换再解引用
}
int main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
printf("%d ", arr[i]);
return 0;
}
struct stu
{
int age;
char name[20];
};
int cmp_name(const void* e1, const void* e2)
{
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2));
}
int cmp_age(const void* e1, const void* e2)
{
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int main()
{
struct stu s[3] = { {17,"ti"},{11,"yiti"},{20,"huang"} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_age);
return 0;
}
可以对结构体的成员进行排序
模拟qsort
指针进阶练习
sizeof()括号内不是单独放数组名的话,都相当于首元素的地址
传给strlen的是一个指针
strlen要遇到0才停下来
sizeof计算的是数据和变量所占内存空间的大小
strlen求的是字符串长度
到这里就要理解为什么strlen(*arr)是会报错的,因为相当于传了一个数的地址给strlen
strlen(&p)是随机值,是从p的地址开始往下找,和字符串的内存空间是两回事,p只是存放字符串的首元素地址
也不确定是大端还是小端存储,所以是随机值
a[ 3 ]不是真的去访问二维数组的第四行,sizeof只要确定类型就可以计算字节大小
sizeof(int)是直接给类型,sizeof(a)函数会分析a的类型,其实是一样的
总结:
数组名的意义:
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
2.&数组名,这里的数组名表示整个数组,出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。
总结就是精华所在,万变不离其宗
标签:arr,return,进阶,int,void,数组,指针 From: https://blog.csdn.net/2402_83411382/article/details/143265488