Day23.C提高7
一、链表逆序
//接上一次的代码(此处只附逆序函数)
void Reverse_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//创建辅助指针
struct LinkNode* pCurrent = header->next;
struct LinkNode* pNext = NULL;
struct LinkNode* pPrev = NULL;
while (pCurrent != NULL)
{
pNext = pCurrent->next;
pCurrent->next = pPrev;
pPrev = pCurrent;
pCurrent = pNext;
}
header->next = pPrev;
}
二、作业_排序算法(选择排序)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int myCompareInt(void* pJ, void* pMinOrMax)
{
int* p1 = (int*)pJ;
int* p2 = (int*)pMinOrMax;
return (*p1 < *p2);
}
void SelectSort(void* ptr,int ele_size,int num,int(*compare)(void*,void*))
{
char* temp = malloc(ele_size);
for (int i = 0; i < num; ++i)
{
int minOrMax = i;
for (int j = i + 1; j < num; ++j)
{
char* pMinOrMax = (char*)ptr + minOrMax * ele_size;
char* pJ = (char*)ptr + j * ele_size;
if (compare(pJ, pMinOrMax))
{
minOrMax = j;
}
}
if (minOrMax != i)
{
char* pMinOrMax = (char*)ptr + minOrMax * ele_size;
char* pI = (char*)ptr + i * ele_size;
memcpy(temp, pI, ele_size);
memcpy(pI, pMinOrMax, ele_size);
memcpy(pMinOrMax, temp, ele_size);
}
}
if (NULL != temp)
{
free(temp);
temp = NULL;
}
}
void test201()
{
int arr[] = { 7,4,9,2,1,21.5,98,564,414,2515641,1651,13216,321 };
SelectSort(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), myCompareInt);
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i)
{
printf("%d ", arr[i]);
}
}
int main(void)
{
test201();
system("pause");
return EXIT_SUCCESS;
}
三、预处理指令
“文件包含处理”是指一个源文件可以将另外一个文件的全部内容包含进来,C语言提供了#include命令来实现“文件包含”的操作。
不带参数的宏定义(宏常量)
#define MAX 1024
/*
1.宏名一般用大写,以便于与变量区别
2.宏定义可以是常数、表达式等
3.宏定义不作语法检查,只有在编译被宏展开后的源程序才会报错
4.宏名有效范围从定义到本源文件结束
5.可以用#undef命令终止宏定义的作用域
6.在宏定义中,可以引用已定义的宏名
*/
带参数的宏定义(宏函数)
//在项目中,经常把一些短小而又频繁使用的函数写成宏函数,这是由于宏函数没有普通函数参数压栈、跳转、返回等的开销,可以调高程序的效率
#define SUM(x,y) ((x)+(y))
void test()
{
//仅仅只做文本的替换,下例替换为 int ret = ((10) + (20));
//不进行计算
int ret = SUM(10, 20);
printf("ret:%d ", ret);
}
注意:
1.用括号括住每一个参数,并括住宏的整体定义
2.用大写字母表示宏的函数名
3.如果打算宏函数代替函数来加快程序运行速度,假如在程序中只使用一次宏,对程序的运行时间没有太大提高
四、条件编译(常见三种方式)
测试存在:
#define 标识符
#ifdef 标识符
程序段1
#else
程序段2
#endif
测试不存在:
#define 标识符
#ifndef 标识符
程序段1
#else
程序段2
#endif
根据表达式定义:
#if 表达式
程序段1
#else
程序段2
#endif
五、一些特殊的预定宏
C编译器,提供了几个特殊形式的预定义宏,在实际编程中可以直接使用,很方便。
//__FILE__ 宏所在文件的源文件名
//__LINE__ 宏所在行的行数
//__DATE__ 代码编译的日期
//__TIME__ 代码编译的时间
例子:
void doLogic(int* p)
{
if(NULL == p)
{
printf("%s 的 %d行出错\n",__FILE__,__LINE__);
return;
}
}
int main()
{
doLogic(NULL);
}
六、动态库的封装和使用
库的基本概念:
库是已经写好的、成熟的、可复用的代码。每个程序都需要依赖很多底层库,不可能每个人的代码都从零开始编写,因此库的存在具有非常重要的意义。
在我们的开发的应用中经常有一些公共代码是需要反复使用的,就把这些代码编译为库文件。
库可以简单看成一组目标文件的集合,将这些目标文件经过压缩打包之后形成的一个文件。
创建静态库:
省略
静态库优缺点
优点: 1.静态库对函数库的链接是放在编译时期完成的,静态库在程序的链接阶段被复制到了程序中,和程序运行的时候没有关系;
2.程序在运行时与函数库再无瓜葛,移植方便。
缺点: 1.浪费空间和资源,所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件,因此每次运行一次可执行文件都会重新创建相关的目标文件与牵涉到的函数库,故会浪费很多的资源和内存。
2.4 动态库的创建
动态库的函数分为:内部函数、外部函数(导出函数)
void func(){}; //内部函数
__declspec(dllexport) int myAdd(int a, int b); //外部函数(导出函数)
创建过程省略
2.5 动态库的使用
创建主程序TestDll,将mydll.h、mydll.dll和mydll.lib复制到源代码目录下。
在程序中指定链接引用链接库 : #pragma comment(lib,"./mydll.lib")
七、递归函数
C通过运行时堆栈来支持递归函数的实现。递归函数就是直接或者间接调用自身的函数。
递归函数必须有退出条件(结束条件)
例子(递归函数实现字符串反转等):
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"LinkList.h"
void reversePrint(char* p)
{
//1.首先要确定递归退出条件
if (!*p)
{
return;
}
reversePrint(p + 1);
printf("%c", *p);
}
//字符串逆序打印
void test301()
{
char* s = "abcdefg";
reversePrint(s);
}
void reverseLinkListPrint(struct LinkNode* pCurrent)
{
if (NULL == pCurrent)
{
return;
}
reverseLinkListPrint(pCurrent->next);
printf("%d ", pCurrent->data);
}
//链表逆序打印
void test302()
{
//初始化一个链表
struct LinkNode* header = Init_LinkList();
//链表逆序打印
reverseLinkListPrint(header->next);
//打印链表
printf("\n------------------\n");
Foreach_LinkList(header);
//销毁链表
Destroy_LinkList(header);
}
void recursion(int val)
{
if (val == 0)
{
return;
}
recursion(val / 10);
printf("%d ", val % 10);
}
void test303()
{
int a = 8793;
//依次打印千位数字8,百位数字7,十位数字9,个位数字3
recursion(a);
}
int main(void)
{
//test301();
//test302();
test303();
system("pause");
return EXIT_SUCCESS;
}
LinkList.h
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#ifdef __cplusplus
extern "C" {
#endif
//定义结点数据类型
struct LinkNode
{
int data;
struct LinkNoda* next;
};
//初始化链表
struct LinkNode* Init_LinkList();
//在值为oldval的位置插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval);
//删除值为delValue的结点
void RemoveByValue_LinkList(struct LinkNode* header, int delValue);
//遍历链表
void Foreach_LinkList(struct LinkNode* header);
//销毁链表
void Destroy_LinkList(struct LinkNode* header);
//清空链表
void Clear_LinkList(struct LinkNode* header);
//链表逆序
void Reverse_LinkList(struct LinkNode* header);
#ifdef __cplusplus
}
#endif
LinkList.c
#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 (1)
{
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;
}
//在值为oldval的位置插入一个新的数据newval
void InsertByValue_LinkList(struct LinkNode* header, int oldval, int newval)
{
if (NULL == header)
{
return;
}
//两个辅助指针变量
struct LinkNode* pPrev = header;
struct LinkNode* pCurrent = pPrev->next;
while (pCurrent != NULL)
{
if (pCurrent->data == oldval)
{
break;
}
pPrev = pCurrent;
pCurrent = pPrev->next;
}
//如果pCurrent为NULL,说明链表中不存在值为oldval的结点
//写上此if语句,若不存在值为oldval的结点,则不做操作
//不写此语句,若不存在值为oldval的结点,将newval添加到链表最后
//if (pCurrent == NULL)
//{
// return;
//}
//先创建新节点
struct LinkNode* newnode = malloc(sizeof(struct LinkNode));
newnode->data = newval;
newnode->next = NULL;
//新结点插入到链表中
pPrev->next = newnode;
newnode->next = pCurrent;
}
//删除值为delValue的结点
void RemoveByValue_LinkList(struct LinkNode* header, int delValue)
{
if (NULL == header)
{
return;
}
//创建两个辅助指针变量
struct LinkNode* pPrev = header;
struct LinkNode* pCurrent = pPrev->next;
while (pCurrent != NULL)
{
if (pCurrent->data == delValue)
{
break;
}
//移动两个辅助指针
pPrev = pCurrent;
pCurrent = pPrev->next;
}
//如果pCurrent为NULL,说明链表中不存在值为delValue的结点
if (pCurrent == NULL)
{
return;
}
//重新建立待删除结点的前驱和后继结点关系
pPrev->next = pCurrent->next;
//释放删除结点的内存空间
free(pCurrent);
pCurrent = NULL;
}
//遍历链表
void Foreach_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
printf("%d ", pCurrent->data);
pCurrent = pCurrent->next;
}
}
//销毁链表
void Destroy_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header;
while (pCurrent != NULL)
{
//先保存一下当前结点的下一个结点地址
struct LinkNode* pNext = pCurrent->next;
printf("%d 结点被销毁\n", pCurrent->data);
//释放当前结点内存
free(pCurrent);
pCurrent = NULL;
//pCurrent指向下一个结点
pCurrent = pNext;
}
}
//清空链表
void Clear_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//辅助指针变量
struct LinkNode* pCurrent = header->next;
while (pCurrent != NULL)
{
//先保存一下当前结点的下一个结点地址
struct LinkNode* pNext = pCurrent->next;
//释放当前结点内存
free(pCurrent);
pCurrent = NULL;
//pCurrent指向下一个结点
pCurrent = pNext;
}
header->next = NULL;
}
//链表逆序
void Reverse_LinkList(struct LinkNode* header)
{
if (NULL == header)
{
return;
}
//创建辅助指针
struct LinkNode* pCurrent = header->next;
struct LinkNode* pNext = NULL;
struct LinkNode* pPrev = NULL;
while (pCurrent != NULL)
{
pNext = pCurrent->next;
pCurrent->next = pPrev;
pPrev = pCurrent;
pCurrent = pNext;
}
header->next = pPrev;
}
八、面向接口编程
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//初始化
typedef void(*init_CSocketProtocol)(void** handle);
//发送接口
typedef void(*send_CSocketProtocol)(void* handle,unsigned char* sendData,int sendLen);
//接收接口
typedef void(*recv_CSocketProtocol)(void* handle, unsigned char* recvData,int* recvLen);
//关闭接口
typedef void(*close_CSocketProtocol)(void* handle);
struct Info
{
char data[1024];
int len;
};
//初始化
void init_CSocketProtocol_1(void** handle)
{
if (handle == NULL)
{
return;
}
struct Info* info = malloc(sizeof(struct Info));
memset(info, 0, sizeof(struct Info));
*handle = info;
}
//发送接口
void send_CSocketProtocol_1(void* handle, unsigned char* sendData, int sendLen)
{
if (NULL == handle || NULL == sendData)
{
return;
}
struct Info* info = (struct Info*)handle;
strncpy(info->data, sendData, sendLen);
info->len = sendLen;
}
//接收接口
void recv_CSocketProtocol_1(void* handle, unsigned char* recvData, int* recvLen)
{
if (NULL == handle || NULL == recvData || NULL == recvLen)
{
return;
}
struct Info* info = (struct Info*)handle;
strncpy(recvData, info->data, info->len);
*recvLen = info->len;
}
//关闭接口
void close_CSocketProtocol_1(void* handle)
{
if (handle == NULL)
{
return;
}
free(handle);
handle = NULL;
}
//业务代码
void FrameWork(
init_CSocketProtocol init,
send_CSocketProtocol send,
recv_CSocketProtocol recv,
close_CSocketProtocol close
)
{
//初始化连接
void* handle = NULL;
init(&handle);
//发送数据
char buf[] = "快发论文";
int len = strlen(buf);
send(handle, buf, len);
//接收数据
char recvBuf[1024] = { 0 };
int recvLen = 0;
recv(handle, recvBuf, &recvLen);
printf("%s\n", recvBuf);
//关闭连接
close(handle);
handle = NULL;
}
void test401()
{
FrameWork(init_CSocketProtocol_1,
send_CSocketProtocol_1,
recv_CSocketProtocol_1,
close_CSocketProtocol_1);
}
int main(void)
{
test401();
system("pause");
return EXIT_SUCCESS;
}