打印(字符*)(空格*)在主程序中有效但不起作用

时间:2015-04-22 18:05:58

标签: c arrays pointers void-pointers

我有一组名为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);
}

输出: Output of program

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

我写的是什么让程序无法在printFunc函数中打印出* *作为char *?

2 个答案:

答案 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);
}