Hey,
So I've got these instructions for a piece of work, but I don't understand what it's saying, there are prototypes for functions but like I said, I don't understand them.

typedef struct BigInteger* big_integer_t; // so I know typedef allows you to assign different names to existing types, but this seems to be making a struct, but then has this pointer of type BigInteger after it, so is it making a struct of this type? What would that even do?
big_integer_t bigIntFromString(const char *str);
void freeBigInt(big_integer_t a); // what does the 'a' mean? What sort of formatting is this? Thought you need a comma between variables.
big_integer_t add(big_integer_t a, big_integer_t); // From this line it seems that 'big_integer_t a' is a different variable, I didn't think you could have a space in a variable name.
big_integer_t subtract(big_integer_t a, big_integer_t);

Sorry if this is all really simple stuff, but it's confusing me :(

typedef struct BigInteger* big_integer_t; // so I know typedef allows you to assign different names to existing types, but this seems to be making a struct, but then has this pointer of type BigInteger after it, so is it making a struct of this type? What would that even do?

This line defines the type big_integer_t to be a pointer to a BigInteger . This is a handy shortcut--without it, you'd have to type struct BigInteger* everywhere you wanted a pointer to a BigInteger .

Here's a short program to run and ponder:

#include <stdio.h>

struct BigInteger
{
    short stuff;
};

typedef struct BigInteger* big_integer_t;

int main()
{
    printf("sizeof(short) is %d\n", sizeof(short));
    printf("sizeof(BigInteger) is %d\n", sizeof(struct BigInteger));
    printf("\n");
    printf("sizeof(void *) is %d\n", sizeof(void *));
    printf("sizeof(struct BigInteger*) is %d\n", sizeof(struct BigInteger*));
    printf("sizeof(big_integer_t) is %d\n", sizeof(big_integer_t));

    return 0;
}
void freeBigInt(big_integer_t a); // what does the 'a' mean? What sort of formatting is this? Thought you need a comma between variables.

freeBigInt is a function that takes a single parameter, a , which happens to be of type big_integer_t . Because of the typedef, this is essentially shorthand for void freeBigInt(struct BigInteger* a) .

There's no comma because there's only one parameter. Something with two parameters would look like this: void freeTwoBigInts(big_integer_t a, big_integer_t b)

big_integer_t add(big_integer_t a, big_integer_t); // From this line it seems that 'big_integer_t a' is a different variable, I didn't think you could have a space in a variable name.

big_integer_t a is a single parameter declaration, just like in freeBigInt above. big_integer_t is a 's type; we're still dealing with pointers to BigInteger s.

Thanks for your help, I'm slowly getting there!
I couldn't quite work out what the program you wrote was doing though. What is void * ? Am I right in saying that the first two lines were looking at the actual values stored (the short is 2 bytes, and so is the struct because all it contains is the short ), where as the last two were looking at pointers, and pointers are 4 bytes?

With the add and subtract lines:

big_integer_t add(big_integer_t a, big_integer_t); 
big_integer_t subtract(big_integer_t a, big_integer_t);

What is the second big_integer_t doing? The function is using a parameter called a of type big_integer_t , as well as just the type big_integer_t . I'm sorry, but I don't understand what this second parameter is for.

Thanks again for your previous help!

What is void * ?

It's the type of a void pointer; essentially, a pointer to somewhere in memory without an associated data type. I'm just using it to demonstrate the size of a pointer on your machine.

Am I right in saying that the first two lines were looking at the actual values stored (the short is 2 bytes, and so is the struct because all it contains is the short ), where as the last two were looking at pointers, and pointers are 4 bytes?

There are no actual values involved; I'm just printing out the number of bytes required to store values of each of those data types. You have the right idea, though--my fake BigInteger should normally be the same size as a short since that's all it contains. Same goes for the three pointer types. The idea there is to show that big_integer_t is clearly not the same thing as a BigInteger (because their sizes are different).

With the add and subtract lines:

big_integer_t add(big_integer_t a, big_integer_t); 
big_integer_t subtract(big_integer_t a, big_integer_t);

