Like Tree5Likes

I actually tried to do something…

This is a discussion on I actually tried to do something… within the C Programming forums, part of the General Programming Boards category; Hi! I studied C in the 1980's and never touched it, at least not much, since then. Now I want ...

  1. #1
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    59

    I actually tried to do something…

    Hi!

    I studied C in the 1980's and never touched it, at least not much, since then. Now I want to catch up and I have been on this forum for a while now, reading other people's posts, replying and I've also asked a few questions myself. So far I only do small meaningless things, just to learn. Nothing serious.

    So I read some tutorials here and I got interested in binary trees. I studied the functions provided in the tutorial and I also did some searching for other examples.

    I decided to play a little with this myself, so I stole some functions from the tutorial at this site, and I got some inspiration also from other examples out there, putting it all together ”my way” (which isn't necessarily something good, I guess). Some of the tutorial functions didn't compile, so I made a few changes there. Now I don't get any errors, but there are a few warnings that I don't fully understand.

    The code is not finished, so there are some things that I wrote that I don't even use yet, just pretend they are not there at the moment…

    For now, I only do three things: I add random values to the binary tree, then print them out ”sorted” and finally I get rid of the tree. More features will be added, of course, until I feel that I know what I'm doing.

    I separated the code into four files, and here they are.

    bt-functions.c:
    Code:
    #include "bt-functions.h"
    
    void Insert(struct node** Leaf, int Value) {
        if(*Leaf==0) {
            *Leaf=(struct node*)malloc(sizeof(struct node));
            (*Leaf)->Points=Value;
    
            /* Initialize the children to null */
            (*Leaf)->Lower=0;
            (*Leaf)->Higher=0;
        }
        else if(Value<=(*Leaf)->Points)
            Insert(&(*Leaf)->Lower, Value);
        else if(Value>(*Leaf)->Points)
            Insert(&(*Leaf)->Higher, Value);
    }
    
    
    struct node* Search(struct node* Leaf, int Value) {
        if(Leaf!=0) {
            if(Value==Leaf->Points)
                return Leaf;
            else if(Value<Leaf->Points)
                return Search(Leaf->Lower, Value);
        else
            return Search(Leaf->Higher, Value);
        }
        else return 0;
    }
    
    
    void PrintList(struct node* Leaf) {
        if(Leaf!=0) {
            PrintList(Leaf->Lower);
    /*      printf("%30s %20s %8d\n", Leaf->Lname, Leaf->Fname, Leaf->Points); */
            printf("%8d\n", Leaf->Points);
            PrintList(Leaf->Higher);
        }
    }
    
    
    /* To do later! Will probably be somewhat tricky… */
    void Delete(struct node** Leaf) {
    }
    
    
    void DestroyTree(struct node* Leaf) {
        if(Leaf!=0) {
            DestroyTree(Leaf->Lower);
            DestroyTree(Leaf->Higher);
            free(Leaf);
        }
    }
    bt-functions.h:
    Code:
    #include "bt.h"
    
    /* Function prototypes */
    void            Insert        (struct node**, int);
    struct node*    Search        (struct node*,  int);
    void            PrintList     (struct node*);
    void            Delete        (struct node**);
    void            DestroyTree   (struct node*);
    bt.c:
    Code:
    #include <time.h>
    #include "bt.h"
    
    void InitRand(void);
    int  Rand1000(void);
    
    int main(void)
    {
        struct node *Temp=NULL;
        struct node *Root=NULL;
    
        InitRand();
        for(int i=0; i<75; i++)    
            Insert(&Root, Rand1000());
    
        PrintList(Root);
    
        DestroyTree();
        return 0;
    }
    
    
    /* Functions only needed at this early stage */
    void InitRand(void) {
        srand(time(0));
    }
    
    
    int Rand1000(void) {
        return rand()%1000;
    }
    bt.h:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    /* Structures */
    struct node
    {
    /*  char Fname[20];
        char Lname[30];*/
        int Points;
        struct node *Lower;
        struct node *Higher;
    };
    I compiled those with the following command:
    Code:
    gcc -std=c99 -o btree bt-functions.c bt.c
    I get these errors (the program works, though):
    Code:
    bt.c: In function "main":
    bt.c:14:3: warning: implicit declaration of function "Insert" [-Wimplicit-function-declaration]
    bt.c:16:2: warning: implicit declaration of function "PrintList" [-Wimplicit-function-declaration]
    bt.c:18:2: warning: implicit declaration of function "DestroyTree" [-Wimplicit-function-declaration]
    $
    I don't get these messages when omitting -std=c99, but I need c99 or gnu99 for the for loop, since I prefer declaring the loop variable (i) inside the for statement…
    However, I'm not sure what these messages really means. What am I expected to do? English is not my native language, which could be a reason for not understanding this completely, I don't know.

    I also wonder about my #include lines. Is it generally okay to do it this way, or should I keep those common lines (like stdio and stdlib) in the C files rather than in the H files?

    I know there is not much error handling in this example, I will probably add some later, when I feel ready for it, just for practising, especially when I will let the user input the values rather than using random numbers.

    If there are other important things that I need to know, related to the code above, please tell me.


    Thanks!


    Johnny Rosenberg
    Last edited by guraknugen; 08-13-2013 at 12:34 PM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,976
    You should #include "bt-functions.h" in bt.c. By the way, your headers should have inclusion guards.
    stahta01 likes this.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    59
    Wow… that was really fast… Did you just sit there waiting for someone to write…?
    Inclusion guards, then I suppose you are referring to those things like ”#ifndef” and so on?

    Yes, I see now that I forgot to include bt-functions-h, I thought that it was included in bt.h, but it was the other way around (bt.h included in bt-functions.h). So this is kind of a mess that should be avoided, right?

    I'll rewrite it slightly and come back later…

    Thanks for the quick reply!


    Johnny Rosenberg

  4. #4
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    59
    I tried a different approach now, concerning those include statements. Here's what I have now.

    bt-functions.c:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include "bt-functions.h"
    #include "bt.h"
    
    void Insert(struct node** Leaf, int Value) {
        if(*Leaf==0) {
            *Leaf=(struct node*)malloc(sizeof(struct node));
            (*Leaf)->Points=Value;
    
            /* Initialize the children to null */
            (*Leaf)->Lower=0;
            (*Leaf)->Higher=0;
        }
        else if(Value<=(*Leaf)->Points)
            Insert(&(*Leaf)->Lower, Value);
        else if(Value>(*Leaf)->Points)
            Insert(&(*Leaf)->Higher, Value);
    }
    
    
    struct node* Search(struct node* Leaf, int Value) {
        if(Leaf!=0) {
            if(Value==Leaf->Points)
                return Leaf;
            else if(Value<Leaf->Points)
                return Search(Leaf->Lower, Value);
        else
            return Search(Leaf->Higher, Value);
        }
        else return 0;
    }
    
    
    void PrintList(struct node* Leaf) {
        if(Leaf!=0) {
            PrintList(Leaf->Lower);
    /*      printf("%30s %20s %8d\n", Leaf->Lname, Leaf->Fname, Leaf->Points); */
            printf("%8d\n", Leaf->Points);
            PrintList(Leaf->Higher);
        }
    }
    
    
    /* To do later! Will probably be somewhat tricky… */
    void Delete(struct node** Leaf) {
    }
    
    
    void DestroyTree(struct node* Leaf) {
        if(Leaf!=0) {
            DestroyTree(Leaf->Lower);
            DestroyTree(Leaf->Higher);
            free(Leaf);
        }
    }
    bt-functions.h:
    Code:
    #ifndef BT_FUNCTIONS_H
    #define BT_FUNCTIONS_H
    
    #include "bt.h"
    
    /* Function prototypes */
    void            Insert        (struct node**, int);
    struct node*    Search        (struct node*,  int);
    void            PrintList     (struct node*);
    void            Delete        (struct node**);
    void            DestroyTree   (struct node*);
    
    #endif
    bt.c:
    Code:
    #include <stdlib.h>
    #include <time.h>
    #include "bt.h"
    #include "bt-functions.h"
    
    void InitRand(void);
    int  Rand1000(void);
    void FillTree(struct node**);
    
    int main(void)
    {
        struct node *Root=NULL;
    
        FillTree(&Root);
        PrintList(Root);
        DestroyTree(Root);
    
        return 0;
    }
    
    
    /* Functions only needed at this early stage */
    void InitRand(void) {
        srand(time(0));
    }
    
    
    int Rand1000(void) {
        return rand()%1000;
    }
    
    
    void FillTree(struct node** Leaf) {
        InitRand();
        for(int i=0; i<75; i++)    
            Insert(Leaf, Rand1000());
    }
    bt.h:
    Code:
    #ifndef BT_H
    #define BT_H
    
    /* Structures */
    struct node {
    /*  char Fname[20];
        char Lname[30];*/
        int Points;
        struct node *Lower;
        struct node *Higher;
    };
    
    #endif
    There are no compiling errors now, using the same command as before:
    Code:
    gcc -std=c99 -o btree bt-functions.c bt.c
    or
    Code:
    gcc -std=gnu99 -o btree bt-functions.c bt.c
    Now I also found that I forgot the argument in main() for the DestructTree() function, so I guess it didn't destruct anything in my previous version…

    It doesn't seem like I need stdio.h in bt.c (it's needed and included in bt-functions.c, though). Should I include it anyway for some reason or should I just wait until I am actually using it there in a future version?


    Johnny Rosenberg
    Last edited by guraknugen; 08-13-2013 at 01:41 PM. Reason: Found a variable that's not used (*Temp in main()). And I wrote a function for filling the tree (FillTree()).

  5. #5
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    59
    By the way, I also see now that I set a pointer (Root) to NULL in main(), but in the code that I originally stole from the tutorial, they set pointers to 0 instead. I guess consistency is recommended, but otherwise, NULL or 0, what is recommended and why?

    I did some searching about this and people don't seem to agree with each other… but most of what I found was about C++, not C.
    Last edited by guraknugen; 08-13-2013 at 02:50 PM.

  6. #6
    Registered User
    Join Date
    May 2009
    Posts
    2,372
    Quote Originally Posted by guraknugen View Post
    By the way, I also see now that I set a pointer (Root) to NULL in main(), but in the code that I originally stole from the tutorial, they set pointers to 0 instead. I guess consistency is recommended, but otherwise, NULL or 0, what is recommended and why?

    I did some searching about this and people don't seem to agree with each other… but most of what I found was about C++, not C.
    C programmers tend to use NULL, C++ Programmers tend to use 0.

    If using newer version of C++, the C++ Programmers tend to use nullptr.

    Tim S.
    "Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the Universe is winning." Rick Cook

  7. #7
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by laserlight View Post
    You should #include "bt-functions.h" in bt.c. By the way, your headers should have inclusion guards.
    Inclusion guards?

  8. #8
    CSharpener vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,424
    Quote Originally Posted by SirPrattlepod View Post
    Inclusion guards?
    Let me google that for you
    The first 90% of a project takes 90% of the time,
    the last 10% takes the other 90% of the time.

  9. #9
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by vart View Post
    Not sure if they'd fix the problem, though.

  10. #10
    CSharpener vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,424
    Quote Originally Posted by SirPrattlepod View Post
    Not sure if they'd fix the problem, though.
    I do not know about THE problem. But there is a list of problems that include guards prevent from happening. That's why its usage is recommended/required.

    Here on the forum when we look at the code we not only provide suggestions to solve immediate problems, but also give some advice related to improving basic programming style based on the code demonstrated.
    SirPrattlepod and Salem like this.
    The first 90% of a project takes 90% of the time,
    the last 10% takes the other 90% of the time.

  11. #11
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by vart View Post
    Here on the forum when we look at the code we not only provide suggestions to solve immediate problems, but also give some advice related to improving basic programming style based on the code demonstrated.
    I understand now. That seems like a good thing to do... my apologies.

  12. #12
    CSharpener vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,424
    Quote Originally Posted by SirPrattlepod View Post
    my apologies.
    I do not see anything you did that needs apologies. But you're welcome.
    The first 90% of a project takes 90% of the time,
    the last 10% takes the other 90% of the time.

  13. #13
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    If you don't nest includes, you won't need guards.

  14. #14
    Registered User
    Join Date
    Feb 2013
    Location
    Sweden
    Posts
    59
    First of all, thanks for all replies.
    Quote Originally Posted by Barney McGrew View Post
    If you don't nest includes, you won't need guards.
    I know. Before adding them I could get it work without them, but I can see at least one advantage using them. Without them it's easier to get lost in the code, especially for a beginner (or a not very experienced ”programmer” like me). Easy to forget something or to realise when you need what. With an include guard I can just think something like ”in this file I need this and that and nothing more” and I don't need to investigate everything again and again… So if I just include what's needed for every particular file, I will be fine. The include guards, if used properly, prevents double inclusions. Well, that's my theory at least.

    Of course I will add functionality to this simple code, to practise my skills further. Maybe that will mean a new file or two. Then the include thing will perhaps be somewhat more complicated, and then I will probably need the include guards more than I do now. I actually never used them before, but I guess I will start doing that now.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,976
    You should have header inclusion guards whether or not you "nest includes", otherwise a reader of your code may wonder if the omission was a mistake, and even if it was not a mistake at the time of writing, it might eventually lead to a mistake as it is not unusual for header files to be included more than once in the same translation unit, indirectly.

    Besides, a policy of avoiding the nested inclusion of header files so as to avoid having to use inclusion guards is not a good idea. Consider: suppose your program has two headers, each of which depends on the definition of the same struct. To avoid nesting the inclusion of header files, this means that you will define the struct in two places, which is bad as you must keep them in sync. Furthermore, if a source file depends on both headers, then you will be defining the struct twice in the same translation unit, which is an error. You can avoid this by combining the header files into one, but it might not be desirable to do so for code organisation purposes.

    Quote Originally Posted by guraknugen
    So if I just include what's needed for every particular file, I will be fine.
    But it is also something of a bad habit since you're not thinking about your code.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21