Cday06---链表和函数指针

1.函数指针的定义

在这里插入图片描述
在这里插入图片描述

void func() {
	printf("hello world!");
}

//func函数名其实是代表函数的入口地址
//如何定义一个指向函数的指针

int myfunc(int a, char b) {
	printf("int myfunc(int a, char b)\n");
	return 0;
}

void test() {
	//1.定义函数类型,通过类型来定义函数指针
	typedef int(FUN_TYPE)(int, char);
	FUN_TYPE* pFunc = myfunc;
	pFunc(10, 'a');
	(*pFunc)(20, 'b');

	//2.直接定义函数指针类型
	typedef int(*FUNC_P)(int, char);
	FUNC_P pFunc2 = myfunc;
	pFunc2(20, 'd');

	//3.直接定义函数指针变量
	//把指针转换为函数指针类型写法
	int(*pFunc3)(int, char) = (int(*)(int, char))NULL;
	pFunc3 = myfunc;
	pFunc3(50, 'e');
	printf("pFunc3 size:%d\n", sizeof(pFunc3));
}

在这里插入图片描述

2.函数指针做函数参数

int con1(int a, int b) {
	return a + b;
}

int con2(int a, int b) {
	return a + b - 10;
}

int con3(int a, int b) {
	return a + b + 10;
}

//使用函数指针就可以将函数作为另一个函数的参数
void doLogic(int(*pFunc)(int, int)) {
	int a = 20; int b = 10;
	int ret = pFunc(a, b);
	printf("ret = %d\n", ret);
}

void test() {
	//通过函数指针可以方便地调用编写的规则,不用大幅更改代码
	doLogic(con3);
}

在这里插入图片描述

void func1() {
	printf("func1\n");
}

void func2() {
	printf("func2\n");
}

void func3() {
	printf("func3\n");
}

void test() {
	//函数指针数组
	void(*func_array[3])(); 
	func_array[0] = func1;
	func_array[1] = func2;
	func_array[2] = func3;

	for (int i = 0; i < 3; ++i) {
		func_array[i]();
	}
}

在这里插入图片描述

struct Person {
	char name[64];
	int age;
};

//函数指针做函数参数(回调函数)
void printAllArray(void* arr, int eleSize, int len,void(*print)(void *)) {
	//先拿到元素首地址,然后通过函数指针回传给调用函数
	char* start = (char*)arr;
	for (int i = 0; i < len; ++i) {
		//printf("%d\n", start+i*eleSize);//元素首地址
		char* eleAddr = start + i * eleSize;
		print(eleAddr);
	}
}

void myPrint(void* data) {
	//data为地址,强转为指定类型后即可输出
	int* p = (int*)data;
	printf("%d ", *p);
}

void myPrintPerson(void* data) {
	struct Person* person = (struct Person*)data;
	printf("Name:%s Age:%d\n", person->name, person->age);
}

void test() {
	int arr[] = { 1,2,3,4,5 };
	printAllArray(arr, sizeof(int), 5, myPrint);

	struct Person persons[] = {
		{"aaa",10},
		{"bbb",20},
		{"ccc",30},
		{"ddd",40},
	};
	printAllArray(persons, sizeof(struct Person), 4, myPrintPerson);
}

在这里插入图片描述

3.链表的定义

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.静态链表

在这里插入图片描述

//链表节点类型定义
struct linkNode {
	int data;
	struct linkNode* next;
};

void test() {
	struct linkNode node1 = { 10,NULL };
	struct linkNode node2 = { 20,NULL };
	struct linkNode node3 = { 30,NULL };
	struct linkNode node4 = { 40,NULL };
	struct linkNode node5 = { 50,NULL };
	struct linkNode node6 = { 60,NULL };
	node1.next = &node2;
	node2.next = &node3;
	node3.next = &node4;
	node4.next = &node5;
	node5.next = &node6;

	//如何遍历链表
	//先定义一个辅助指针变量
	struct linkNode* pCur = &node1;
	while (pCur != NULL)
	{
		printf("%d ", pCur->data);;
		//指针移动到下一个元素的首地址
		pCur = pCur->next;
	}
}

在这里插入图片描述
在这里插入图片描述

5.动态链表的基本操作

初始化、遍历、插入、清空、删除和销毁

//linkList.h
#pragma once
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>//可计算偏移量
#include <stdbool.h>

//为了在C++中能调用C写的函数
#ifdef __cplusplus
extern "C" {
#endif

	//定义节点数据类型
	struct linkNode {
		int data;
		struct linkNode* next;
	};

	//初始化链表
	struct linkNode* init_linkList();
	//在值为val的位置插入一个新数据newVal
	void insertValue(struct linkNode* header, int value, int newVal);
	//删除值为val的节点
	void removeValue(struct linkNode* header, int value);
	//遍历
	void forEach(struct linkNode* header);
	//销毁
	void destroy(struct linkNode* header);
	//清空
	void clearLinkList(struct linkNode* header);
	//链表逆序
	void reverse_linkList(struct linkNode* header);

#ifdef __cplusplus
}
#endif
//linkList.c
#define _CRT_SECURE_NO_WARNINGS
#include "linkList.h"

