You are not logged in.

#1 2011-01-25 17:08:37

xelados
Member
Registered: 2007-06-02
Posts: 314
Website

Trying to learn pointers and structs, getting stuck (C)

Hello. I've been reading along in the K&R (2nd ed, ofc!) and my aim is to make a simple blackjack clone as my first game. It's supposed to run in the terminal and have simple keystrokes for actions. I'm stuck on building the initial deck and a debug function to test and ensure the deck is built properly. What I have so far is in the following paste:

http://sprunge.us/JUMS?c

Understand that I'm sort of flailing about in my understanding of pointers and how they interact with structs. As far as I can tell, there are two ways to do this; with pointers and with array subscription. I'd prefer the latter if possible since it would be easier to understand, but I'd like to learn both. The problem I'm getting is that my deck isn't being built properly, which makes the test_deck() function return a few bogus cards and then a bunch of zeros (if it doesn't segfault!)

Any help would be great.

Offline

#2 2011-01-25 17:56:35

Google
Member
From: Mountain View, California
Registered: 2010-05-31
Posts: 484
Website

Re: Trying to learn pointers and structs, getting stuck (C)

You didn't malloc the space for the struct pointer?

Offline

#3 2011-01-25 18:08:06

Barrucadu
Member
From: York, England
Registered: 2008-03-30
Posts: 1,158
Website

Re: Trying to learn pointers and structs, getting stuck (C)

    struct card nd;
    struct card *pnd;
    int suits;

    pnd = &nd;

[...]

            pnd++;
            nd = *pnd;

Not good. "nd" is *one* instance of the struct, and "pnd" points to that. Incrementing "pnd" points it to a memory location after the end of the 'array' (which is only one element long). This is why it's segfaulting.

