C语言进阶之泛型列表(Generic List)

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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值