我正在尝试使用 C 编程语言创建一个通用链接列表 成功但我有一点问题:
linked_list.h
struct Element {
void * data;
struct Element * nEl;
};
typedef struct Element Element;
struct List {
size_t el_size;
Element * start_el;
};
typedef struct List List;
linked_list.c
List * create_list(size_t el_size);
void delete_list(List * ls);
void append(List * ls, void * data);
void s_append(List * ls, void * data);
void append(List * ls, void * data) {
Element * last_el = ls - > start_el;
if (last_el == NULL)
ls - > start_el = last_el = malloc(sizeof(Element));
else {
while (last_el - > nEl != NULL)
last_el = last_el - > nEl;
last_el - > nEl = malloc(sizeof(Element));
last_el = last_el - > nEl;
}
void * cdata = malloc(ls - > el_size);
memcpy(cdata, data, ls - > el_size);
last_el - > data = cdata;
last_el - > nEl = NULL;
}
适用于所有类型,例如int
,char
,float
,double
等。
但它不能与char *
一起使用,因为它复制了前4个bytes
(依赖于实现)string
,但不是整个string
。
答案 0 :(得分:3)
问题是列表中每个元素的大小是固定的(el_size)。并非所有字符串都具有相同的大小,假设每个字符为1个字节" hola"将占用4个字节,而#34; hi"占用2个字节。
答案 1 :(得分:2)
您应该使用更通用的方法。您应该使用指向要保留的对象的构造函数的函数指针,而不是仅仅分配内存。
在该函数中,您应该正确分配类型所需的空间。 并且在使用相同的原理后不要忘记正确清理。
这两个功能应该是struct
的成员。
这可能会对您有所帮助:How do function pointers in C work?
答案 2 :(得分:1)
您的列表绝不应分配和复制数据。这不是它的工作。它只应存储数据(作为指针)。复制数据是列表创建者的责任。
因此,而不是
void * cdata = malloc(ls - > el_size);
memcpy(cdata, data, ls - > el_size);
last_el -> data = cdata;
你会有
last_el -> data = data;
也没有释放数据。
现在,如果您想要一个拥有其数据的列表,您也可以将其作为基本非拥有列表的包装。这个想法是你只在需要时才这样做。并非每个列表都需要拥有其内容。
拥有其内容的列表需要有一种方法来复制和处理数据,ant应该作为一对函数指针提供复制和释放数据。这不是一个不适当的负担,因为每种数据类型都应该为它定义这样的功能。
答案 3 :(得分:0)
我赞成memcpy是链表中的坏主意。我已经在队列中使用它(使用链接列表下方),链接列表只有在我没有开始释放(节点 - >数据)时才有效。当我在前面(),pop_front()这样的调用顺序中执行此操作时,为了不丢失我的free()ed数据,我开始使用memcpy但这是一个可怕的事情。我想当你进行结构时,它只释放第一个字段。当你记忆这样的结构时((对generics void *进行操作)你只能复制指针,因为它只指向一个结构字段,所以你会丢失这些结构中的字段而不是第一个。
所以要恢复: 放弃INSERT操作中的memcpy以及REMOVING放弃释放(节点 - >数据)
答案 4 :(得分:0)
void指针是我自己使用的,但是假设您要执行此操作,因为您不想针对将要使用的不同数据类型多次重写列表的整个实现,则可以实现一次例如使用
Exception in thread "main" org.openqa.selenium.TimeoutException: Timed out
waiting for page to load.
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-
14T08:25:48'
System info: host: 'INGGNED89DP882', ip: '10.197.131.45', os.name: 'Windows
10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_60'
Driver info: org.openqa.selenium.ie.InternetExplorerDriver
Capabilities {acceptInsecureCerts: false, browserName: internet explorer,
browserVersion: 11, javascriptEnabled: true, pageLoadStrategy: normal,
platform: WINDOWS, platformName: WINDOWS, proxy: Proxy(), se:ieOptions:
{browserAttachTimeout: 0, elementScrollBehavior: 0, enablePersistentHover:
true, ie.browserCommandLineSwitches: , ie.ensureCleanSession: true,
ie.fileUploadDialogTimeout: 3000, ie.forceCreateProcessApi: false,
ignoreProtectedModeSettings: true, ignoreZoomSetting: false, initialBrowserUrl:
http://localhost:46027/, nativeEvents: true, requireWindowFocus: false},
setWindowRect: true, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}}
Session ID: 908d30d6-dc3f-4ac8-a1ca-1ddfc060b716
然后,每次您想要将列表用于不同的数据类型时,只需复制源文件和头文件以不同的名称,然后将int *替换为要使用的数据类型即可。 我不是这个的忠实拥护者,因此不建议这样做,但是我认为值得一提。