我有一组名为node
的结构。每个节点都包含一个void指针的字段。
在一个函数中,我获取特定节点并将void指针分配给一个字符串,该字符串包含已转换为二进制的十进制结果。
问题是访问和打印转换为char *的void指针在函数中工作正常,以便将void *分配给新的char *并在返回main函数时打印正常。但是当我尝试在一个单独的函数中打印它时,它无法正确打印,该函数将节点[]和数组的索引作为参数。
为了解释混乱,这是我的程序的简化版本:
#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);
}
输出:
我也在2012年的Visual Studios中进行编译。我知道GCC中指向Microsoft C编译器的指针有时会有所不同。
我写的是什么让程序无法在printFunc
函数中打印出* *作为char *?
答案 0 :(得分:1)
您正在将dataPtr
分配给此行上堆栈上声明的字符串:
link->dataItem.dataPtr = &string;
一旦超出范围,您就会有未定义的行为。您需要为堆上的字符串分配内存。
char *string = malloc(220);
...
//then assign it directly
link->dataItem.dataPtr = string;
完成后,您还需要一个功能来释放所有数据。
答案 1 :(得分: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);
}