项目地址 工程仓库
本项目的初衷在于,使用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 | 插入数据 |
pop | d出数据 |
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 | 插入数据入栈 |
pop | d出栈顶数据 |
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_VALUE | int最大值 |
MIN_VALUE | int最小值 |
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* |
parseDecInt | 10进制char*转int |
parseBinInt | 2进制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]);
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)