C复习Day10
#技术笔记1.函数指针函数指针即指向函数的指针。它仍然是一个指针变量用于存储函数的地址。函数在虚拟内存中存储在代码段当中函数的地址是指向这些指令序列起始点的内存地址即函数的入口点。在C语言中函数指针最经常用的地方就是将函数作为参数传递。声明就是void (*fun)(void);在当形参传递的时候*和小括号()可以省略 变成void Fun(void)这样起别名也是函数指针中的一种奇怪的定义形式typedef void (*Fun)(void);就可以用 Fun f;来声明函数指针了。下面的qsort有一个例子来辅助理解函数指针的作用其实就是在业务中方便写一个通用模块再在通用模块中实现其他的逻辑。2.qsort()qsort函数是在头文件stdlib.h中的一个库函数用于排序内部采用快速排序。里面传入的参数理解起来就是一段话参数一给个要传的任意类型数组参数二数组的元素个数(可以用sizeof(数组名) / sizeof (数组名[0])这样的思路求)参数三就是数组中每个元素的大小用sizeof求一下就行参数四也就是函数指针类型了用于实现怎么笔记了,形式为int (*compare)(const void *a, const void *b)关于qsort函数 有二个规则排序规则对元素进行从小到大或者从大到小如果返回a - b最终数组会从小到大排列反过来b - a就是降序。比较大小的规则由函数指针传入的函数决定。(也是修改业务的核心举个例子)#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include stdlib.h #include string.h #define STU_LEN(stu) ((sizeof(stu)) / (sizeof(stu[0]))) typedef struct { char name[25]; int score; } Student; void print_students(Student stus[], int size); int compare_score(const void *a, const void *b) { Student *s1 a; Student *s2 b; if (s1-score ! s2-score) { return s1-score - s2-score; //asc } return strcmp(s1-name, s2-name); } void test() { Student stus[] { {赵日天, 59}, {龙傲天, 100}, {叶良辰, 85}, {李狗蛋, 45}, {张二狗, 68}, {翠花, 77}, {铁柱, 83}, {马nb, 60}, {赵四, 63}, {尼古拉斯赵四, 66}, {约瑟翰庞麦郎, 50}, }; qsort(stus, STU_LEN(stus), sizeof(Student), compare_score); print_students(stus, STU_LEN(stus)); } void print_students(Student stus[], int size) { for (int i 0; i size; i) { printf(%s, %d\n, stus[i].name,stus[i].score); } } int main(void) { test(); return 0; }3.二级指针二级指针可以称为指针的指针也就是一个指向另外一个指针的指针 也就是存储了另一个指针变量地址的指针。int NUM 10; int *p x; // 一级指针指向int变量 int **pp p; // 二级指针指向指针p // *pp 得到 p 的值即x的地址 // **pp 得到 x 的值即 10主要用途可以用来修改指针的指向(例如处理一些封装分配逻辑等)二维动态数组分配字符串数组(命令行参数) 前面文章使用过的。4.链表下面有一个关于二级指针应用的例子,是一个关于二级指针实现的一个链表。#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include stdlib.h typedef int ElementType; typedef struct node { ElementType data; struct node *next; } Node; // 头插法新增一个结点 void insert_head(Node **head, ElementType new_val); // 修改第一个结点的元素值如果链表为空则用new_val初始化第一个结点 void modify_first_node(Node **head, int new_val); // 尾插法新增一个结点 void insert_tail(Node **head, ElementType new_val); // 打印单链表 格式为1 - 2 - 3 -... void print_list(Node *head); int main(void) { Node *head NULL;//在main函数中定义一个head头指针等于NULL代表此时单链表为空 int n; printf(请输入你要创建的链表长度n: ); scanf(%d, n); //for (int i n; i 0; i--) //{ // insert_head(head, i); //这样头插方便后续输出 //} //print_list(head); for (int i 1; i n; i) { insert_tail(head, i); } print_list(head); return 0; } void modify_first_node(Node **head, int new_val) { if (*head NULL) { *head malloc(sizeof(Node)); if (*head NULL) { printf(malloc failed in modify_first_node.\n); return;//exit } //*head-data new_val; -的优先级比*高啊 (*head)-data new_val; (*head)-next NULL; } (*head)-data new_val; //链表非空可以不用else } void insert_head(Node **head, ElementType new_val) { Node *new_node malloc(sizeof(Node)); if (new_node NULL) { printf(malloc failed in insert_head.\n); return; } new_node-data new_val; new_node-next *head; *head new_node; } void print_list(Node *head) { Node *current head; //复制一份指针! while (current ! NULL) { printf( %d , current-data); if (current-next ! NULL) { printf(-); } current current-next; } printf(\n); } void insert_tail(Node **head, ElementType new_val)// { Node *new_node malloc(sizeof(Node)); if (new_node NULL) { printf(malloc failed in insert_tail.\n); return; } new_node-data new_val; new_node-next NULL; if (*head NULL) { *head new_node; return; } Node *tail *head; while (tail-next ! NULL) { tail tail-next; } tail-next new_node; }尾插法这里结构体没有尾指针确实不方便。