【发布时间】:2018-03-29 17:19:34
【问题描述】:
我已经用纯 C 语言实现了 ArrayList。
标题(arraylist.h):
#pragma once
struct ArrayListImpl;
typedef int LISTTYPE;
typedef struct ArrayListImpl ArrayList;
ArrayList* new_ArrayList(int iSize);
void destroy(ArrayList* list);
int indexOf(ArrayList* list, LISTTYPE element);
void add(ArrayList* list, LISTTYPE element);
void addBefore(ArrayList* list, int index, LISTTYPE element);
void clear(ArrayList* list);
_Bool contains(ArrayList* list, LISTTYPE element);
_Bool removeEl(ArrayList* list, LISTTYPE element);
void removeFrom(ArrayList* list, int index);
void set(ArrayList* list, int index, LISTTYPE element);
int size(ArrayList* list);
void print(ArrayList* list);
void printInfo(ArrayList* list);
实现(arraylist.c):
#include "arraylist.h"
#include <stdlib.h>
#include <stdio.h>
struct ArrayListImpl
{
int size, buffer, origBuffer;
LISTTYPE* data;
};
void incBuffer(ArrayList* list)
{
if (list->size == list->buffer)
{
list->buffer = (int)(list->buffer * 1.5 + 1);
list->data = (LISTTYPE*)realloc(list->data, sizeof(LISTTYPE) * list->buffer);
}
}
void decBuffer(ArrayList* list)
{
if (list->size < list->buffer / 2.5 && list->buffer > list->origBuffer)
{
list->buffer = max(list->origBuffer, list->buffer / 2);
list->data=(LISTTYPE*)realloc(list->data, sizeof(LISTTYPE) * list->buffer);
}
}
void resetBuffer(ArrayList* list)
{
list->buffer = list->origBuffer;
list->data = (LISTTYPE*)realloc(list->data, sizeof(LISTTYPE) * list->buffer);
}
ArrayList* new_ArrayList(int buffer)
{
ArrayList* out;
out = (ArrayList*)malloc(sizeof out);
out->size = 0;
out->buffer = buffer;
out->origBuffer = buffer;
out->data = (LISTTYPE*)malloc(buffer * sizeof(LISTTYPE));
return out;
}
void destroy(ArrayList* list)
{
free(list->data);
}
int indexOf(ArrayList* list, LISTTYPE element)
{
for (int i = 0; i < list->size; ++i)
{
if (list->data[i] == element)
return i;
}
return -1;
}
void add(ArrayList* list, LISTTYPE element)
{
incBuffer(list);
list->data[list->size++] = element;
}
void addBefore(ArrayList* list, int from, LISTTYPE element)
{
if (from < 0 || from > list->size)
{
printf("[ERROR] Trying to add before %d. element of list having size %d\n", from, list->size);
return;
}
incBuffer(list);
++list->size;
for (int i = list->size; i > from; --i)
{
list->data[i] = list->data[i - 1];
}
list->data[from] = element;
}
_Bool removeEl(ArrayList* list, LISTTYPE element)
{
int id = indexOf(list, element);
if (id == -1)
return 0;
--list->size;
for (int i = id; i < list->size; ++i)
{
list->data[i] = list->data[i + 1];
}
decBuffer(list);
return 1;
}
void removeFrom(ArrayList* list, int index)
{
if (index < 0 || index >= list->size)
{
printf("[ERROR] Trying to remove %d. element of list having size %d\n", index, list->size);
return;
}
--list->size;
for (int i = index; i < list->size; ++i)
{
list->data[i] = list->data[i + 1];
}
decBuffer(list);
}
_Bool contains(ArrayList* list, LISTTYPE element)
{
return indexOf(list, element) != -1;
}
int size(ArrayList* list)
{
return list->size;
}
void clear(ArrayList* list)
{
list->size = 0;
resetBuffer(list);
}
void set(ArrayList* list, int index, LISTTYPE element)
{
if (index < 0 || index >= list->size)
{
printf("[ERROR] Trying to set %d. element of list having size %d\n", index, list->size);
return;
}
list->data[index] = element;
}
void print(ArrayList* list)
{
printf("--- ArrayList ---\n");
for (int i = 0; i < list->size; ++i)
{
printf("%d.: %dn", i, list->data[i]);
}
printf("\n-------------------\n");
}
void printInfo(ArrayList* list)
{
printf("--- ArrayList INFO ---\nSize: %d\nElement size : %d\nBuffer : %d\n", list->size, sizeof(int), list->buffer);
}
如您所见,它仅适用于头文件中定义的 LISTTYPE 类型的数据。我的问题是,我怎样才能使它普遍适用于任何类型的数据类型?因此,例如以某种方式将 LISTTYPE 添加到它的构造函数而不是它的标题中。是否有可能做到这一点,或者至少在纯 C 中而不是在 C++ 中做类似的事情?
【问题讨论】:
-
是的,但具体是什么?我还没有真正找到任何解决方案,这就是我在这里问的原因。
-
您有几个函数接受
LISTTYPE类型的参数。 C 函数参数的数据类型是包含它们的函数类型的一部分,因此在编译函数时是固定的。如果不重新编译函数,就无法更改它。 -
这种情况的常用方法是让列表存储指向元素的指针,而不是元素本身。然后,您可以对这些指针使用类型
void *,并且用户需要在取消引用它们之前将它们转换为适当的指针类型。可以想象编写宏包装器来协助完成所有这些工作。 -
还请注意,当元素是字符串或已经是指针时,存储指向元素的指针和存储元素本身之间的区别会显着消失。当然,可以创建和存储指向指针的指针,但也可以直接存储原始指针。
-
我知道 void * 是如何工作的,但是正如您在我的源代码中看到的那样,如果我将 LISTTYPE* 替换为 void*,那么我将在取消引用它们时遇到严重问题,例如在添加元素时到列表中。
标签: c arraylist implementation generic-programming universal