首页 > 其他分享 > test29 指针进阶3-8

test29 指针进阶3-8

时间:2023-02-12 23:35:00浏览次数:56  
标签:sz arr 进阶 int void test29 ret printf 指针

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

}

标签:sz,arr,进阶,int,void,test29,ret,printf,指针
From: https://blog.51cto.com/u_15880362/6052250

相关文章

  • C语言--指针与堆空间
    1.堆空间的本质--备用的“内存仓库”,以字节为单位预留的可用内存--程序可在需要时从“仓库”中申请使用内存(动态借)--当不需要再使用申请的内存时,需要及时归......
  • C语言--指针与函数
    1.深入函数--函数的本质是一段内存中的代码(占用一片连续内存)--函数拥有类型,函数类型有返回值和参数类型列表组成eg:intsun(intn)<==>int(int)......
  • 蜗牛式学习Java--基础进阶2--常用API(Scanner,String,StringBuilder)
     1.2键盘录入字符串Scanner类:next():遇到了空格,就不再录入数据了,结束标记:空格,tab键nextLine():可以将数据完整的接收过来,结束标记:回......
  • 蜗牛式学习Java--基础进阶--面向对象1
    1.2类的定义 1.3对象的创建和使用 2.1成员变量和局部变量 2.2this关键字 5.1构造方法的格式和执行时机 5.4标准类的代码编写和......
  • Rust智能指针
    Rust智能指针https://course.rs/advance/smart-pointer/intro.htmlBox堆对象分配Box指针拥有内存对象的独占使用权(一)使用场景1.使用Box将数据存储在堆上fnmain(......
  • C语言--指针与数组
    1.数组的本质就是一片连续的内存;2.一些事实-使用取地址操作符&获取数组的地址-数组名可看作一个指针,代表数组中0元素的地址-当指针指向数组元素时,可......
  • C语言--深入理解指针与地址
    1.初学指针的军规--Type*类型的指针只保存Type类型变量的地址--禁止不同类型的指针相互赋值注意:指针保存的地址必须是有效地址eg:inti=10;floa......
  • C语言--指针:一种特殊的变量
    1.因为是变量,所以用于保存具体值,特殊之处,指针保存的值是内存中的地址--内存地址:内存就是计算机中的存储部件,每个存储单元有固定唯一的编号--内存中存储单元的编......
  • C语言:指针 运行结果
    #include<stdio.h>//程序运行结果:【1】int*f(int*x,int*y){if(*x<*y)returnx;elsereturny;}main(){inta=7,b=8,*p=&a,*q=&b,*r;r=f......
  • MySQL - 进阶
    1、存储引擎MySQL体系结构:连接层最上层是一些客户端和链接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所......