Here are two ways to do it, one using pointers and one using array indices (pointers in disguise). Both return a pointer to the deck (as it's an array), so the rest of your code will need to be slightly modified:

struct card* create_deck (void)
{
        struct card* nd = (struct card*) malloc (sizeof (struct card) * 52);
        struct card *pnd;
        int suits;

        pnd = nd;

        for (suits = 1; suits <= 4; suits++) {
                int n;

                for (n = 1; n <= 13; n++) {
                        switch(suits) {
                                case 1:
                                        pnd->suit = 'h';
                                        break;
                                case 2:
                                        pnd->suit = 'd';
                                        break;
                                case 3:
                                        pnd->suit = 'c';
                                        break;
                                case 4:
                                        pnd->suit = 's';
                                        break;
                        }
                        pnd->value = n;
                        pnd++;
                }
        }

        return nd;
}
struct card* create_deck (void)
{
        struct card *nd = (struct card*) malloc (sizeof (struct card) * 52);
        int suits, n, i;

        i = 0;
        for (suits = 1; suits <= 4; suits++) {
                for (n = 1; n <= 13; n++) {
                        switch(suits) {
                                case 1:
                                        nd[i].suit = 'h';
                                        break;
                                case 2:
                                        nd[i].suit = 'd';
                                        break;
                                case 3:
                                        nd[i].suit = 'c';
                                        break;
                                case 4:
                                        nd[i].suit = 's';
                                        break;
                        }
                        nd[i].value = n;
                        i++;
                }
        }

        return nd;
}

edit: Of course, you will also need to free the returned value at some point.

Last edited by Barrucadu (2011-01-25 18:11:17)

Offline

#4 2011-01-25 18:09:06

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 20,324

Re: Trying to learn pointers and structs, getting stuck (C)

I trust this is not a homework assignment...

struct card create_deck (void)
 {
      struct card nd;
      struct card *pnd;
    ....
          return nd;

Right after the return nd, nd goes out od scope (it lives on the stack for the duration of create_deck)
When the stack unwinds, nd goes poof!

As Google points out, you need to create storage on the heap, make it static at the application level, or create a reference in main that will be valid during the call to create_deck and test_deck, and pass that reference in to the functions.

If you create it on the heap, make sure you include logic to delete it (Not really important in this case, but good form none-the-less

Edit:  Never mind, upon further consideration, I realize you can return a struct (by value).  I don't.   What you are returning is a single card, not the deck.  You created 51 cards for which you don't have storage, so you walked all over something (it was a block of data that had been at the end of the stack)  When you returned, you returned a copy of the first card.  The others (in unallocated space) vanished.  In your inline example, it worked because the cards did not vanish -- they were just written over perfectly innocent data that were in the way of the 51 unallocated cards.  Your pointer could, however, still find them.  Anything that tried to update the data that was supposed to have been at those addresses overwrites the rouge card data

Last edited by ewaller (2011-01-25 18:58:59)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#5 2011-01-25 19:06:01

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 20,324

Re: Trying to learn pointers and structs, getting stuck (C)

Can I recommend a book that cleared it up for me?  Try "The C Puzzle Book"  (Alan Feuer)
It is a short book of c puzzles.  The object of each exercise in the book is to figure out what a program will print.  Check out the puzzle: "Pointer Stew"


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#6 2011-01-25 19:14:02

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 20,324

Re: Trying to learn pointers and structs, getting stuck (C)

Oh, another thing....

     for (suits = 1; suits <= 4; suits++) {
         int n;
  
          for (n = 1; n <= 13; n++) {

Consider using a zero based count instead:

     for (suits = 0; suits < 4; suits++) {
         int n;
  
          for (n = 0; n < 13; n++) {

It makes it much easier to use indexes.  *foo == foo[0]   (foo does not point to foo[1])


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#7 2011-01-28 03:42:09

xelados
Member
Registered: 2007-06-02
Posts: 314
Website

Re: Trying to learn pointers and structs, getting stuck (C)

Wow, thanks for all the feedback and advice. You're correct in assuming this is not homework! I'm trying to learn C and game development at the same time and I felt this would be a good challenge and exercise.

One thing that isn't quite clear to me yet is what the difference in symbol placement is, e.g.

struct foo* bar;

and

struct foo *bar;

If I understand correctly, the latter is creating a pointer that can be used to point to a foo. What is the former doing?

@ewaller: I need to start my second loop at 1 so my card values are correct. I need 1-13, with 11-13 being face cards and 1 being the ace. Of course, I could simply add 1 to each of them later, but why add more work? The value won't be used in any indices.

malloc() is a function to allocate memory for something, where sizeof() will return the size (in memory, I'm guessing bits or bytes) of whatever its argument is, right?. Are these in the stdlib or a part of C? I want to make sure I'm learning properly, and plan on rereading the chapter on pointers in the near future.

Thank you guys again for being patient and helpful.

Offline

#8 2011-01-28 03:56:46

Allan
Pacman
From: Brisbane, AU
Registered: 2007-06-09
Posts: 11,488
Website

Re: Trying to learn pointers and structs, getting stuck (C)

xelados wrote:

One thing that isn't quite clear to me yet is what the difference in symbol placement is, e.g.

struct foo* bar;

and

struct foo *bar;

There is no difference.

Some people prefer the first syntax (reading it a "struct foo pointer" called bar) while others like the second (as the * is associated with the bar telling you that bar is a pointer).

Offline

#9 2011-01-28 04:45:46

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 20,324

Re: Trying to learn pointers and structs, getting stuck (C)

xelados wrote:

@ewaller: I need to start my second loop at 1 so my card values are correct. I need 1-13, with 11-13 being face cards and 1 being the ace. Of course, I could simply add 1 to each of them later, but why add more work? The value won't be used in any indices.

Okay.  But when you allocate the memory, make sure you allocate enough memory for that last card. 
int a[10]  allocates room for 10 integers with indexes from 0 to 9.  Use 10, and you have a buffer overrun.  This has the drawback of leaving unused (and probably uninitialized storage).  Also, it may be more work to calculate <= versus <.  Probably not an issue on x86, but true on some microcontrollers.

malloc() is a function to allocate memory for something, where sizeof() will return the size (in memory, I'm guessing bits or bytes) of whatever its argument is, right?. Are these in the stdlib or a part of C?

on Linux, malloc is part of glibc.  Check out the man page for malloc.  It also describes calloc  and realloc. (and, of course free).  malloc allocates a certain number of bytes, calloc allocates a number of elements of a given size -- and zeros them.  realloc resizes and potentially moves a block.  free releases a block. 

They are not built in to the 'C' language, but they are ubiquitous.  There are better solutions than malloc that are available in other libraries on a variety of platforms, but they are not guaranteed to be available cross platform. C++ uses the new and delete operators as part of the language.  I spend a lot of time with C++.  Now days, when I write in C, I tend to get lazy and use a C++ compiler to compile C-like code so I can use new, delete, namespaces and inline declarations.  Don't start down that path yet.

Last edited by ewaller (2011-01-28 04:46:48)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#10 2011-01-28 05:51:38

xelados
Member
Registered: 2007-06-02
Posts: 314
Website

Re: Trying to learn pointers and structs, getting stuck (C)

Thanks for the clarification, ewaller. I had a thought, though: eventually, I will be using a pseudo random number to deal cards out. When I deal a card, I need to use some means of considering it "dealt". I could free() each card as it's dealt, zero its value, use a "stack" to keep track of which cards have been dealt, or add a "field to the struct that's a boolean. I'm thinking the latter is the best idea since I can use the same index, reference the same data, and keep things simple.

Barrucadu's code worked great, with some modification to a few lines in main(). I feel as if I haven't grasped pointers very well yet, so I'm gonna take a break from the game to figure these babies out. I'm sure that I'll need to know how they work if I plan on developing any _real_ games. Which mechanics of pointers are the most important to grasp from the outset?

Offline

#11 2011-01-28 06:54:39

ewaller
Administrator
From: Pasadena, CA
Registered: 2009-07-13
Posts: 20,324

Re: Trying to learn pointers and structs, getting stuck (C)

As you learn, I would set flag if the card has been dealt.  You have touched on another of the niceties of C++, Python, C# and others -- classes that take care of collections and organize them as stacks, lists, dictionaries, etc...

What you touched on, however, is the right way to handle this and is an excellent lesson in C and pointers -- linked lists.  Consider a card structure in which one of the elements is a pointer to another card.  What you would do would be to call malloc 1 time for each card you create.  Fill in the structure with the card info and a pointer to the previous card you had created.  When you create the first card, you would just set that field to null.  After you have created all the cards, you still have the reference to the most recently created card.   To find the nth card, you iterate through the pointer starting with the first card to find the second, the pointer in the second card to find the third, etc.  If you find a null pointer, you have reached the end of the stack.  Then you can deal a card by changing the pointer from the card preceding it to point to the card following it, followed by calling free on the pointer to the card you want to deal.  Of course, you have to deal with the boundary conditions (how do you deal the first card, or the last card of the deck, how do you deal the 52 card, and what do you do if something goes horribly wrong and you find a null pointer when you are not expecting it) 

As to figuring out pointers, I still recommend The C Puzzle Book

Last edited by ewaller (2011-01-28 06:55:42)


Nothing is too wonderful to be true, if it be consistent with the laws of nature -- Michael Faraday
Sometimes it is the people no one can imagine anything of who do the things no one can imagine. -- Alan Turing
---
How to Ask Questions the Smart Way

Offline

#12 2011-01-28 10:58:00

Damnshock
Member
From: Barcelona
Registered: 2006-09-13
Posts: 414

Re: Trying to learn pointers and structs, getting stuck (C)

Allan wrote:
xelados wrote:

One thing that isn't quite clear to me yet is what the difference in symbol placement is, e.g.

struct foo* bar;

and

struct foo *bar;

There is no difference.

Some people prefer the first syntax (reading it a "struct foo pointer" called bar) while others like the second (as the * is associated with the bar telling you that bar is a pointer).

I usually dislike the first form because if you were to write something like:

struct foo* bar bar2;

Bar2 *won't* be a pointer thus the reason you wanted to write it that way is lost...

Regards


My blog: blog.marcdeop.com
Jabber ID: damnshock@jabber.org

Offline

#13 2011-03-13 04:11:03

sigmund
Member
From: Milano, Italy, EU
Registered: 2009-12-06
Posts: 50

Re: Trying to learn pointers and structs, getting stuck (C)

Thinking that this might be of interest: http://pw1.netcom.com/~tjensen/ptr/pointers.htm


Definitely moving to GNU/Linux made me trust Computer Science once again.
Definitely moving to Arch made me enjoy and understand GNU/Linux once again.

Offline

#14 2011-03-13 18:05:03

BaconPie
Member
Registered: 2010-08-11
Posts: 209

Re: Trying to learn pointers and structs, getting stuck (C)

Damnshock wrote:

I usually dislike the first form because if you were to write something like:

struct foo* bar bar2;

Bar2 *won't* be a pointer thus the reason you wanted to write it that way is lost...

Regards

I think you shouldn't be declaring variables of two different types on the same line anyway. That is the problem, just because C lets you do it, doesn't mean you should.

char * foo

and

char bar

are of completely separate types; they just both happen to have char in the name. Personally I write it with a space on both sides, in the same way that I don't write structure's and their names stuck together.

structpoint origin => int* foo
struct pointorigin => int *foo
struct point origin => int * foo

Not only that but the habit of sticking the type onto the variable name confuses the operation with dereferencing. More confusion comes when sticking the return type of a function on the function name! Are you dereferencing the function? What?!

Maybe it's just be but I think this makes C's poor (old) syntax a whole lot clearer. I wonder what K&R would say about it in 2011? smile

(Nothing personal by the way, I just have a vendetta against unclear code... tongue)

Offline

#15 2011-03-31 11:07:09

akephalos
Member
From: Romania
Registered: 2009-04-22
Posts: 114

Re: Trying to learn pointers and structs, getting stuck (C)

Damnshock wrote:

I usually dislike the first form because if you were to write something like:

struct foo* bar bar2;

Bar2 *won't* be a pointer thus the reason you wanted to write it that way is lost...

Regards

Yeah, that's why a lot of people recommend grouping the asterix with the variable name, instead of the type (Torvals, IIRC). I consider it a design flaw in C/C++, in D it is corrected, int* is an actual type (int[] for an array).

http://www.digitalmars.com/d/2.0/dstyle.html :

int[] x, y;    // makes it clear that x and y are the same type
int** p, q;    // makes it clear that p and q are the same type
int []x, y;    // confusing since y is also an int[]
int **p, q;    // confusing since q is also an int**

Offline

#16 2011-10-04 04:18:45

xelados
Member
Registered: 2007-06-02
Posts: 314
Website

Re: Trying to learn pointers and structs, getting stuck (C)

I'm at it again. This time, I'm outputting decimal representations of the pointers for "prev" and "next" for each card so I know my structure's well made before I make game logic. I have 'prev' and the edge case (nd[0]) nailed down, but 'next' is off by 8 bytes. I'm not really sure what to do to make

nd[i].next

point to the right thing. Here's my code: http://sprunge.us/JSAM?c

For the record, BBcode is annoying sad

EDIT: I fixed it! Compared to the above, I reinserted the +1 to nd(i) on line 53 and removed the & from &stack(i).next in the printf() function on line 69. What the issue was (I think, correct me if I'm wrong) is &stack(i).next was returning the address of the pointer itself, NOT the address that it was pointing to (which is what I was after). Removing & made it do what I needed it to.

(I'm using (s instead of [s because the forum is weird)

So, line 53:

nd[i].next = &nd[i + 1];

and line 69:

printf("%02d: %02d of %c, dealt?: %d, ADD: %d, next is %d, previous is %d\n", i, stack[i].value, stack[i].suit, stack[i].dealt, &stack[i], stack[i].next, stack[i].prev);

Last edited by xelados (2011-10-04 04:28:42)

Offline

Board footer

Powered by FluxBB