C模拟面向对象工具库

C模拟面向对象工具库,第1张

一.项目简介(Program info)

项目地址 工程仓库
本项目的初衷在于,使用java和c++进行了许多的面向对象编程之后。

由于电子专业原因。用回C时,感觉在编程的过程中不再那么规范了。

于是产生了使用 “函数指针” 这一知识点写一个模拟面向对象的容器库。

这样在调用的时候就可以利用类似 结构体.函数 这一种面向对象的方法 *** 作

省的每次再去头文件或者其他地方copy函数名字。

也让代码的内聚性更加高

头文件有很多的静态函数 但是静态不用管其实现,只需要调用结构体内部的函数指针即可使用

本人几乎没学过算法,所以源码里面的一些函数部分如果大家有更好的解决办法欢迎提出,
代码里肯定也存在一些不符合设计原则的地方。有时间会慢慢重构改善的

当前存在问题

1:如何写出this指针,不然每次传参都得把自己传进去,太麻烦了

2:如何实现泛型

3:迭代器设计模式

二.集合(Collector) 1.Vector

是一个连续空间的存储结构

名字由来于C++的stl容器库中的vector,有该有的功能,也有添加的功能,当然也有没实现的功能

使用方法:用New_Vector()这个接口函数获取vector的指针对象即可。

由于篇幅原因,测试代码和部分注释就只放了一小部分

Vector中的成员介绍
data真实存放的数据
capacity当前Vetor的容量
size当前Vector的数据个数
remove指定索引d出
lpop左d出
rpop右d出
insert指定位置插入
emplace指定位置插入(覆盖式插入)
lpush左插入
rpush右插入
at返回当前索引下标的数据地址
isEmpty是否为空
clear清除
destory销毁
resize重新指定大小
swap交换两元素下标
toString打印Vector里的data地址
front返回第一个元素的索引
back返回最后一个元素的索引
shrink_to_fit自动缩小到对应大小
reverse反转
#define VECTOR_DEFAULT_CAPCITY 10
//test
typedef struct student {
	char* name;
}Student;

/// 
/// 向量: 连续的存储结构
/// 
typedef struct vector {
	void** data;
	int capacity;
	int size;
	
	void* (*remove)(struct vector*, int index);
	void* (*lpop)(struct vector*);
	void* (*rpop)(struct vector*);
	//...省略后续
}Vector;

//-----------------接口---------------------
extern Vector* New_Vector();

测试代码

void test_rpop()
{
	char* name[12] = { "AA","BB","CC", "DD", "EE", "FF", "GG", "HH", "II","JJ", "KK", "LL" };
    //调用接口
	Vector* vector = New_Vector();
	for (size_t i = 0; i < 12; i++)
	{
        //这里的new是宏定义  #define new(T) calloc(1, sizeof(T))
		Student* stu = new(Student);
		stu->name = name[i];
        //传参传入自己,因为我暂时写不出this指针
		vector->rpush(vector, stu);
		stu = NULL;
		free(stu);
	}
	for (size_t i = 0; i < 12; i++)
	{
		Student* stu = vector->rpop(vector);
        //宏定义 防止空指针导致程序崩溃
		__NOT_NULL(stu, printf("name:%s\n", stu->name););
	}
}
2.Queue

队列Queue是一种先进先出的数据结构,利用成员变量继承自Vector基类

由于Vector是连续的,所以先进先出时,d出时相当于所有数据都要遍历一次

未来实现了链表的时候,会用链表优化

使用方法:调用New_Queue()获取一个Queue变量即可

Queue中的成员介绍
push插入数据
popd出数据
front返回第一个元素的索引
back返回最后一个元素的索引
empty是否为空
#pragma once
#include "vector.h"
//模拟C++和javad的Queue
//结构:利用成员变量继承自Vector,做出了面向对象部分的继承效果。
//使用方法:调用 New_Queue() 接口实例化对象,然后按需调用结构体内部的函数就行
//底下面向过程的函数是静态的所以无法调用哦 
typedef struct queue {
	int size;
	Vector* vector;

	void (*push)(struct stack*, void* data);
	void* (*pop)(struct stack*);
	void* (*front)(struct stack*);
	void* (*back)(struct stack*);

	//...省略后续
}Queue;
//接口
extern Queue* New_Queue();

测试代码

void queue_test()
{
	Queue* queue = New_Queue();
	char* name[12] = { "AA","BB","CC", "DD", "EE", "FF", "GG", "HH", "II","JJ", "KK", "LL" };
	if (queue->empty(queue)) {
		printf("Now is empty\n");
	}

	for (size_t i = 0; i < 12; i++)
	{
		Student* stu = new(Student);
		stu->name = name[i];
		stu->age = 1000000000;
		stu->hobby = "learn";
		queue->push(queue, stu);
	}
	queue->toString(queue);
	for (size_t i = 0; i < 12; i++)
	{
		Student* stu = queue->pop(queue);
		printf("%s  %d    %s\n", stu->name, stu->age, stu->hobby);
	}
	printf("\n");
}
3.Stack

