首页 > 解决方案 > 如何管理链表中不同类型的数据?

问题描述

我有一个项目,老师要求我们在链表中做一些操作。好的,它们很容易实现,但我在管理列表中的数据时遇到了麻烦。它们可以是以下任何一种:int、char、float 或 string(char 数组)。我知道如何单独链接其中的任何一个,但是当它们混在一起时,事情就开始变得混乱了。

我没有尝试太多,我被卡住了。以下是我脑海中闪过的一些想法:创建 4 个结构,每个数据类型 1 个(但我从未见过不同结构的链表,也许它不是定义上的列表,因为它们不是相同的结构类型)或为每种数据类型创建 1 个带有声明的结构。重要的是要告诉我我有一个变量,它告诉我当时我正在管理什么类型的数据(但是当我为我的函数传递参数时,我没有所有这些参数,除非我想出一些标志但它似乎很愚蠢,该项目没有为我的变量指定任何限制)。

抱歉没有显示任何代码,我认为在这种情况下没有必要,因为我的想法行不通。我可以向您展示我期望的结果,例如:

给定数据(第一个数字告诉我我的列表有多少个节点):

5

f 3.14

d 100

CX

花园的

d 300

我希望我的结果是:

3.1400 100 x 花园 300

我是这个主题的新手,我试图明确我对上面代码的想法。感谢您阅读本文,祝您星期四愉快。

标签: cdata-structureslinked-list

解决方案


通常,您需要添加一个类型标签,struct Node以便您可以跟踪存储在各个节点中的数据类型。

对于存储数据,您可以使用 void 指针,也可以使用联合。如果您使用 void 指针,您将需要在访问数据时进行强制转换。如果您使用联合,每个节点最终将使用与最大联合成员大小相对应的内存。

这是一个使用 void 指针的简单示例:

#include <stdio.h>
#include <stdlib.h>

enum ListType 
{
    INT = 0,
    FLOAT,
    CHAR,
    STRING,
};

struct Node
{
    struct Node *next;
    enum ListType type;
    void *data;
};

void printNode(struct Node *p)
{
    switch (p->type)
    {
        case INT:
            printf("%d ", *((int*)p->data));
            break;
        case FLOAT:
            printf("%f ", *((float*)p->data));
            break;
        case CHAR:
            printf("%c ", *((char*)p->data));
            break;
        case STRING:
            printf("%s ", (char*)p->data);
            break;
        default:
            printf("ERROR ");
            break;
    }
}

void printList(struct Node *p)
{
    while(p)
    {
        printNode(p);
        p = p->next;
    }
}

void freeListData(struct Node *p)
{
    while(p)
    {
        free(p->data);
        p = p->next;
    }
}

int main(void) {
    // Build the list manually to illustrate the printing
    struct Node N1;
    struct Node N2;

    N1.type = FLOAT;
    N1.data = malloc(sizeof(float));
    *((float*)N1.data) = 3.14;
    N1.next = &N2;

    N2.type = INT;
    N2.data = malloc(sizeof(int));
    *((int*)N2.data) = 100;
    N2.next = NULL;

    // .. more nodes

    printList(&N1);

    freeListData(&N1);

    return 0;
}

输出:

3.140000 100

这是一个使用 union的示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

enum ListType 
{
    INT = 0,
    FLOAT,
    CHAR,
    STRING,
};

union ListData
{
    int d;
    float f;
    char c;
    char *str;  // Memory for the string must be malloc'ed
};

struct Node
{
    struct Node *next;
    enum ListType type;
    union ListData data;
};

void printNode(struct Node *p)
{
    switch (p->type)
    {
        case INT:
            printf("%d ", p->data.d);
            break;
        case FLOAT:
            printf("%f ", p->data.f);
            break;
        case CHAR:
            printf("%c ", p->data.c);
            break;
        case STRING:
            printf("%s ", p->data.str);
            break;
        default:
            printf("ERROR ");
            break;
    }
}

void printList(struct Node *p)
{
    while(p)
    {
        printNode(p);
        p = p->next;
    }
}

void freeListStrings(struct Node *p)
{
    while(p)
    {
        if (p->type == STRING) free(p->data.str);
        p = p->next;
    }
}

int main(void) {
    // Build the list manually to illustrate the printing
    struct Node N1;
    struct Node N2;
    struct Node N3;

    N1.type = FLOAT;
    N1.data.f = 3.14;
    N1.next = &N2;

    N2.type = INT;
    N2.data.d = 100;
    N2.next = &N3;

    N3.type = STRING;
    N3.data.str = malloc(sizeof "Hello World");
    strcpy(N3.data.str, "Hello World");
    N3.next = NULL;

    // .. more nodes

    printList(&N1);

    freeListStrings(&N1);

    return 0;
}

输出:

3.140000 100 Hello World 

推荐阅读