What is the second big_integer_t doing? The function is using a parameter called a of type big_integer_t , as well as just the type big_integer_t . I'm sorry, but I don't understand what this second parameter is for.

Those lines are declarations. Essentially they're saying that somewhere later in the code, there will be definitions for two functions, add and subtract , which both take two parameters of type big_integer_t .

The trick here is that declarations don't need to name parameters. All of the following are equivalent:

  • big_integer_t add(big_integer_t, big_integer_t);
  • big_integer_t add(big_integer_t a, big_integer_t b);
  • big_integer_t add(big_integer_t a, big_integer_t);
  • big_integer_t add(big_integer_t, big_integer_t b);
  • big_integer_t add(big_integer_t sifl, big_integer_t olly);

If you have the actual code for add and subtract , my guess is that the definitions actually name all of the parameters.

Fun facts: The names of the parameters in the definition don't need to match the ones given in the declaration, if any. Also, the definition doesn't have to name parameters either, which you won't see very often because without a name, the function can't do anything with the parameter--it just ignores it.

I consider it good practice, though, to name all of your parameters in declarations and make them match your definitions. That's much easier to read and maintain.

It's all clicking in to place now :)
There's one last thing I'm hoping you can clarify for me; Does the line big_integer_t add(big_integer_t a, big_integer_t); create this add function inside the BigInteger struct? Or is it creating its own instance of the BigInteger struct?

Does the line big_integer_t add(big_integer_t a, big_integer_t); create this add function inside the BigInteger struct?

No. You can't add functions to structures in C. You can in C++, but that's a different discussion.

Or is it creating its own instance of the BigInteger struct?

Also no. This is just a function declaration. All it does is say "Hey, somewhere in here there's code for a function called 'add' and here's some information about how you call it."

Remember that big_integer_t is really a just a pointer to a BigInteger . The function assumes you've already created a pair of BigInteger s to add, and that you're passing in pointers to them; and you have to assume that the return value also points to a BigInteger that's already been created--but there's no true guarantee that any of these pointers actually point to anything useful. You'd have to look at the code in the definition of add to verify that it's not returning garbage (it probably isn't).

Fun with pointers: It's possible that add is creating a brand-new BigInteger for its return value, but because you're passing it pointers, it could also, for example, just modify your a parameter and return the same pointer you passed in for a .

Ah, so the big_integer_t at the front is just defining what type the return value from the function is?

The last thing I'm hoping you can help with is the phrase "free them". We are told that the first function, big_integer_t bigIntFromString(const char *str); , contructs large integers from strings, and the second function, freeBigInt , frees the integers.

Does that mean anything to you?

Ah, so the big_integer_t at the front is just defining what type the return value from the function is?

Exactly.

The last thing I'm hoping you can help with is the phrase "free them". We are told that the first function, big_integer_t bigIntFromString(const char *str); , contructs large integers from strings, and the second function, freeBigInt , frees the integers.

Does that mean anything to you?

Because it's a pointer, the "value" of a big_integer_t is only the address of a memory location. Creating a pointer variable reserves the storage needed to hold this address (normally 4 bytes on a 32-bit system), but it doesn't actually allocate any memory at that address. You still need to reserve enough free space for a BigInteger .

This is half of what bigIntFromString does--the other half being reading the string and deciding what number it represents. If you look at the definition of bigIntFromString , you'll probably see something like this:

big_integer_t b = malloc(sizeof(big_integer_t));

After that line, b is a pointer to somewhere in memory that is big enough to hold a BigInteger . freeBigInt does the opposite--it tells the system you're done with the chunk of memory you reserved by calling bigIntFromString , and it can now be used for other purposes. The most basic definition of freeBigInt will have just this one line:

free(b);

Once freed, the pointer still refers to the same location, but the system might use the memory there for other purposes, so it's not safe to do anything with it after you've called freeBigInt .

The benefit you get from all of this allocating and freeing of memory is that you get a pointer to pass around instead of the whole object. Without pointers, you're actually copying entire BigInteger s every time you use them as parameters to or return values from functions. With pointers, the actual BigInteger stays in one place, and you're only ever copying pointers, which are always the same small size, even if BigInteger is enormous.

This article has been dead for over six months. Start a new discussion instead.