栈Stack是一种先进后出的数据结构,利用成员变量方法继承自Vector基类

使用方法:调用 New_Stack();获取一个栈变量

Stack中的成员介绍
push插入数据入栈
popd出栈顶数据
top返回第一个元素的索引
empty是否为空
#pragma once
#include "vector.h"
//模拟C++和javad的Stack
//结构:利用成员变量继承自Vector。以及对应所需的函数
//使用方法:调用 New_Stack() 接口实例化对象,然后按需调用结构体内部的函数就行
//底下面向过程的函数是静态的所以无法调用哦 
typedef struct stack {
	int size;
	Vector* vector;

	void (*push)(struct stack*,void* data);
	void* (*pop)(struct stack*);
	void* (*top)(struct stack*);

	//...省略后续
}Stack;
//接口
Stack* New_Stack();

测试代码

void stack_test()
{
	Stack* stack = New_Stack();
	char* name[12] = { "AA","BB","CC", "DD", "EE", "FF", "GG", "HH", "II","JJ", "KK", "LL" };
	if (stack->empty(stack)) {
		printf("Now is empty\n");
	}
	
	for (size_t i = 0; i < 12; i++)
	{
		Student* stu = new(Student);
		stu->name = name[i];
		stu->age = 1000000000;
		stu->hobby = "learn";
		stack->push(stack, stu);
	}
	stack->toString(stack);
	for (size_t i = 0; i < 12; i++)
	{
		Student* stu = stack->pop(stack);
		printf("%s  %d    %s\n", stu->name,stu->age,stu->hobby);
	}
	printf("\n");
}
4.List

List是一个双向链表

List中的成员介绍
addFirst向前插入一个数据
addLast向后插入一个数据
insert向任意位置插入一个数据
removeFirst移除最前面的一个元素
removeLast移除最后一个元素
deleteNode删除任意位置的元素
isEmpty是否为空
destory销毁
printList打印
int main()
{
	Dlist* listNode = New_DList();
	listNode->addLast(listNode, 1);
	listNode->addLast(listNode, 2);

	int a = listNode->removeFirst(listNode);
	int b =listNode->removeLast(listNode);
	printf("%d %d\n",a,b);
	printf("%d\n", listNode->size);
	printf("%d\n", listNode->isEmpty(listNode));
	listNode->printList(listNode);
}
5.DStack

Dstack是一个链表实现的栈(前面那个是基于数组)

List中的成员介绍
addFirst向前插入一个数据
addLast向后插入一个数据
insert向任意位置插入一个数据
removeFirst移除最前面的一个元素
removeLast移除最后一个元素
deleteNode删除任意位置的元素
isEmpty是否为空
destory销毁
printList打印
int main()
{
	DStack* dstack = New_DStack();
	dstack->push(dstack, 1);
	dstack->push(dstack, 2);
	dstack->push(dstack, 3);
	dstack->push(dstack, 4);
	dstack->push(dstack, 5);

	int a = dstack->pop(dstack);
	int b = dstack->pop(dstack);
	printf("%d %d\n", a, b);
	printf("%d\n", dstack->size);
	printf("%d\n", dstack->isEmpty(dstack));
	dstack->printStack(dstack);
}
6.Deque

Deque是一个链表实现的队列(前面那个Queue是基于数组)

使用方法和成员变量与DStack完全一样 这里不做展示;

三.字符串(String)

可以理解为是一种加强的char*

以前使用char*时 如果涉及数据处理什么的,我们都需要去调用很多str系列的函数方法,例如strcpy,strcmp,strstr之类的

于是我封装了一个String结构体 内置了很多的处理函数,现在我们只需要使用一个String变量

即可方便的对我们的字符串数据进行处理

例如我们要转换大写

String* str = New_String("Jack");
str->upper(str);//调用upper即可进行大写转化

例如我们要截取串

String* str = New_String("BirthDay");
String* str2 = str->substring(str, 0 , 4);

例如我们要看是否包含子串

String* str = New_String("BirthDay");
if (str->contains(str, "Bir")) {
	puts("has the Bir");
}

下面给上函数

String中的成员介绍
data保存的真实数据
size数据长度
empty串是否为空
upper串转大写
lower串转小写
substring切割串,返回新串地址
copy复制原串到目标串
equal两串是否相等
equalIgnoreCase两串是否相等(忽略大小写)
contains是否包含子串
append追加(链式)
charAt返回指定索引的字符
#pragma once
#define _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#include "common.h"
//模拟C++和java的String库
//使用方法:用两个接口函数进行初始化,取决于你要无参还是有参
//有需要时调用结构体内部的函数即可,底下的静态函数你用不了,也不要用
//做成静态是因为我的初衷就是要模拟面向对象,所以会去掉部分面向过程的函数
typedef struct string String;
struct string
{	
	//data
	int size;
	char* data;
	//function
	bool (*empty)(String*);
	String* (*upper)(String*);
	String* (*lower)(String*);
	String* (*substring)(String* str,int start, int end);
	//...省略后续

};
//接口
extern String* New_String_NoArg(); 
extern String* New_String(char* data);

