打印 (Char*)(Void*) 在主程序中有效,但在函数中无效
Printing (Char*)(Void*) works in main program but not function
我有一个名为 node
s 的结构数组。每个节点都包含一个空指针字段。
在一个函数中,我获取特定节点并将 void 指针分配给一个字符串,该字符串包含已转换为二进制的十进制结果。
问题是访问和打印转换为 char* 的 void 指针在将 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] = '[=10=]'; }//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);
}
输出:
我也在 Visual Studios 2012 中编译。我知道有时 GCC 中指向 Microsoft C 编译器的指针可能会有些不同。
我在写什么导致程序无法在 printFunc
函数中将 void* 转换为 char* 打印出来?
您正在将 dataPtr
分配给在堆栈上声明的字符串:
link->dataItem.dataPtr = &string;
一旦超出范围,就会出现未定义的行为。您需要为堆上的字符串分配内存。
char *string = malloc(220);
...
//then assign it directly
link->dataItem.dataPtr = string;
您还需要一个函数来在您使用完数据后释放所有数据。
这就是您的代码中发生的情况:
当您调用 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
所在的堆栈 space!
[main variables] [printFunc variables] <-- HEAD
请注意,string
现在不见了!但是您的 Stack
变量仍然指向该内存,该内存现在包含垃圾!
如何解决?好吧,如果你打算从函数中 return 一些东西,你需要在调用方为它分配字符串:
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);
}
我有一个名为 node
s 的结构数组。每个节点都包含一个空指针字段。
在一个函数中,我获取特定节点并将 void 指针分配给一个字符串,该字符串包含已转换为二进制的十进制结果。
问题是访问和打印转换为 char* 的 void 指针在将 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] = '[=10=]'; }//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);
}
输出:
我也在 Visual Studios 2012 中编译。我知道有时 GCC 中指向 Microsoft C 编译器的指针可能会有些不同。
我在写什么导致程序无法在 printFunc
函数中将 void* 转换为 char* 打印出来?
您正在将 dataPtr
分配给在堆栈上声明的字符串:
link->dataItem.dataPtr = &string;
一旦超出范围,就会出现未定义的行为。您需要为堆上的字符串分配内存。
char *string = malloc(220);
...
//then assign it directly
link->dataItem.dataPtr = string;
您还需要一个函数来在您使用完数据后释放所有数据。
这就是您的代码中发生的情况:
当您调用 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
所在的堆栈 space!
[main variables] [printFunc variables] <-- HEAD
请注意,string
现在不见了!但是您的 Stack
变量仍然指向该内存,该内存现在包含垃圾!
如何解决?好吧,如果你打算从函数中 return 一些东西,你需要在调用方为它分配字符串:
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);
}