1.前言
数据结构是需要泛型的,而在C语言中实现泛型就只能去用指针魔法了,来跟我一起实现吧!所有代码经测试未发现明显bug,可放心食用.
2.代码截图展示
1.list.h
2.main.c
3.list.c
3.结语
这次分享的列表采用动态数组的方式实现,下次我会去用链表实现,两种实现方式各有优劣,希望初学者能够自己去实现一下.本次分享到此结束,记得点赞加收藏,你的点赞是我更新的动力!!!
4.可复制代码展示
//list.h
#pragma once
#include <assert.h>
#include <crtdefs.h>
#include <stdbool.h>
#include <stdio.h> // IWYU pragma: export
#include <stdlib.h> // IWYU pragma: export
#include <string.h> // IWYU pragma: export
#include <time.h> // IWYU pragma: export
typedef struct {
void *data;
size_t dataSize;
size_t size;
size_t capacity;
} List;
#define DEFAULT_CAPACITY 4
#define DRFPTR(type, ptr) (*(type *)ptr)
List *ListCreate(size_t dataSize);
#define mListCreate(TYPE) ListCreate(sizeof(TYPE))
void ListDestory(List *pList);
bool CheckCapacity(List *pList, size_t insertSize);
void ListPushBack(List *pList, const void *data);
void ListPopBack(List *pList);
void ListPrint(const List *pList, void (*pfPrint)(const void *));
size_t ListSize(List *pList);
size_t ListCapacity(List *pList);
void ListPushFront(List *pList, const void *data);
void ListPopFront(List *pList);
void ListPosInsert(List *pList, size_t pos, const void *data);
void ListPosErase(List *pList, size_t pos);
void ListRandomInsertIntData(List *pList,
size_t count,
size_t maxNum);
void ListSort(List *pList, int (*pfCmp)(const void *, const void *));
void ListRandomInsertDoubleData(List *pList, size_t count);
void ListDataModify(List *pList,
size_t pos,
void (*pfModify)(void *));
bool ListIsEmpty(List *pList);
bool ListReserve(List *pList, size_t size);
size_t ListResize(List *pList, size_t size);
void *ListDataAt(List *pList, size_t index);
void *ListHeadData(List *pList);
void *ListTailData(List *pList);
void ListClear(List *pList);
size_t ListFindData(List *pList,
const void *findData,
int (*pfCmp)(const void *, const void *));
void ListIndexAccess(const List *pList,
const size_t index,
void (*pfPrint)(const void *));
//main.c
#include "list.h"
typedef struct {
char name[20];
int age;
} People;
int CmpPeopleAge(const void *e1, const void *e2) {
return DRFPTR(People, e1).age - DRFPTR(People, e2).age;
}
int CmpPeopleName(const void *e1, const void *e2) {
return strcmp(DRFPTR(People, e1).name, DRFPTR(People, e2).name);
}
void PrintPeople(const void *data) {
printf("name:%-10s\tage:%2d\n", DRFPTR(People, data).name,
DRFPTR(People, data).age);
}
void ModifyInt(void *data) {
int *d = (int *)data;
*d = 666666;
}
void ModifyDouble(void *data) {
// printf("输入>>>");
// scanf("%lf", (double *)data);
*(double *)data = 0.123456;
}
void PrintInt(const void *data) {
printf("%d ", *(int *)data);
}
void PrintDouble(const void *data) {
printf("%.5lf ", *(double *)data);
}
int CmpInt(const void *e1, const void *e2) {
return *(int *)e1 - *(int *)e2;
}
int CmpDouble(const void *e1, const void *e2) {
return (*(double *)e1 > *(double *)e2
? 1
: (*(double *)e1 < *(double *)e2 ? -1 : 0));
}
void test_int() {
List *list = mListCreate(int);
printf("list size: %zu\n", ListSize(list));
printf("list capacity: %zu\n", ListCapacity(list));
// for (int i = 0, data; i < 3; i++) {
// data = rand() % 10;
// ListPushBack(list, &data);
// }
// ListPrint(list, PrintInt);
// for (int i = 0, data; i < 3; i++) {
// data = rand() % 10;
// ListPushFront(list, &data);
// }
// int a = 666;
// ListPosInsert(list, 2, &a);
// ListPrint(list, PrintInt);
// for (int i = 0; i < 1; i++) {
// ListPopBack(list);
// ListPopFront(list);
// }
// ListPosErase(list, 1);
// ListPosErase(list, 0);
// ListPosErase(list, ListSize(list) - 1);
ListRandomInsertIntData(list, 1234, 666);
// ListPrint(list, PrintInt);
ListSort(list, CmpInt);
// ListPrint(list, PrintInt);
printf("list size: %zu\n", ListSize(list));
printf("list capacity: %zu\n", ListCapacity(list));
size_t index;
while (1) {
int data;
printf("输入>>>");
scanf("%d", &data);
index = ListFindData(list, &data, CmpInt);
if (index == ListSize(list)) {
printf("找不到该数据,请重新输入!\n");
} else {
break;
}
}
printf("find data index is %zu\n", index);
ListIndexAccess(list, index, PrintInt);
ListDestory(list);
}
void test_double() {
List *list = mListCreate(double);
ListRandomInsertDoubleData(list, 13);
ListPrint(list, PrintDouble);
// ListSort(list, CmpDouble);
ListDataModify(list, 0, ModifyDouble);
ListDataModify(list, 4, ModifyDouble);
printf("list new size:%zu:\n", ListResize(list, 5));
ListPrint(list, PrintDouble);
// printf("list[last] is %lf\n",
// *(double *)ListDataAt(list, ListSize(list) - 1));
printf("list head data is %lf\n",
DRFPTR(double, ListHeadData(list)));
printf("list tail data is %lf\n",
DRFPTR(double, ListTailData(list)));
// ListClear(list);
printf("list size: %zu\n", ListSize(list));
printf("list capacity: %zu\n", ListCapacity(list));
size_t index;
while (1) {
double data;
printf("输入>>>");
scanf("%lf", &data);
index = ListFindData(list, &data, CmpInt);
if (index == ListSize(list)) {
printf("找不到该数据,请重新输入!\n");
} else {
break;
}
}
printf("find data index is %zu\n", index);
ListIndexAccess(list, index, PrintDouble);
ListDestory(list);
}
void test_struct() {
List *list = mListCreate(People);
People p;
for (int i = 0; i < 3; i++) {
printf("输入姓名>>>");
scanf("%s", p.name);
printf("输入年龄>>>");
scanf("%d", &p.age);
ListPushBack(list, &p);
}
ListPrint(list, PrintPeople);
// ListSort(list, CmpPeopleAge);
ListSort(list, CmpPeopleName);
ListPrint(list, PrintPeople);
size_t index;
while (1) {
People p;
printf("输入>>>");
scanf("%s", p.name);
// scanf("%d", &p.age);
// index = ListFindData(list, &p, CmpPeopleAge);
index = ListFindData(list, &p, CmpPeopleName);
if (index == ListSize(list)) {
printf("找不到该数据,请重新输入!\n");
} else {
break;
}
}
printf("find data index is %zu\n", index);
ListIndexAccess(list, index, PrintPeople);
ListDestory(list);
}
int main(void) {
srand((unsigned int)time(NULL));
// test_int();
// test_double();
test_struct();
return 0;
}
//list.c
#include "list.h"
List *ListCreate(size_t dataSize) {
List *list = (List *)malloc(sizeof(List));
if (NULL == list) {
printf("malloc fail!\n");
exit(-1);
}
void *ptr = malloc(DEFAULT_CAPACITY * dataSize);
if (NULL == ptr) {
printf("malloc fail!\n");
exit(-1);
}
list->data = ptr;
list->dataSize = dataSize;
list->capacity = DEFAULT_CAPACITY;
list->size = 0;
return list;
}
void ListDestory(List *pList) {
assert(pList);
free(pList->data);
pList->data = NULL;
free(pList);
pList = NULL;
}
bool CheckCapacity(List *pList, size_t insertSize) {
assert(pList && insertSize);
if (insertSize <= pList->capacity - pList->size) {
return true;
}
if (insertSize > 1) {
void *ptr = realloc(pList->data, (pList->capacity + insertSize) *
pList->dataSize);
if (NULL == ptr) {
printf("realloc fail!\n");
return false;
}
pList->data = ptr;
pList->capacity = pList->capacity + insertSize;
return true;
} else {
void *ptr =
realloc(pList->data, 2 * pList->capacity * pList->dataSize);
if (NULL == ptr) {
printf("realloc fail!\n");
return false;
}
pList->data = ptr;
pList->capacity = 2 * pList->capacity;
return true;
}
}
void ListPushBack(List *pList, const void *data) {
assert(pList && data);
if (CheckCapacity(pList, 1)) {
memcpy(pList->data + pList->dataSize * pList->size, data,
pList->dataSize);
pList->size++;
}
}
void ListPopBack(List *pList) {
assert(pList);
if (pList->size) {
pList->size--;
}
}
void ListPrint(const List *pList, void (*pfPrint)(const void *)) {
assert(pList);
for (int i = 0; i < pList->size; i++) {
pfPrint(pList->data + pList->dataSize * i);
}
printf("\n");
}
size_t ListSize(List *pList) {
assert(pList);
return pList->size;
}
size_t ListCapacity(List *pList) {
assert(pList);
return pList->capacity;
}
void ListPushFront(List *pList, const void *data) {
assert(pList && data);
if (CheckCapacity(pList, 1)) {
for (int i = pList->size; i > 0; i--) {
memcpy(pList->data + i * pList->dataSize,
pList->data + (i - 1) * pList->dataSize,
pList->dataSize);
}
memcpy(pList->data, data, pList->dataSize);
pList->size++;
}
}
void ListPopFront(List *pList) {
assert(pList);
if (pList->size) {
for (int i = 0; i < pList->size; i++) {
memcpy(pList->data + i * pList->dataSize,
pList->data + (i + 1) * pList->dataSize,
pList->dataSize);
}
pList->size--;
}
}
void ListPosInsert(List *pList, size_t pos, const void *data) {
assert(pList && data);
assert(pos < pList->size);
if (CheckCapacity(pList, 1)) {
for (int i = pList->size; i > pos; i--) {
memcpy(pList->data + i * pList->dataSize,
pList->data + (i - 1) * pList->dataSize,
pList->dataSize);
}
memcpy(pList->data + pos * pList->dataSize, data,
pList->dataSize);
pList->size++;
}
}
void ListPosErase(List *pList, size_t pos) {
assert(pList);
assert(pos < pList->size);
if (pList->size) {
for (int i = pos; i < pList->size; i++) {
memcpy(pList->data + i * pList->dataSize,
pList->data + (i + 1) * pList->dataSize,
pList->dataSize);
}
pList->size--;
}
}
void ListRandomInsertIntData(List *pList,
size_t count,
size_t maxNum) {
assert(pList);
assert(maxNum + 1 < RAND_MAX);
if (CheckCapacity(pList, count)) {
int data = 0;
for (int i = 0; i < count; i++) {
data = rand() % (maxNum + 1);
memcpy(pList->data + pList->dataSize * pList->size, &data,
sizeof(int));
pList->size++;
}
}
}
void ListSort(List *pList,
int (*pfCmp)(const void *, const void *)) {
assert(pList && pfCmp);
if (pList->size > 1) {
// qsort(void *Base, size_t NumOfElements, size_t SizeOfElements,
// int (*PtFuncCompare)(const void *, const void *)
// __attribute__((cdecl)))
qsort(pList->data, pList->size, pList->dataSize, pfCmp);
}
}
void ListRandomInsertDoubleData(List *pList, size_t count) {
assert(pList);
if (CheckCapacity(pList, count)) {
double data = 0;
for (int i = 0; i < count; i++) {
data = (double)rand() / RAND_MAX;
memcpy(pList->data + pList->dataSize * pList->size, &data,
sizeof(double));
pList->size++;
}
}
}
void ListDataModify(List *pList,
size_t pos,
void (*pfModify)(void *)) {
assert(pList && pfModify);
assert(pos < pList->size);
pfModify(pList->data + pList->dataSize * pos);
}
bool ListIsEmpty(List *pList) {
assert(pList);
if (0 == pList->size) {
return true;
} else {
return false;
}
}
bool ListReserve(List *pList, size_t size) {
assert(pList);
return CheckCapacity(pList, size);
}
size_t ListResize(List *pList, size_t size) {
assert(pList);
if (size <= pList->size) {
pList->size = size;
} else {
if (CheckCapacity(pList, size - pList->size)) {
memset(pList->data + pList->dataSize * pList->size, 0,
(size - pList->size) * pList->dataSize);
pList->size = size;
}
}
return pList->size;
}
void *ListDataAt(List *pList, size_t index) {
assert(pList);
assert(index < pList->size);
return pList->data + pList->dataSize * index;
}
void *ListHeadData(List *pList) {
assert(pList);
if (pList->size) {
return pList->data;
} else {
return NULL;
}
}
void *ListTailData(List *pList) {
assert(pList);
if (pList->size) {
return pList->data + pList->dataSize * (pList->size - 1);
} else {
return NULL;
}
}
void ListClear(List *pList) {
assert(pList);
pList->size = 0;
}
size_t ListFindData(List *pList,
const void *findData,
int (*pfCmp)(const void *, const void *)) {
assert(pList && findData && pfCmp);
for (int i = 0; i < pList->size; i++) {
if (0 == pfCmp(findData, pList->data + pList->dataSize * i)) {
return i;
}
}
return pList->size;
}
void ListIndexAccess(const List *pList,
const size_t index,
void (*pfPrint)(const void *)) {
assert(pList && pfPrint);
assert(index < pList->size);
pfPrint(pList->data + pList->dataSize * index);
}