如何制作通用链表

时间:2014-06-23 14:49:19

标签: c algorithm list struct primitive-types

我正在尝试使用 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;
 }

适用于所有类型,例如intcharfloatdouble等。 但它不能与char *一起使用,因为它复制了前4个bytes (依赖于实现)string,但不是整个string

5 个答案:

答案 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 *替换为要使用的数据类型即可。 我不是这个的忠实拥护者,因此不建议这样做,但是我认为值得一提。