一.项目简介(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 | 指定索引弹出 | lpop | 左弹出 | rpop | 右弹出 | insert | 指定位置插入 | emplace | 指定位置插入(覆盖式插入) | lpush | 左插入 | rpush | 右插入 | at | 返回当前索引下标的数据地址 | isEmpty | 是否为空 | clear | 清除 | destory | 销毁 | resize | 重新指定大小 | swap | 交换两元素下标 | toString | 打印Vector里的data地址 | front | 返回第一个元素的索引 | back | 返回最后一个元素的索引 | shrink_to_fit | 自动缩小到对应大小 | reverse | 反转 |
#define VECTOR_DEFAULT_CAPCITY 10
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++)
{
Student* stu = new(Student);
stu->name = name[i];
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是连续的,所以先进先出时,弹出时相当于所有数据都要遍历一次
未来实现了链表的时候,会用链表优化
使用方法:调用New_Queue()获取一个Queue变量即可
Queue中的成员介绍 | |
---|
push | 插入数据 | pop | 弹出数据 | front | 返回第一个元素的索引 | back | 返回最后一个元素的索引 | empty | 是否为空 |
#pragma once
#include "vector.h"
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 | 弹出栈顶数据 | top | 返回第一个元素的索引 | empty | 是否为空 |
#pragma once
#include "vector.h"
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);
例如我们要截取串
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"
typedef struct string String;
struct string
{
int size;
char* data;
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"
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);
};
Int_Tool IntTool;
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"
typedef struct doubleTool Double_Tool;
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);
};
Double_Tool DoubleTool;
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]);
|