深入理解指针4
1.字符指针变量
#include<stdio.h>
int main()
{
char* ps = "abcdef";
//这种赋值,是把字符串中首字符的地址,赋值给p, ps存放的是首元素a的地址。
*ps = ‘w’;//当把"abcdef"改为w时,
程序会崩溃,
这是因为"abcdef"是常量字符串,
不能被修改,故需要把
char* ps = "abcdef";改为const char* ps = "abcdef";
}
int main()
{
const char*ps = "abcdef";
printf("%s\n",ps);
return 0;
}
结果为:abcdef
int main()
{
char arr[] = "abcdef";
printf("%c\n",arr[2]);
printf("%c\n","abcdef"[2]);
return 0;
}
结果为:c c
可见,输出的结果是一样的
2.数组指针变量
字符指针变量--变量--存放的是字符指针(地址)
char ch;
char*pc = &ch;
整型指针变量--变量--存放的是整型指针(地址)
int num;
int *pa = #
数组指针变量--变量--存放的是数组指针(地址)
int arr[10];
int(*ps)[10] = &arr; //&arr是数组的地址
//这里的ps 就是数组指针变量
//它的类型是:int(*)[10]
#include<stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int (*p)[10] = &arr;
//p+1 跳过整个数组的 ---40个字节
//*p ----整个数组
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0])
for(i = 0;i<sz;i++)
{
printf("%d",);
}
return 0;
}
3.二维数组传参的本质
一维数组传参
void Printf(int arr[3][5],int r,int c)
{
int i = 0;
int j = 0;
for(i = 0;i<r;i++)
{
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};
Printf(arr,3,5);
return 0;
}
二维数组传参,实参也是数组名
数组名是数组首元素的地址
既然实参传过去的是地址,形参就可以写成指针变量
二维数组的数组名就是第一行的地址,二维数组的首元素是它的第一行
二维数组其实是一维数组的数组,以一维数组为元素
故 int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
有3个元素
void Printf(int (*p)[5],int r,int c)
{
int i = 0;
int j = 0;
for(i = 0;i<r;i++)
{
for(j = 0;j<c;j++)
{
printf("%d",arr[i][j]);
//printf("%d",*(*(p+1)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7};
Printf(arr,3,5);
return 0;
}
4.函数指针变量
int Add(int x,int y)
{
return x+y;
}
int main()
{
int (*pf)(int x,int y) = &Add;
int ret = (*pf)(2,3);
//int ret = pf(2,3);
printf("%d\n",ret);
//int (*pf)(int ,int ) = &Add;
//ps就是函数指针变量
//它的类型是int (*)(int x,int y)
//printf("%p\n",&Add);
return 0;
}
------->5
说明函数也有地址
&函数名,函数名 ----取到的都是函数的地址,它只有一个地址
int main()
{
( * ( void ( * )( ) ) 0 )( );
reutrn 0;
}
---->将0强制类型转换成void(*)()这种类型的函数指针
0现在是一个函数的地址,这个函数没有参数,返回类型是void
int main()
{
void ( * signal( int ,void( * )( int ) ) ) ( int );
//其实是
void ( * ) ( int )signal( int ,void( * )( int ) );
但是语法不支持这样写
//signal是一个函数的名字
//这个代码是一个函数的声明
//声明的这个函数的名字是signal
//signal函数有2个参数,第一个参数是int类型,第二个参数是void(*)(int)这样的函数指针类型,该函数指针能够指向的函数参数是int类型,返回类型是void
reutrn 0;
}
typedef关键字
是用来类型重命名,可以将复杂的类型,简单化
如
typedef unsigned int uint;
//uint == unsigned int
typedef int* ptr_t;
int main()
{
unsigned int num;
uint num2;
int* p1,p3;
//p1----int*
//p3----int
ptr_t p2,p3;
//p2----int*
//p4----int*
return 0;
}
typedef int (*pf_t)[10]; //parr_t 是数组指针类型
int Add(int x,int y)
{
return x + y;
}
typedef int (*pf_t)(int ,int)
int main()
{
int (*pf_t)(int ,int) = Add;
pt_t pf2 = Add; // pf2 是函数指针变量
return 0;
}
5.函数指针数组
int Add(int x,int y)
{
return x + y;
}
int Sub(int x,int y)
{
return x - y;
}
int main()
{
int (*pf1)(int ,int ) = Add;
int (*pf2)(int ,int) = Sub;
//Add,Sub这些函数的地址存放在一个数组中
//存放函数指针的数组
//称函数指针数组
//创建 int (*pfArr[4])(int ,int ) = {Add,Sub};
}
用途
写一个计算器
完成整数的加法,减法,乘法,除法
void menu()
{
printf("**************************\n");
printf("**** 1.add 2.sub******\n");
printf("*****3.mul 4.dio*******\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 Siv(int x,int y)
{
return x / y;
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch(input)
{
case 1:
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
ret = Add(x,y);
printf("%d\n",ret);
break;
case 2:
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
ret = Sub(x,y);
printf("%d\n",ret);
break;
case 3:
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
ret = Mul(x,y);
printf("%d\n",ret);
break;
case 4:
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
ret = Siv(x,y);
printf("%d\n",ret);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择");
break;
}while(input);
return 0;
}
简化
用途
写一个计算器
完成整数的加法,减法,乘法,除法
void menu()
{
printf("**************************\n");
printf("**** 1.add 2.sub******\n");
printf("*****3.mul 4.dio*******\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 Siv(int x,int y)
{
return x / y;
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
//函数指针的数组
int (*pfArr[5])(int ,int) = {0,Add,Sub,Mul,Div};
// 0 1 2 3 4
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
if(input>=1&&input <=4)
{
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
pfArr[input](x,y)
printf("%d\n",ret);
}
else if(input == 0)
{
printf("退出计算器\n");
break;
}
else
{
printf("选择错误,重新选择\n");
}
}while(input);
return 0;
}
6.转移表
深入理解指针
1.回调函数
就是通过函数指针调用的函数
如果你把函数的指针作为参数传递给另一个函数,
当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数
int Add(int x,int y)
{
return x+y;
}
void test(int (*pf)(int ,int))
{
int ret = pf(4,5);
printf("%d\n",ret);
}
int main()
{
test(Add);
return 0;
}
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 Siv(int x,int y)
{
return x / y;
}
void Calc(int(*pf)(int,int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入两个操作数>:");
scanf("%d%d",&x,&y);
ret = pf(x,y);
printf("%d\n",ret);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d",&input);
switch(input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}while(input);
return 0;
}
2.qsort使用举例
qsort---库函数
它可以实现任意类型数据的排序
这是因为它使用了回调函数的方式
3.qsort函数的模拟实现