无法访问铸造的虚空指针

Unable to Access Casted Void Pointer

我正在创建一个链表,其中包含带有 "dataItem" 空指针的节点。这样做的目的是为了让节点能够包含任何类型的数据。但是,我无法访问 void 指针的数据,即使该数据已转换为正确的类型。

我的代码如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Student
{
    char stuName[51];
    char stuMajor[5];
    double GPA;
    char stuID[10];
}student;

typedef struct Node
{
    union{
        void *dataPtr;
        int countr;
    }dataItem;
    int  link;
    struct Node* next;
}node;
void readData(struct Node *);

void main(){
    node head;
    node temp;
    readData(&temp);
    student *ptr = (student *)(temp.dataItem.dataPtr);
    printf("%s    %d", ptr->stuName, ptr->GPA);//breaks here because unable to access memory
}

void readData(struct Node *link)
{
    link = (node *)malloc(sizeof(node));
    student *ptr = (student *)malloc(sizeof(struct Student));
    printf("enter the student name : ");
    fflush(stdin);
    scanf("%[^\n]", ptr->stuName);
    printf("enter the student's major : ");
    fflush(stdin);
    scanf("%[^\n]", ptr->stuMajor);
    printf("enter the student GPA : ");
    scanf("%lf", &(ptr->GPA));
    printf("enter the student ID : ");
    fflush(stdin);
    scanf("%[^\n]", ptr->stuID);
    link->dataItem.dataPtr = ptr;
}

我知道我肯定在某个地方有一个指针错误我不确定如何。我的 readData 函数中的节点也指向一个新的 Node malloc,因为在我进一步实现链表时每次调用 readData 时我都想要一个新节点。

你的代码很糟糕,

  1. 您没有包含任何头文件,malloc() 至少需要 stdlib.hprintf() 和 [= 至少需要 stdio.h 15=].

  2. 你的main()定义是错误的,因为main()必须returnint.

  3. fflush(stdin)这是未定义的行为。

  4. 您忽略 scanf() 中的 return 值。

  5. 您假设 malloc() 总是 return 是一个有效的指针。

  6. 您调用了尚未声明的 readData()

但最重要的错误是,您将 node temp 的地址传递给 readData()malloc() 编辑了它,但您没有 return指向它的指针,从而丢失在 readData() 中所做的所有更改,这无论如何都不会起作用,因为它在您调用它时未声明。

我修复了你的代码,因为我知道你不喜欢我的答案,但是检查了与答案相关的修复,现在它按我的预期工作了

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

typedef struct Student
{
    char stuName[51];
    char stuMajor[5];
    double GPA;
    char stuID[10];
} student;

typedef struct Node
{
    union{
        void *dataPtr;
        int countr;
    } dataItem;
    int          link;
    struct Node* next;
} node;

void readData(struct Node **link);


int main()
{
    node    *head;
    student *ptr;

    readData(&head);

    ptr = head->dataItem.dataPtr;
    if (ptr != NULL)
        printf("%s\t%g", ptr->stuName, ptr->GPA);
    return 0;
}

void readData(struct Node **link)
{
    student *ptr;
    if (link == NULL)
        return;
    *link = malloc(sizeof(node));
    if (*link == NULL)
        return;
    memset(*link, 0, sizeof(node));

    ptr = malloc(sizeof(struct Student));
    if (ptr == NULL)
        return;
    printf("enter the student name : ");
    if (scanf("%50[^\n]%*c", ptr->stuName) != 1)
        ptr->stuName[0] = '[=10=]';

    printf("enter the student's major : ");
    if (scanf("%4[^\n]%*c", ptr->stuMajor) != 1)
        ptr->stuMajor[0] = '[=10=]';

    printf("enter the student GPA : ");
    if (scanf("%lf%*c", &(ptr->GPA)) != 1)
        ptr->GPA = 0;

    printf("enter the student ID : ");
    if (scanf("%9[^\n]%*c", ptr->stuID) != 1)
        ptr->stuID[0] = 0;

    (*link)->dataItem.dataPtr = ptr;
}

我还对 scanf() 添加了一些安全修复程序,添加了长度修饰符以防止缓冲区溢出,并且还删除了带有 "%*c" 说明符的尾随 '\n',如果多个,它将​​不起作用空格跟在值后面,但是你可以同时按下 Enter/Return 来测试它,如果你想要更复杂的输入,你应该使用其他东西而不是 scanf().

这个:

void readData(struct Node *link)
{
    link = (node *)malloc(sizeof(node));

您丢弃了传入的 link 参数值,而是通过 malloc 为其分配新的分配。我认为这是你最重要的问题。一个简单的修复方法是删除执行 malloc.

的行

您想将一个指向一个节点的指针(或指针的地址)的指针传递给 readData() 函数。 readData 分配一个新节点并填充它;在你的代码中发生的事情是 readData() 得到一个 copy 的临时地址,用一个新地址覆盖这个地址的副本,这个地址是从 malloc 获得的(这是不可见的) main()) 中的调用代码,然后填充该 malloc 对象。在 return 从 readData 中,无法访问 malloc 对象。

你想做的是:

void main(){
    node head;
    node *tempAddr; // pointer
    readData(&tempAddr); // pass address of that pointer

然后在 main 中使用 *tempAddr 而不是 temp

void readData(struct Node **linkAddr)
{
    node *link = *linkAddr = (node *)malloc(sizeof(node));

[...]

unwind 会抱怨你不应该转换 malloc 的结果,但我认为这很好。我也不关心 main 的 return 值或其参数。