【C语言】深入理解指针(下)

请添加图片描述
主页链接: LSR的主页
专栏链接: 《C语言》


前言

以下是指针的最后内容。


一、函数指针变量

1.类型

int (*pf3) (int x, int y)
 pf3指向函数的参数类型和个数的交代
 pf3为函数指针变量名
 pf3指向函数的返回类型
 ,其中x,y可以省略:
 int(*pf3)(int, int)
int ( * ) (int x, int y) //pf3函数指针变量的类型

可以类比数组和指针之间的关系:
int arr[10] = {0}
int (*pa)[10] = &arr


2.使用

#include<stdio.h>

int Add(int x, int y)
{
       return x+y;
}

int main()
{
         int (*pf3)(int, int) = Add;
         printf("%d\n", (*pf3)(2,3));
         printf("%d\n", pf(3, 5));
         return 0;
}
输出结果:
5
8

3.刻薄代码

(*(void(*)())0)()
void(*)() —— 函数指针类型定义
(void(*)())0 —— 强制类型转换
(*(void(*)())0)() —— 调用函数(或)((void(*)())0)();
void(*signal(int, void(*)(int)))(int)
signal(int, void(*)(int)) → 说明signal是一个函数,它的参数有两个:
第一个参数:int
第二个参数:void(*)(int)
剩余部分void(*)(int)就是signal的返回值类型

4.typedef关键字

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

typedef unsigned int unit;
//将unsigned int重命名为unit
//指针类型:将int* 重命名为ptr_t
typedef int* ptr_t;
//数组指针类型:将int (*)[5] 重命名为 parr_t
typedef int (*)[5] parr_t;
//函数指针类型:将void (*)(int)重命名为pf_t
typedef voud(*pf_t)(int)//新的类型名必须在*的右边

//简化第二个刻薄代码
typedef void(*p)(int)
p signal(int, p)

二、函数指针数组

定义:

int(*parr1[3])();
parr1先与[]结合,说明parr1是数组,数组内容是什么呢?
是int (*)()类型的函数指针。

三、转移表

函数指针数组的用途:转移表

1.实现加减乘除

#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 (*parr[4/*可以省略*/])int,int= {Add, Sub, Mul, Div};

       //8 4 
       //简单演示
       int i = 0;
       for(i = 0;i < 4;i++)
       {
            int r = parr[i](8, 4);
            printf("%d\n", r);
       }
       return 0;
}

2.实现加减乘除

2.1 一般实现

#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;
}

void menu()
{
      printf("*****************************\n");
      printf("*******1. add 2. sub*******\n");
      printf("*******3. mul 4. div********\n");
      printf("******* 0. exit   ************\n");
      printf("*****************************\n");
}


int main()
{
      int x = 0;
      int y = 0;
      int z = 0;
      int input = 0;
      do
      {
           menu();
           printf("请选择:");
           scanf("%d", &input);
           switch(input)
           {    
                     case 1:
                           printf("请输入两个操作数\n");
                           scanf("%d %d", &x, &y);
                           z = Add(x, y)
                           printf("%d\n", z);
                           break;
                     case 2:
                           printf("请输入两个操作数\n");
                           scanf("%d %d", &x, &y);
                           z = Sub(x, y)
                           printf("%d\n", z);
                           break;
                    case 3:
                           printf("请输入两个操作数\n");
                           scanf("%d %d", &x, &y);
                           z = Mul(x, y)
                           printf("%d\n", z);
                           break;
                    case 4:
                           printf("请输入两个操作数\n");
                           scanf("%d %d", &x, &y);
                           z = Mul(x, y)
                           printf("%d\n", z);
                           break;
                    case 0:
                           printf("退出游戏\n");
                           break;
                   default:
                           printf("选择错误,请重新选择\n");
                           break;
                           

           }
      }while(input);
      return 0;
}

2.2使用函数指针数组实现:

#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;
}

void menu()
{
      printf("*****************************\n");
      printf("*******1. add 2. sub*******\n");
      printf("*******3. mul 4. div********\n");
      printf("******* 0. exit   ************\n");
      printf("*****************************\n");
}



int main()
{
      int x = 0;
      int y = 0;
      int z = 0;
      int input = 0;
      int (*p[5])(int x, int y) = {0, add, sub, mul, div};//转移表
      do
      {
           menu();
           printf("请选择:");
           scanf("%d", &input);
           if(input<= 4 &&input>= 1)
           {
                 z = (*p[input])(x, y);
                 printf("%d\n", z);
           }
           else if(input ==0)
           {
                 printf("退出计算器\n");
           }
           else
           { 
                 printf("输入有误,请重新输入!!!\n");
           }
                           

           }
      }while(input);
      return 0;
}

2.3回调函数实现

#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;
}

void menu()
{
      printf("*****************************\n");
      printf("*******1. add 2. sub*******\n");
      printf("*******3. mul 4. div********\n");
      printf("******* 0. exit   ************\n");
      printf("*****************************\n");
}

