2015-04-21 4 views
1

Я создаю связанный список, содержащий узлы с «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 на новый malloc узла, потому что я хочу новый узел каждый раз, когда вызывается readData, когда я реализую связанный список дальше.

+1

Здесь 'student * ptr = (student *) (temp.dataItem.dataPtr);' cast совершенно не нужно. Также здесь 'link = (node ​​*) malloc (sizeof (node));'. И так далее ... И этот 'fflush (stdin);' является неопределенным поведением, вы никогда не должны 'fflush()' входного потока. Вы включили какие-либо заголовки? и 'main()' возвращает значение 'int'. –

ответ

5

Ваш код очень сломана,

  1. Вы не включать любой файл заголовка, вы должны по крайней мере stdlib.h для malloc() и stdio.h для printf() и scanf().

  2. Ваше неправильное определение main(), потому что main() должно вернуть int.

  3. Вы fflush(stdin), который является неопределенным поведением.

  4. Вы игнорируете возвращаемое значение от scanf().

  5. Вы предполагаете, что malloc() всегда возвращает действительный указатель.

  6. Вы вызвали readData(), который еще не объявлен.

Но самая главная ошибка, что вы прошли адрес node temp «с до readData() и вы malloc() эд его, но не возвращает указатель на него, тем самым теряя все изменения, сделанные в 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] = '\0'; 

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

    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(), добавляя модификатор длины для предотвращения переполнения буфера, а также удаляйте конечный '\n' с помощью спецификатора "%*c", он не будет работать, если несколько значений соответствуют этому значению, но вы можете проверить его, пока просто нажмите . Введите/вернуть, если вам нужен более сложный ввод, вы должны использовать что-то другое вместо scanf().

+0

1. эти заголовочные файлы включены, я думал, что было бы очевидно, что они будут 2. main не нужно возвращать int и будет возвращать только предупреждение, если оно не – beckah

+2

Это не очевидно, и это общая причина проблем , Поскольку ваш компилятор не жаловался на 'readData()', поэтому разумно подумать, что вы не включили файлы заголовков. Объявление неявной функции - ваш враг, и вы, кажется, игнорируете это, потому что вы не объявляли 'readData()' перед вызовом. То же самое произойдет, если вы не включите заголовки, не включив предупреждения компилятора, сделайте код без каких-либо проблем, что не означает, что проблем нет. –

+0

@beckah 'main()' не нужно явно возвращать значение, потому что это исключение из обычных правил компиляции - его можно использовать по умолчанию. Но 'main()' должен иметь тип 'int', за исключением некоторых встроенных приложений, где он не возвращается. –

2

Это:

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

Вы выбрасывайте значение link параметра, который был принят в, вместо того, чтобы присвоить ей новое распределение через malloc. Думаю, это ваша самая важная проблема. Простое исправление - удалить строку, выполняющую malloc.

+0

Это действительно так, и создание узла связанного списка, который не является указателем, не имеет большого смысла. –

0

Вы хотите передать указателю указателю (или адресу указателя) на узел функции readData(). readData выделяет новый узел и заполняет его; то, что происходит в вашем коде, является то, что readData() получает копию адреса temp, перезаписывает копию этого адреса новым адресом, полученным из malloc (который невидим для вызывающего кода в main()) а затем заполняет этот объект malloc'ed. По возвращении из readData объект malloc'ed недоступен.

Что вы хотите сделать это:

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

, а затем использовать *tempAddr в основной вместо temp.

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

[...] 

relink пожаловаться, что вы не должны бросать результат malloc, но я думаю, что все в порядке. Я также не забочусь о возвращаемом значении main или его аргументах.

+0

«Вы хотите передать указатель на указатель (или адрес указателя) на узел функции readData()» - это одна из возможных интерпретаций; другой заключается в том, что подпись 'readData' правильная и что вызывающий должен выделить узел. – davmac

+0

@ davmac Ну, тот факт, что OP * * выделяет узел в 'readData', сильно поддерживает мою интерпретацию, я бы подумал ;-) –

+0

Я думаю, что тот факт, что OP проходит в уже выделенном узле, и что тип параметра 'struct Node *', одинаково сильны в поддержке альтернативной интерпретации. – davmac