Question

I'm sort of learning C, I'm not a beginner to programming though, I "know" Java and python, and by the way I'm on a mac (leopard). Firstly,

1: could someone explain when to use a pointer and when not to?

2:

char *fun = malloc(sizeof(char) * 4);

or

char fun[4];

or

char *fun = "fun";

And then all but the last would set indexes 0, 1, 2 and 3 to 'f', 'u', 'n' and '\0' respectively. My question is, why isn't the second one a pointer? Why char fun[4] and not char *fun[4]? And how come it seems that a pointer to a struct or an int is always an array?

3: I understand this:

typedef struct car
{
    ...
};

is a shortcut for

struct car
{
    ...
};
typedef struct car car;

Correct? But something I am really confused about:

typedef struct A
{
    ...
}B;

What is the difference between A and B? A is the 'tag-name', but what's that? When do I use which? Same thing for enums.

4. I understand what pointers do, but I don't understand what the point of them is (no pun intended). And when does something get allocated on the stack vs. the heap? How do I know where it gets allocated? Do pointers have something to do with it?

5. And lastly, know any good tutorial for C game programming (simple) ? And for mac/OS X, not windows?

PS. Is there any other name people use to refer to just C, not C++? I hate how they're all named almost the same thing, so hard to try to google specifically C and not just get C++ and C# stuff.

Thanks!!

It was hard to pick a best answer, they were all great, but the one I picked was the only one that made me understand my 3rd question, which was the only one I was originally going to ask. Thanks again!

Was it helpful?

Solution

My question is, why isn't the second one a pointer?

Because it declares an array. In the two other cases, you have a pointer that refers to data that lives somewhere else. Your array declaration, however, declares an array of data that lives where it's declared. If you declared it within a function, then data will die when you return from that function. Finally char *fun[4] would be an array of 4 pointers - it wouldn't be a char pointer. In case you just want to point to a block of 4 chars, then char* would fully suffice, no need to tell it that there are exactly 4 chars to be pointed to.

The first way which creates an object on the heap is used if you need data to live from thereon until the matching free call. The data will survive a return from a function.

The last way just creates data that's not intended to be written to. It's a pointer which refers to a string literal - it's often stored in read-only memory. If you write to it, then the behavior is undefined.

I understand what pointers do, but I don't understand what the point of them is (no pun intended).

Pointers are used to point to something (no pun, of course). Look at it like this: If you have a row of items on the table, and your friend says "pick the second item", then the item won't magically walk its way to you. You have to grab it. Your hand acts like a pointer, and when you move your hand back to you, you dereference that pointer and get the item. The row of items can be seen as an array of items:

And how come it seems that a pointer to a struct or an int is always an array?

item row[5];

When you do item i = row[1]; then you first point your hand at the first item (get a pointer to the first one), and then you advance till you are at the second item. Then you take your hand with the item back to you :) So, the row[1] syntax is not something special to arrays, but rather special to pointers - it's equivalent to *(row + 1), and a temporary pointer is made up when you use an array like that.

What is the difference between A and B? A is the 'tag-name', but what's that? When do I use which? Same thing for enums.

typedef struct car
{
    ...
};

That's not valid code. You basically said "define the type struct car { ... } to be referable by the following ordinary identifier" but you missed to tell it the identifier. The two following snippets are equivalent instead, as far as i can see

1)

struct car
{
    ...
};
typedef struct car car;

2)

typedef struct car
{
    ...
} car;

What is the difference between A and B? A is the 'tag-name', but what's that? When do I use which? Same thing for enums.

In our case, the identifier car was declared two times in the same scope. But the declarations won't conflict because each of the identifiers are in a different namespace. The two namespaces involved are the ordinary namespace and the tag namespace. A tag identifier needs to be used after a struct, union or enum keyword, while an ordinary identifier doesn't need anything around it. You may have heard of the POSIX function stat, whose interface looks like the following

struct stat {
  ...
};

int stat(const char *path, struct stat *buf);

In that code snippet, stat is registered into the two aforementioned namespaces too. struct stat will refer to the struct, and merely stat will refer to the function. Some people don't like to precede identifiers always with struct, union or enum. Those use typedef to introduce an ordinary identifier that will refer to the struct too. The identifier can of course be the same (both times car), or they can differ (one time A the other time B). It doesn't matter.

OTHER TIPS

3) It's bad style to use two different names A and B:

typedef struct A
{
    ...
} B;

With that definition, you can say

struct A a;
B b;
b.field = 42;
a.field = b.field;

because the variables a and b have the same type. C programmers usually say

typedef struct A
{
  ...
} A;