void calc(int (*p)(int, int))
{
      int x = 0;
      int y = 0;
      int z = 0;  
      printf("请输入两个操作数\n");
      scanf("%d %d", &x, &y);
      z = p(x, y);
      printf("%d\n", z);
}
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;
}

三、qsort使用及模拟实现

使用头文件:stdlib.h,底层采用快速排序可以排序任意类型的数据。基本形式:

void qsort(void* base,//指针,指向的是待排序的数组的第一个元素
                 size_t num,//指向待排序数元素的个数
                 size_t size,//base指向的待排序数单个元素的大小(字节)
                 int (*compar)(const  void*, const void*)//函数指针,指向两个元素比较的函数
                 );

1.排序整形数据

//使用qsort排序整型数据
//比较函数
//使用比较函数的注意点:相比较的
		/*两个元素p1, p2,
		前 > 后,返回一个 > 0的数
		= ,返回0
		< ,返回一个 < 0的数
		返回>0的数就交换
		返回<=0的数就不变*/
#incldue<stdio.h>
int int_cmp(const void* p1, const void* p2)
{
       return *(int*)p1 - *(int*)p2;
}

void print(int*arr, int sz)
{
    int i = 0;
    for(i = 0;i<sz;i++)
    printf("%d ", arr[i]);
    printf("\n");
}
int main()
{
       int arr[] = {1, 3, 5 ,9, 2, 4, 6, 8, 0};
       int sz = sizeof(arr)/sizeof(arr[0]);
       qsort(arr, sz, sizeof(int), int_cmp);
       print(arr, sz);
       return 0;
}

2.排序结构数据

////结构体补充
////三种指向结构体成员的方式
// ->间接访问操作符
// 结构图指针->成员名
// 
// 
// 
// struct Stu
//{
//	char name[20];
//	int age;
//};
//
//void print(struct Stu* ps)
//{
//	/*printf("%s %d\n", (*ps).name,(*ps).age);*/
//	printf("%s %d", ps->name, ps->age);
//}
//int main()
//{
//	struct Stu s = {"zhangsan", 19};
//	/*printf("%s %d\n", s.name, s.age);*/
//	print(&s);
//	return 0;
//}



////创建变量:
//struct Stu
//{
//	char name[20];
//	int age;
//}s,s1;//通过类型创建的变量名
//
//typedef struct Stu
//{
//	char name[20];
//	int age;
//}stu;//修改的类型名

#include<stdio.h>
//使用qsort排序结构数据
struct Stu
{
	char name[20];
	int age;
};

//按照年龄来比较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test2()
{
	struct Stu arr[] = { {"zhangsan", 18},{"lisi", 29}, {"wangwu", 37} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}

//按照名字来比较
int cmp_stu_by_name(const void* e3, const void* e4)
{
	return strcmp(((struct Stu*)e3)->name, ((struct Stu*)e4)->name);//原理:按照对应的字符串中
	//的ASCII码值比较的
	//如:	a b q > a b c d e
	//和qsort比较函数返回规则一致
}
void test3()
{
	struct Stu arr[] = { {"zhangsan", 18},{"lisi", 29}, {"wangwu", 37} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
int main()
{
	test2();
	test3();
	return 0;
}

3.qsort函数的模拟实现

使用回调函数,采用冒泡方式,模拟实现qsort
//采用冒泡方式模拟实现qsort函数
int int_cmp(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}

void _swap(void* p1, void* p2,int size)
{
	int i = 0;
	for (i = 0; i < size; i++)
	{
		char tmp = *((char*)p1 + i);
		*((char*)p1 + i) = *((char*)p2 + i);
		*((char*)p2 + i) = tmp;
	}

}
bubble(void* base, int count, int size, int(*int_cmp)(void*, void*))
{
		int i = 0;
	int j = 0;
	for (i = 0; i < count - 1; i++)//有sz个元素,进行sz-1次循环
	{
		
		for (j = 0; j <count-1-i ; j++)//每次循环进行sz-1-i次比较
		{
			if (int_cmp((char*)base+j*size , (char*)base+(j+1)*size) > 0)
			{
				_swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
			}
		}
	}
}
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz, sizeof(arr[0]), int_cmp);
	print(arr, sz);
	return 0;
}

四、sizeof和strlen的对比

1. sizeof

  1. sizeof是操作符不是函数,虽然有(),但是求变量的内存大小可以省略(),如:sizeof(a) == sizeof a;
  2. sizeof计算操作数所占内存大小,单位是字节;
  3. 不关注内存所放的数据是什么
  4. 数组名的理解:
    数组首元素的地址
    but两个意外
    1.sizeof(数组名):数组名表示整个数组,计算整个数
    组大小,单位是字节
    2.&数组名:数组名表示整个数组,取出的是整个数组的地址
    注意:地址的大小始终为4/8个字节

2. strlen

  1. strlen是库函数,需包含头文件string.h;
  2. strlen是求字符串长度的,统计的是\0之前字符的各个数,单位字节
  3. 关注内存中是否有\0,如果没有,那就会往后一直找,可能会越界。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值