I'm having trouble with a binary tree algorithm. A test program I wrote calls for the top node to only be altered in another method outside main (A simple guessing/learning game scenario). I wrote a smaller test of that exercise here:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

struct binary {
        unsigned long ID;
    char *guess;
    char isAns;
    struct binary *yes;
    struct binary *no;
};
typedef struct binary Node;

Node * make_question_answer(char *ques,char *ans);
Node * make_question_answer2(char *ques,char *ans);
void make_question_answer3(Node **change, char *ques,char *ans);

Node * getnew(char *msg, char isAns)
{
    Node *nnew = malloc(sizeof(Node));
        nnew->ID=clock();
    nnew->guess=msg;
    nnew->isAns=isAns;
    nnew->yes=0;
    nnew->no=0;
    return nnew;
}
void dummy_method(Node **top)
{
        char ques[128] = "ok";
        char ans[128] = "ok";
        printf("Node is null\n");
        printf("Put in a question and answer to yes condition\n");
        printf("Enter question: ");
        while(!fgets(ques,128,stdin));
        printf("Enter answer for yes condition: ");
        while(!fgets(ans,128,stdin));
    printf("Check ques: %s\nCheck ans: %s\n\n",ques,ans);
    //(*top) = make_question_answer(ques,ans);
        //(*top) = getnew(ques,'n');
    make_question_answer3(top,ques,ans);
    fprintf(stdout,"\ncheck in method: top: %s\n\n",(*top)->guess);
        //(*top)->yes=getnew(ans,'y');
    fprintf(stdout,"\ncheck in method: top->yes: %s\n\n",(*top)->yes->guess);
}
Node * make_question_answer(char *ques,char *ans)
{
    Node *top = getnew(ques,'n');
    top->yes = getnew(ans,'y');
    return top;
}
Node * make_question_answer2(char *ques,char *ans)
{
    Node *top = getnew(ques,'n');
    Node *a = getnew(ans,'y');
    top->yes=a;
    return top;
}
void make_question_answer3(Node **change, char *ques,char *ans)
{
    Node *top = getnew(ques,'n');
    Node *a = getnew(ans,'y');
    top->yes=a;
    top->no=(*change);
    *change=top;
}
int main()
{
    Node *top=0;
    dummy_method(&top);
    /*char *ques = "sample question";
    char *ans = "smaple answer";
    top = make_question_answer(ques,ans);*/
    fprintf(stdout,"\ncheck: %s\n\n",top->yes->guess);
}

The issue at hand is seen in the output:

Node is null
Put in a question and answer to yes condition
Enter question: test question
Enter answer for yes condition: test answer
Check ques: test question

Check ans: test answer



check in method: top: test question



check in method: top->yes: test answer



check: ?1?p?

From what I can tell all of those methods work in main, but not in dummy_method, which is confusing. Why might this be?

I don't know what compiler you're using, but from running your code through visual studio, your program initially seems to be doing what it should. The functions called in dummy_method seem to be working. For me, the fprintf call at the end of main displays check:_test answer with some additional gibberish characters on the following line.

At first I thought the reason for the gibberish characters might have been due to strings that were not null terminated. But from looking at your code a little more carefully, I'm pretty certain that the problem is in the way you are dealing with the input strings and creating your new nodes.

In dummy_method, you have declared two local variables ques and ans to act as buffers to store the users input. Then in your call to make_question_answer3 you are passing in pointers to both of these variables. In turn, inside make_question_answer3; in your calls to getnew you are passing the pointers again (in two separate calls). Finally in both calls to getnew, the new nodes char* member variables (guess) are assigned the passed in pointers.

So effectively, you are creating two new nodes and the guess member variables of both are set to point to the addresses of ques and ans respectively. Now the thing to bear in mind is that the ques and ans variables being pointed to by the guess variables of both nodes are local to dummy_method. So after your call to make_question_answer3 returns and we are back in dummy_method, everything is OK, because ques and ans are both in scope.

However, as soon as dummy method returns and we are back in main; ques and ans have both dropped out of scope. So now the pointers in your nodes are technically pointing to invalid memory. Thus, you are not seeing what you are expecting to see in your call to fprintf at the end of main!

I think the best fix would probably be in your getnew function. Instead of simply assigning the guess variable the passed in pointer (msg), you should perhaps allocate some memory for guess to point to (based on the size of msg) and copy the content of msg to the memory pointed to by guess.
That way your nodes will point to valid memory and will contain the appropriate string.
Just don't forget to write some code to free/deallocate the memory when you are done with the nodes! :)

So based on what you said and I asked the question on stackoverflow:

char * expstrcpy2(char * a)
{
    char *b = malloc(sizeof(a));
    char *d = b;
    while(*b++ = *a++);
    return d;
}
Node * getnew(char *msg, char isAns)
{
    Node *nnew = malloc(sizeof(Node));
    nnew->ID=clock();
    //nnew->guess=msg;
    nnew->guess=expstrcpy2(msg);
    nnew->isAns=isAns;
    nnew->yes=0;
    nnew->no=0;
    return nnew;
}

The code still isn't right, but the string don't appear to be dropping out of scope. (although a pesky newline character is entered in the front. I always assumed a pointer, unless pointing to a normal variable, i.e int *ptr = &my_int was always on the heap and hence beyond the bounds of scope. I guess you have to use malloc or calloc to place variables on the heap? Everything else is on the stack and has scope? Can you clarify?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.