2015-04-22 4 views
1

У меня есть массив структур, называемый node s. Каждый узел содержит поле указателя пустоты.Печать (Char *) (Void *) работает в основной программе, но не работает

В функции я беру конкретный узел и назначаю указатель void на строку, содержащую результат десятичного числа, которое было преобразовано в двоичное.

Проблема заключается в том, что доступ и печать указателя void, переданного char *, отлично работает в функции, чтобы назначить void * новому символу * И печатает отлично при возврате к основной функции. Однако он не печатает правильно, когда я пытаюсь напечатать его в отдельной функции, которая принимает узел [] и индекс массива в качестве аргументов.

Чтобы осветить путанице это упрощенная версия моей программы:

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

#define listSize 100 

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

void loadData(node*); 
void printFunc(node[], int); 

void main() 
{ 
    struct Node Stack[listSize]; 

    loadData(&Stack[0]); 

    //This prints fine 
    char * temp; 
    temp = (char*)(Stack[0].dataItem.dataPtr); 
    printf("\nMain(): Stack[empty].dataItem.dataPtr = %s\n", temp); 


    printFunc(Stack, 0); 

} 

void loadData(node* link){ 
    char string[220]; 

    int n, c, k, i; 

    printf("Enter an integer: "); 
    scanf("%d", &n); 

    i = 0; 

    for (c = 31; c >= 0; c--) 
    { 
     k = n >> c; 

     if (k & 1){ 
      string[i] = '1'; 
      i++; 
     } 
     else{ 
      string[i] = '0'; 
      i++; 
     } 
     if (c == 0){ string[i] = '\0'; }//end the string 
    } 

    link->dataItem.dataPtr = &string; 

    //This prints fine: 
    printf("\nLoadData(): link->dataItem.dataPtr is now %s\n", (char *)(link->dataItem.dataPtr)); 
} 


void printFunc(node Stack[], int newLink){ 

    //This does not work! 
    char* temp; 
    temp = (char*)(Stack[newLink].dataItem.dataPtr); 
    printf("\npush(): Stack[newLink].dataItem.dataPtr %s\n", temp); 
} 

Выход: Output of program

Я также компиляции в визуальной студии 2012. Я знаю, что иногда указатели в НКУ к Компилятор Microsoft C может быть немного другим.

Что я пишу, что делает программу неспособной печатать пустоту * отличить как символ * в функции printFunc?

+3

'ссылка-> dataItem.dataPtr = & строки;' - это не работает. Во-первых, вам не нужно '&', потому что локальный массив распадается на указатель. Во-вторых, и что более важно, вы назначаете локальный массив указателю, который будет использоваться вне его области. Это неопределенное поведение. –

ответ

1

Это то, что происходит в вашем коде:

Как вы звоните в функции LoadData, он выделяет string[220] на стеке. Затем стек выглядит следующим образом:

[main variables] [LoadData variables, including string[220]] <-- HEAD 

Затем загрузить данные. Когда он выйдет, он вернет указатель стека назад. В это время ваш стек выглядит следующим образом:

[main variables] <-- HEAD [LoadData variables, including string[220]] 

Обратите внимание, что в вашем случае string все еще технически есть, его можно прочитать и получить доступ, но это чисто случайно и зависит от реализации компилятором. Некоторый другой компилятор мог бы немедленно удалить его или оптимизировать его каким-то другим способом. Как только функция выйдет, не должно быть указателей, указывающих на переменные, выделенные в стеке! Ваш код нарушает это, пропуская указатель на выделенный стек string. В это время ваш код уже находится в опасной зоне! Когда вы получите доступ к этому указателю, ваш код может упасть, ваш компьютер может загореться, или мир может перестать существовать.

Но в вашем конкретном случае string оказывается доступным, так как вы печатаете его с main, он, кажется, печатается правильно. Это дает иллюзию, что все в порядке. Иллюзия исчезает, когда вы звоните в printFunc, потому что теперь она будет занимать пространство стека, где находилось string!

[main variables] [printFunc variables] <-- HEAD 

Обратите внимание, что string теперь ушел! Но ваша переменная Stack по-прежнему указывает на эту память, которая теперь содержит мусор!

Как обращаться? Ну, если вы планируете что-то вернуть из функции, вам необходимо либо выделить строку для этого на вызывающей стороне:

int main { 
    ... 
    char string[220]; 
    LoadData(&Stack[0], string); // and make LoadData use the argument string instead of creating its own 
    ... 
} 

или сделать LoadData выделить строку в куче:

char* LoadData (...) { 
    char* string = malloc(220); 
    ... 
} 

В этот случай не забудьте освободить его в main позже:

int main() { 
    loadData(&Stack[0]); 
    ... 
    free(Stack[0].dataItem.dataPtr); 
} 
1

Вы назначая dataPtr в строку, которая объявлена ​​в стеке на этой линии:

link->dataItem.dataPtr = &string; 

После того, как вы вышли из сферы у вас есть неопределенное поведение. Вам нужно выделить память для строки в куче.

char *string = malloc(220); 

... 

//then assign it directly 
link->dataItem.dataPtr = string; 

Вам также понадобится функция для освобождения всех ваших данных, когда вы закончите с этим.

+0

... и 'strcpy()', или просто используйте что-то вроде ['strdup()'] (http://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html), если они дружественные. – WhozCraig