#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<string.h>
//一级指针接收 地址或者指针
void print(int*ptr, int sz)//一级指针接收
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(ptr + i));
}
}
void test(char*p)
{
}
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(p, sz);//p是一级指针
char ch = 'w';
char*p1 = &ch;
test(&ch);//char*
test(p1);
return 0;
}
//二级指针传参
void test(int**p2)
{
**p2 = 20;
}
int main()
{
int a = 0;
int*pa = &a;//pa是一级指针
int**ppa = &pa;//ppa是二级指针
test(ppa);//把 1. 二级指针 进行传参
test(&pa);//传 2.一级指针的地址 两者几乎等价
int b = 0;
int*p3 = &b;
int*arr[10] = {p3};// 不能是空指针
test(arr);//传 3.存放一级指针的数组的数组名!!!!!!!!
printf("%d\n", a);//?
printf("%d", b);
return 0;
}
//【函数指针定义】 Add 前 加不加&都行 ,调用时 *pf() pf() Add() 3种
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 0;
int *pa = &a;
char ch = 'w';
char*pc = &ch;
int arr[10] = { 0 };
int (*parr)[10]= &arr; // 取出数组的地址
//parr是指向数组的指针 --存放的是数组的地址
//函数指针--存放函数地址的指针
//&函数名--取到的就是函数的地址
//pf就是一个 函数 指针变量
int(*pf)(int,int) = &Add;
//int(*pf)(int, int) = Add;
//返回类型+ 指针+函数参数
/*printf("%p ",&Add);
printf("%p ", Add);*/
// 数组名!= &数组名
//但是 函数名 == &函数名,只有函数是例外
return 0;
}
void test(char*str)
{
}
int main()
{
void(*pt)(char*)=&test;//viod省去了会报错
return 0;
}
int Add(int x, int y)
{
return x + y;
}
int main()
{
//pf就是一个函数指针变量
//int(*pf)(int, int) = &Add;
int(*pf)(int, int) = Add; //同上一行
//int ret = (*pf)(3, 5); 1
// 这个不行: int ret = *pf(3, 5); pf 成了函数
//int ret = pf(3, 5); // Add===pf 注:说明*是个摆设,用来理解的 2
int ret=Add(3,5); // 3
printf("%d\n", ret);
return 0;
}
//【调用0地址处的函数】用来理解,不可模仿 哈哈,0地址不可用。
int main()
{
(*(void(*)())0)();
//调用0地址处的函数
//该函数无参,返回类型是void
//1.void(*)() - 函数指针类型
//2.( void(*)() )0 - 对0进行强制类型转换,被解释为一个函数的地址(指针==地址)
//3. *((void(*)())0 - 对0地址进行了解引用操作
//4.(*((void(*)())0)() - 调用0地址处的函数
// ------《C陷阱和缺陷》
// 错误写法:把常量的值 作为地址:(*((void(*)())0x0012ff40)(),尽管编译器不会报错
return 0;
}
//void(*signal(int,void(*)(int)))(int);
void(*signal(int, void(*)(int)))(int);
//简化 写法如下
//tepedef-对类型进行重定义
typedef void(*pfun_t)(int);//对void(*)(int)函数指针类型 重命名为 pfun_t;
pfun_t signal(int, pfun_t);
//单独放,就是本身。 变量在右,等价于变量在中。
//1.signal 先和()先结合,说明signal是函数名;
//2.signal函数第一个参数的类型是int,第二个参数的类型是函数指针
//该函数指针,指向一个 参数为int,返回类型为void的函数
//3.signal函数的返回类型也是一个函数指针,因为signal的位置就在“函数指针的指针处”
//该函数指针,指向一个 参数为int,返回类型为void的函数
//signal是一个函数的声明
//【函数指针数组】
//整形指针 int*
//整形指针数组 int*arr[5]
//计算器 计算整型变量 加减乘除 (但是 case 1 2 3 4 重复多了,需要用函数指针数组来实现简便)
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("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
printf("xxxxx 1.add 2.sub xxxxxx\n");
printf("xxxxx 3.mul 4.div xxxxxx\n");
printf("xxxxx 0.exit xxxxxx\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
}
int main()
{
int input = 0;
do{
menu();
int(*parr[5])(int, int) = { NULL, Add, Sub, Mul, Div };
int ret = 0;
int x = 0;
int y = 0;
printf("请选择:>");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
ret = (parr[input](x, y));
printf("ret=%d\n", ret);
}
else if (input == 0)
{
printf("退出程序\n");
}
else
{
printf("选择错误\n");
}
// switch (input)
// {
//
// case 1:
// printf("请输入两个操作数:>");
// scanf("%d %d", &x, &y);
// ret = Add(x, y);
// printf("ret=%d\n", ret);
// break;
//
// case 2:
// printf("请输入两个操作数:>");
// scanf("%d %d", &x, &y);
// ret = Sub(x, y);
// printf("ret=%d\n", ret);
// break;
//
// case 3:
// printf("请输入两个操作数:>");
// scanf("%d %d", &x, &y);
// ret = Mul(x, y);
// printf("ret=%d\n", ret);
// break;
//
// case 4:
// printf("请输入两个操作数:>"); //打算计算 才提示 输入操作数
// scanf("%d %d", &x, &y);
// ret = Div(x, y);
// printf("ret=%d\n", ret); //有结果才打印
// break;
//
// case 0:
// printf("退出程序\n");
// break;
//default:
// printf("选择错误,请重新输入");
// break;
// }
} while (input);
//int(*pf1)(int,int)=Add;//pf是指向函数的指针
//int(*pf2)(int, int) = Sub;
//int(*pfarr[2])(int, int) = { Add, Sub };//函数指针数组 存放同类型的函数指针 多个
return 0;
}
//【回调函数】 函数指针数组最方便,此方法也行,适合封装
//计算器 回调函数版本(一个函数的地址 是另一个函数的参数)
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("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
printf("xxxxx 1.add 2.sub xxxxxx\n");
printf("xxxxx 3.mul 4.div xxxxxx\n");
printf("xxxxx 0.exit xxxxxx\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");
}
int Calc(int(*pf)(int, int))//回调函数( 函数指针需要和调用的函数类型吻合)(Calc执行重复部分和变化部分)
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
ret = pf(x, y);//可以用这个指针 调用传过来地址 对应的函数
printf("ret=%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("选择错误,请重新输入");
break;
}
} while (input);
return 0;
}
//【冒泡排序】(只能排序整形数据)
void bubble_sort(int arr[],int sz)
{
int i = 0;
//冒泡排序趟数:9趟 0-8 9 10不要
for (i = 0; i < sz - 1; i++)
{
//一趟冒泡排序:9 趟 9 8 7......
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
//交换
if (arr[j]>arr[j + 1])
{
int tmp = 0;
tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
}
void print_arr(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
print_arr(arr, sz);
bubble_sort(arr, sz);
print_arr(arr, sz);
return 0;
}
//【qsort学习】
void qsort(void*base,//base中存放的是 待排序数据中第一个对象的地址 1
size_t num,//排序数据中的 元素个数 2
size_t size,//排序数据中一个元素的大小,单位是字节 3
int(*compare)(const void*,const void*)//用来比较待排序数据中 两个元素 的 函数( 返回数> == < 0来比较) 4
[交给了使用者来实现]
)
int(*compare)(const void* e1,const void* e2) ; //e1 e2没什么意义,因为指针接收
qsort-库函数-的作者提供的,cmp交给了使用者 e1 e1换位置可以逻辑相反 实现降序
整形比较函数
int cmp_int(const void*p1, const void*p2)
{
return *(int*)p1 - *(int*)p2;// return >0, qsort就执行换位置的功能
}
struct Stu
{
char name[20];
int age;
};
//结构体Stu年龄比较函数
int sort_by_age(const void * e1, const void * e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
void test1()
{
//整形排序的数据
int arr[] = { 9, 8, 7, 6, 5, 4, 33, 3, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
//排序
qsort(arr, sz, sizeof(arr[0]), cmp_int);//首元素地址 元素个数 元素大小
//打印
print_arr(arr, sz);
}
int sort_by_name(const void * e1, const void * e2)
{
return strcmp( ((struct Stu*)e1)->name , ((struct Stu*)e2)->name );//失效了
//strcmp 返回值, 和我们要的效果一样(大于 就>0; 小于就<0; 等于就==0)
}
void test2()
{
//使用qsort排序 结构体数据
struct Stu s[3] = { { "la", 20 }, { "lc", 90 }, { "lb", 15 } };
int sz = sizeof(s) / sizeof(s[0]);
////按照年龄来排序
//qsort(s, sz, sizeof(s[0]), sort_by_age);
//按照名字来排序
qsort( s, sz, sizeof(s[0]), sort_by_name);
printf("%s ", s[0].name);
printf("%s ", s[1].name);
printf("%s ", s[2].name);
}
//【模仿qsort实现一个冒泡排序函的通用算法】
void Swap(char*buf1, char*buf2, int width)//交换程序
{
int i = 0;
for (i = 0; i <width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
void bubble_sort(void* base,
int sz,
int width,
int(*cmp)(const void *e1, const void* e2)//指向的元素类型不确定,加const只是比较 不会改变里面的值
//cmp是接收 比较函数 的指针
)
{
int i = 0;
for (i = 0; i < sz - 1; i++)//9趟
{
int j = 0;
for (j = 0; j < sz - 1 - i; j++)//9趟
{
//两个 元素比较
//原来 是 arr[j] 与 arr[j+1]比较 9 8 7 6 5 4 3 2 1 0
if ( cmp( (char*)base+j*width , (char*)base+(j+1)*width ) > 0)
{
//交换
Swap( (char*)base + j*width, (char*)base + (j + 1)*width ,width );
}
}
}
}
void test3()
{
//整形排序的数据
int arr[] = { 9, 8, 7, 1000,6, 5, 4, 33, 3,100, 2, 1, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
//排序
bubble_sort(arr, sz, sizeof(arr[0]),cmp_int);//首元素地址 元素个数 元素大小
//比较函数 cmp_int sort_by_name sort_by_age 三选一
//打印
print_arr(arr, sz);
}
int main()
{
//test1();
//test2();
test3();
return 0;
}