//初始化链表
struct linkNode* init_linkList() {
	//创建头结点
	struct linkNode* header = malloc(sizeof(struct linkNode));
	header->data = -1;
	header->next = NULL;

	//尾部指针
	struct linkNode* pRear = header;

	int val = -1;
	while (true) {
		printf("输入插入的数据:\n");
		scanf("%d", &val);
		if (val == -1)
			break;
		//先创建新节点
		struct linkNode* newNode = malloc(sizeof(struct linkNode));
		newNode->data = val;
		newNode->next = NULL;

		//新节点插入到链表中
		pRear->next = newNode;
		//更新尾部指针
		pRear = newNode;
	}
	return header;
}

//在值为val的位置插入一个新数据newVal
void insertValue(struct linkNode* header, int value, int newVal) {
	if (NULL == header)
		return;
	//两个辅助指针变量
	struct linkNode* pPrev = header;
	struct linkNode* pCur = pPrev->next;
	while (pCur != NULL) {
		if (pCur->data == value)
			break;
		//未找到时,继续向后移动
		pPrev = pCur;
		pCur = pCur->next;
	}
#if 0 
	//如果pCur为空,说明链表中不存在值为value的节点
	if (NULL == pCur) {
		return;
	}
#endif
	//先创建新节点
	struct linkNode* newNode = malloc(sizeof(struct linkNode));
	newNode->data = newVal;
	newNode->next = NULL;
	//新节点插入到链表中
	newNode->next = pCur;
	pPrev->next = newNode;
}

//删除值为val的节点
void removeValue(struct linkNode* header, int value) {
	if (NULL == header)
		return;
	//两个辅助指针变量
	struct linkNode* pPrev = header;
	struct linkNode* pCur = pPrev->next;
	while (pCur != NULL) {
		if (pCur->data == value) {
			break;
		}
		//移动两个辅助指针
		pPrev = pCur;
		pCur = pCur->next;
	}
	//此时已找到节点或者节点不存在
	if (NULL == pCur) {
		return;
	}
	//重新建立待删除节点的前驱和后继节点关系
	pPrev->next = pCur->next;
	free(pCur);
	pCur = NULL;
}

//遍历
void forEach(struct linkNode* header) {
	if (NULL == header)
		return;
	//辅助指针变量
	struct linkNode* pCur = header->next;
	while (pCur != NULL) {
		printf("%d ", pCur->data);
		pCur = pCur->next;
	}
}

//销毁
void destroy(struct linkNode* header) {
	if (NULL == header)
		return;
	//辅助指针变量
	struct linkNode* pCur = header->next;
	while (pCur != NULL) {
		//先保存下当前节点的下一个节点地址
		struct linkNode* pNext = pCur->next;

		//释放当前节点内存
		printf("%d节点被销毁!\n", pCur->data);
		free(pCur);
		//指针向后移动
		pCur = pNext;
	}
}

//清空
void clearLinkList(struct linkNode* header) {
	if (NULL == header) {
		return;
	}
	//辅助指针变量
	struct linkNode* pCur = header->next;
	while (pCur != NULL) {
		//先保存下当前节点的下一个节点地址
		struct linkNode* pNext = pCur->next;
		//释放当前节点内存
		free(pCur);
		//pCur指向下一节点
		pCur = pNext;
	}
	header->next = NULL;
}

//链表逆序
void reverse_linkList(struct linkNode* header) {
	if (NULL == header)
		return;
	struct linkNode* pPrev = NULL;
	struct linkNode* pCur = header->next;
	struct linkNode* pNext = NULL;
	while (pCur != NULL) {
		pNext = pCur->next;
		pCur->next = pPrev;
		pPrev = pCur;
		pCur = pNext;
	}
	header->next = pPrev;
}
//main.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>//可计算偏移量
#include"linkList.h"

void test(){
	//初始化链表100 200 666 300 400 500 600
	struct linkNode* header = init_linkList();
	//打印链表
	forEach(header);
	//插入数据
	printf("\n-------------------\n");
	insertValue(header, 300, 666);
	//打印链表
	forEach(header);
	//逆序链表
	reverse_linkList(header);
	printf("\n---------逆序链表----------\n");
	forEach(header);

	//清空链表
	clearLinkList(header);
	printf("\n-------------------\n");
	//打印链表
	forEach(header);
	insertValue(header, 1000, 111);
	insertValue(header, 1000, 211);
	insertValue(header, 1000, 311);
	insertValue(header, 1000, 411);
	printf("\n-------------------\n");
	//打印链表
	forEach(header);

	//删除节点
	removeValue(header, 311);
	printf("\n-------------------\n");
	forEach(header);

	removeValue(header, 211);
	printf("\n-------------------\n");
	forEach(header);

	//销毁链表
	destroy(header);
}

int main(){
	test();
	return 0;
}

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值