so that you can use "A" as a type name, equivalent to "struct A" but it saves you a lot of typing.

  1. Use them when you need to. Read some more examples and tutorials until you understand what pointers are, and this ought to be a lot clearer :)
  2. The second case creates an array in memory, with space for four bytes. When you use that array's name, you magically get back a pointer to the first (index 0) element. And then the [] operator then actually works on a pointer, not an array - x[y] is equivalent to *(x + y). And yes, this means x[y] is the same as y[x]. Sorry.
    Note also that when you add an integer to a pointer, it's multiplied by the size of the pointed-to elements, so if you do someIntArray[1], you get the second (index 1) element, not somewhere inbetween starting at the first byte.
    Also, as a final gotcha - array types in function argument lists - eg, void foo(int bar[4]) - secretly get turned into pointer types - that is, void foo(int *bar). This is only the case in function arguments.
  3. Your third example declares a struct type with two names - struct A and B. In pure C, the struct is mandatory for A - in C++, you can just refer to it as either A or B. Apart from the name change, the two types are completely equivalent, and you can substitute one for the other anywhere, anytime without any change in behavior.
  4. C has three places things can be stored:

    • The stack - local variables in functions go here. For example:

      void foo() {
          int x; // on the stack
      }
      
    • The heap - things go here when you allocate them explicitly with malloc, calloc, or realloc.

      void foo() {
          int *x; // on the stack
          x = malloc(sizeof(*x)); // the value pointed to by x is on the heap
      }
      
    • Static storage - global variables and static variables, allocated once at program startup.

      int x; // static
      void foo() {
          static int y; // essentially a global that can only be used in foo()
      }
      
  5. No idea. I wish I didn't need to answer all questions at once - this is why you should split them up :)

Note: formatting looks ugly due to some sort of markdown bug, if anyone knows of a workaround please feel free to edit (and remove this note!)

char *fun = malloc(sizeof(char) * 4);
or char fun[4];
or char *fun = "fun";

The first one can be set to any size you want at runtime, and be resized later - you can also free the memory when you are done. The second one is a pointer really 'fun' is the same as char ptr=&fun[0].

I understand what pointers do, but I don't understand what the point of them is (no pun intended). And when does something get allocated on the stack vs. the heap? How do I know where it gets allocated? Do pointers have something to do with it?

When you define something in a function like "char fun[4]" it is defined on the stack and the memory isn't available outside the function. Using malloc (or new in C++) reserves memory on the heap - you can make this data available anywhere in the program by passing it the pointer. This also lets you decide the size of the memory at runtime and finaly the size of the stack is limited (typically 1Mb) while on the heap you can reserve all the memory you have available.

edit 5. Not really - I would say pure C. C++ is (almost) a superset of C so unless you are working on a very limited embedded system it's usualy OK to use C++.

\5. Chipmunk

  • Fast and lightweight 2D rigid body physics library in C.

  • Designed with 2D video games in mind.

  • Lightweight C99 implementation with no external dependencies outside of the Std. C library.

  • Many language bindings available.

  • Simple, read the documentation and see!

  • Unrestrictive MIT license.

  • Makes you smarter, stronger and more attractive to the opposite gender!

  • ...

In your second question:

char *fun = malloc(sizeof(char) * 4);

vs

char fun[4];

vs

char *fun = "fun";

These all involve an array of 4 chars, but that's where the similarity ends. Where they differ is in the lifetime, modifiability and initialisation of those chars.

The first one creates a single pointer to char object called fun - this pointer variable will live only from when this function starts until the function returns. It also calls the C standard library and asks it to dynamically create a memory block the size of an array of 4 chars, and assigns the location of the first char in the block to fun. This memory block (which you can treat as an array of 4 chars) has a flexible lifetime that's entirely up to the programmer - it lives until you pass that memory location to free(). Note that this means that the memory block created by malloc can live for a longer or shorter time than the pointer variable fun itself does. Note also that the association between fun and that memory block is not fixed - you can change fun so it points to different memory block, or make a different pointer point to that memory block.

One more thing - the array of 4 chars created by malloc is not initialised - it contains garbage values.

The second example creates only one object - an array of 4 chars, called fun. (To test this, change the 4 to 40 and print out sizeof(fun)). This array lives only until the function it's declared in returns (unless it's declared outside of a function, when it lives for as long as the entire program is running). This array of 4 chars isn't initialised either.

The third example creates two objects. The first is a pointer-to-char variable called fun, just like in the first example (and as usual, it lives from the start of this function until it returns). The other object is a bit strange - it's an array of 4 chars, initialised to { 'f', 'u', 'n', 0 }, which has no name and that lives for as long as the entire program is running. It's also not guaranteed to be modifiable (although what happens if you try to modify it is left entirely undefined - it might crash your program, or it might not). The variable fun is initialised with the location of this strange unnamed, unmodifiable, long-lived array (but just like in the first example, this association isn't permanent - you can make fun point to something else).

The reason why there's so many confusing similarities and differences between arrays and pointers is down to two things:

  • The "array syntax" in C (the [] operator) actually works on pointers, not arrays!
  • Trying to pin down an array is a bit like catching fog - in almost all cases the array evaporates and is replaced by a pointer to its first element instead.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top