2015-04-22 65 views
1

我有一个名为node s的结构数组。每个节点都包含一个void指针的字段。打印(Char *)(void *)在主程序中运行,但不起作用

在一个函数中,我使用特定的节点并将void指针指定给一个字符串,该字符串包含已转换为二进制的十进制结果。

问题是,访问和打印无效指针强制转换为char *可以在函数中将void *分配给新的char *,并且在返回主函数时打印正常。但是,当我尝试在一个单独的函数中打印它时,它不能正确打印,该函数将数组的节点[]和索引作为参数。

为了帮助阐明混乱,这是我的程序的简化版本:

#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年我知道有时候三分球GCC到微软C编译器可能有点不同。

我在写什么,使程序无法在printFunc函数中打印void *作为char *投射?

+3

'link-> dataItem.dataPtr =&string;' - 这是行不通的。首先,你不需要'&',因为本地数组会衰减为一个指针。其次,更重要的是,您将一个本地数组分配给一个指向其范围之外的指针。这是未定义的行为。 –

回答

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