测试代码

void string_test1() {
	String* str = New_String("Jack");
	printf("%s size:%d\n", str->data, str->size);
	str->upper(str);
	printf("Upper:%s size:%d\n", str->data, str->size);
	str->lower(str);
	printf("Lower:%s size:%d\n", str->data, str->size);
	String* str2 = New_String("");
	if (str2->empty(str2)) {
		printf("Str2 is empty\n");
	}
}
void string_test2()
{
	String* str = New_String("BirthDay");
	String* str2 = str->substring(str, 0 , 4);
	printf("substring:%s\n", str2->data);
	str->copy(str, str2);
	printf("copy:%s\n", str2->data);
	if (str->equal(str, str2)) {
		puts("now is equal");
	}
	str->append(str," to")->append(str," you");
	printf("append:%s\n", str->data);
	printf("charAt:%c\n", str->charAt(str,0));
	if (str->contains(str, "Bir")) {
		puts("has the Bir");
	}
}
四.工具库(Tool Lib) 1.IntTool

一个专门服务于各种Int事项的工具类

调用方法只需要,先调用IntToolFactory()进行一次装配

然后使用全局变量 IntTool.函数()即可。

Int_Tool成员介绍
MAX_VALUEint最大值
MIN_VALUEint最小值
Max返回最大数
Min返回最小数
toBinaryString返回2进制string
toOctalString返回8进制string
toHexString返回16进制string
toDecString返回10进制string
toBinaryChar返回2进制char*
toOctalChar返回8进制char*
toHexChar返回16进制char*
toDecChar返回10进制char*
parseDecInt10进制char*转int
parseBinInt2进制char*转int
arrayMax数组最大值
arrayMin数组最小值
arrayAverage数组平均值
arraySum数组总和
sortByASEC升序排序数组
sortByDESC降序排序数组
printArr打印数组
#pragma once
#include "common.h"
#include "a_string.h"
#include "Interger.h"

/**
* 标题:单例模式设计的int工具类
* 使用方法:调用IntToolFactory();进行装配,并调用全局变量IntTool结构体里的函数即可
*/
typedef struct intTool Int_Tool;
struct intTool {
	int MAX_VALUE;
	int MIN_VALUE;
	int (*Max)(int a, int b);
	int (*Min)(int a, int b);
	int (*sum)(int a, int b);

	//省略后续...
};
//-----Interface-----
Int_Tool IntTool;
//-----Factory-----
extern void IntToolFactory();

部分测试代码

	printf("MAX_VALUE:%d  MIN_VALUE:%d\n", IntTool.MAX_VALUE, IntTool.MIN_VALUE);
	printf("parseDecInt:%d\n", IntTool.parseDecInt("123321"));
	printf("Char* Binary:%s\n", IntTool.toBinaryChar(INT_MAX));
	int a[] = { 1,2,5,4,3 };
	printf("intArrMax:%d\n", IntTool.arrayMax(a, ARR_SIZE(a)));
	IntTool.sortByASEC(a, ARR_SIZE(a));
	//底下这个到时候提供一个数组遍历吧
	printf("SortASEC:%d %d %d %d %d\n", a[0], a[1], a[2], a[3], a[4]);
2.DoubleTool

一个专门服务于各种Double事项的工具类

调用方法只需要,先调用DoubleToolFactory()进行一次装配

然后使用全局变量 DoubleTool.函数()即可。

#pragma once
#include "common.h"
#include "a_string.h"
/**
* 标题:单例模式设计的double工具类
* 使用方法:调用DoubleToolFactory();进行装配,并调用全局变量DoubleTool结构体里的函数即可
*/
typedef struct doubleTool Double_Tool;
/// doubleTool:解决double问题的工具类
struct doubleTool {
	double MAX_VALUE;
	double MIN_VALUE;
	double (*Max)(double a, double b);
	double (*Min)(double a, double b);
	double (*sum)(double a, double b);

	//省略后续...
};
//-----Interface-----
Double_Tool DoubleTool;
//-----Factory-----
extern void DoubleToolFactory();

部分测试代码

	printf("Min:%lf\n", DoubleTool.Min(1.1, 10.1));
	printf("Sum:%lf\n", DoubleTool.sum(1.1, 10.1));
	printf("paresDouble:%lf\n", DoubleTool.parseDecDouble("3.1415926"));
	printf("toChar:%s\n", DoubleTool.toChar(DoubleTool.MAX_VALUE));
	printf("toString:%s\n", DoubleTool.toString(5)->data);
	double a[] = { 1.5,2.5,5,4.5,3.5 };
	DoubleTool.sortByDESC(a, ARR_SIZE(a));
	printf("SortDESC:%lf %lf %lf %lf %lf\n", a[0], a[1], a[2], a[3], a[4]);

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/722197.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存