c - 打印 (Char*)(Void*) 在主程序中有效,但在函数中无效

标签 c arrays pointers void-pointers

我有一个名为节点的结构数组。每个节点都包含一个空指针字段。

在一个函数中,我获取特定节点并将 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] = '\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

我也在 Visual Studios 2012 中进行编译。我知道有时 GCC 中指向 Microsoft C 编译器的指针可能会有些不同。

我在写什么导致程序无法在 printFunc 函数中将 void* 转换为 char* 打印出来?

最佳答案

这是您的代码中发生的情况:

当您调用 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);
}

关于c - 打印 (Char*)(Void*) 在主程序中有效,但在函数中无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29805617/

相关文章:

java - 如何在 Java 中反转 int 数组?

java - 如何在Java中使用charAt查找数组中每个值的首字母?

c - 如何知道库是否存在或是否与 makefile 保持同步

c - 在用 C 创建的位图文件中叠加 2 个或更多形状?

php - 基于键将大型关联数组转换为局部变量

编译器不显示任何错误或警告,但程序不工作

在 C 中从 char * 转换为 char[31]

c++ - 在 C++ 中将 double* 转换为 int*

c - 高效网络服务器设计实例,C语言编写

c - 从命令行接受整数数组 - C 编程