从double转换为指针

时间:2012-11-03 22:12:06

标签: c linked-list generic-list

我在C中相当新手,现在我正在尝试使用3个元素实现基本通用链表,每个元素将包含不同的数据类型值 - intchar和{{1 }}

这是我的代码:

double

我对前两个元素没有问题,但是当我尝试将double类型的值赋给第三个元素时,我收到一个错误:«无法从#include <stdio.h> #include <stdlib.h> struct node { void* data; struct node* next; }; struct node* BuildOneTwoThree() { struct node* head = NULL; struct node* second = NULL; struct node* third = NULL; head = (struct node*)malloc(sizeof(struct node)); second = (struct node*)malloc(sizeof(struct node)); third = (struct node*)malloc(sizeof(struct node)); head->data = (int*)malloc(sizeof(int)); (int*)(head->data) = 2; head->next = second; second->data = (char*)malloc(sizeof(char)); (char*)second->data = 'b'; second->next = third; third->data = (double*)malloc(sizeof(double)); (double*)third->data = 5.6; third->next = NULL; return head; } int main(void) { struct node* lst = BuildOneTwoThree(); printf("%d\n", lst->data); printf("%c\n", lst->next->data); printf("%.2f\n", lst->next->next->data); return 0; } 转换为{{1 }} »。

出现此错误的原因是什么?为什么doubledouble *出现同样的错误? 最重要的问题:如何解决这个问题,如何将int值分配给第三个元素的数据字段?

问题字符串是«char»。

感谢。

3 个答案:

答案 0 :(得分:6)

在“工作”示例中,您正在调用malloc来获取指向某个新分配空间的指针,然后立即抛出该指针并将指针值替换为你的整数或字符值。这或多或少是偶然的,因为在大多数C实现中,指针单元格可以包含整数或char值,但是您应该收到警告。如果您在这些分配后实际尝试取消引用数据指针,则可能会发生崩溃和核心转储。

您希望将值放在指针指向的位置,而不是指针本身。这意味着您需要额外的*

 *((double *)third->data) = 5.6;

*类型转换中的(double *)是类型名称的一部分 - “指向double的指针”。演员表示“取third->data的值并将其解释为指向双倍的指针”。结果仍然是一个指针,所以当你指定它时,你正在改变指针指向的位置(并且可能使它指向某个地方毫无意义)。相反,您希望为已经指向的位置指定一个值,这就是外部*所做的。

但是,如果您只存储intchardouble等基本类型,则无需通过指针(并担心伴随的内存)管理)。你可以使用一个联盟:

struct node 
{
    struct node *next;
    union {
        char c;
        int  i;
        double d;
    } data;
 }

然后你会这样做。

head->data.i = 2;
second->data.c = 'b';
third->data.d = 5.6;

答案 1 :(得分:2)

你正在施放指针,但是你需要为指派做出决定,因为intchar已被转换为指针,因此前两个指派工作正常,它应该是:

*((int*)(head->data)) = 2;
*((char*)(second->data)) = 'b';
*((double*)(third->data)) = 5.6;

无论如何,首先应该警告这样的演员。

答案 2 :(得分:1)

您无法将值分配给指针,您必须将其分配给指向的对象(在最后一种情况下,双倍 - 您只有空间一双)。

所以:

    ...
    head->data = (int*)malloc(sizeof(int));
    ((int*)(head->data))[0] = 2;
    head->next = second;

    second->data = (char*)malloc(sizeof(char));
    ((char*)second->data)[0] = 'b';
    second->next = third;

    third->data = (double*)malloc(2 * sizeof(double));
    ((double*)third->data)[0] = 5.6;
    ((double*)third->data)[1] = 3.1415;
    // We only allocated space for 2 doubles, so this line here would cause a crash
    // (or anyway, a data corruption)
    // ((double*)third->data)[2] = 666;
    third->next = NULL;

    return head;
}

int main(void)
{
    struct node* lst = BuildOneTwoThree();

    printf("%d\n", ((int *)lst->data)[0]);
    printf("%c\n", ((char *)lst->next->data)[0]);
    printf("%.2f\n", ((double *)lst->next->next->data)[0]);
    printf("%.2f\n", ((double *)lst->next->next->data)[1]);
    ...

返回:

2
b
5.60
3.14
BTW:在启用完全警告的情况下,编译器应警告您前两个分配有风险(GCC认为它们是错误)而第三个分配是不允许的(不能从双精度转换为指针)

还有一件事:当您以这种方式使用struct有效负载时,您必须考虑实际存储在有效负载本身中的数据类型。因此,您不能通过检查链接列表的实例来确定它是char,整数还是double。更糟糕的是,即使检查值也可能不被允许并使程序崩溃(假设您存储了一个字节,但尝试读取四个或八个)。

因此,您还应该在结构中存储一个额外的字段,其中包含原始数据类型的指示符(可能是enum):

typedef enum
{
    TYPE_IS_CHAR,
    TYPE_IS_INT,
    TYPE_IS_FLOAT,
    TYPE_IS_DOUBLE,
    ...
} mytype_t;

struct node
{
    mytype_t type;
    void     *data;
    struct node *next;
}