Wednesday 17 December 2014

Tips for those starting C programming

Since starting my PhD I have been coding in Perl again (yay) but I have also started coding in C. I've found C more difficult than I thought to get to grips with for such a familiar syntax. Here are some things that caught me out and need to be remembered.

Remember to cast your results, arguments and expressions to exactly what is requested/expected
I was using the ceil() function found in the <math.h> header include. This has a signature: double ceil(double x); My initial thoughts were it would do the casting automatically since what is an int except a double with the decimal numbers attached and if I'm dividing a double by an int then it will just evaluate the result of the calculation as a double. I was wrong. I've been coding PHP way too long. I tried:

x = ceil ( y / z ); //x was 0 no matter what numbers I passed!

The problem was a type issue. I had to cast z to a double and change the output of ceil to int:

x = (int) ceil ( y / (double) z ); //now it works!

Always initialize variables with a starting value
Another thing I expected the language to do was to initialize variables for me like it does with PHP, so when I declared: unsigned int i; I expected i to hold a value of 0. It doesn't! C just grabs a block of memory for the x variable but it doesn't clear it. YOU have to do that! This is what I did initially:

unsigned int i; //but what is held in i?
while ( j > i ) {
    //do something
    i++;
}

Every time I ran this bit of code it did something a different numbers of times and sometimes not at all. That's because the memory occupied for the variable i wasn't initialized and the previous value present in that memory block was being used as the starting value. It was usually something random like 65288424572589. The correct thing to do is to initialize a variable with a value at declaration or shortly before you need to use it: unsigned int i = 0;

Choose calloc over malloc

Calloc is memory allocation but it initializes values to 0 as expected. It is always better to know what values you expect before you change them. The best way to allocate memory from the stack is:

unsigned int * arr;
unsigned int length = 10;
if ( ( arr = ( unsigned int * ) calloc ( length , sizeof ( unsigned int ) ) ) == NULL )
{
    fprintf ( stderr, " Error: arr could not be allocated!\n");
    return ( EXIT_FAILURE );
}


Don't forget to free( arr ) before returning. Every time, check you free things before returning.

Don't trouble yourself with extra compilation flags (preference)

Just because you like to code a certain way, it shouldn't mean you need the burden of more compilation flags. Only bother with more flags if you really need the performance boost. For example, declaring and initializing a variable in a for loop requires the -std=c99 flag to be added to compile, otherwise it gives this error for the code:

//'for' loop initial declaration used outside C99 mode
for (int i = 0; i < x; i++){/*bla*/}

To get past this problem why not just declare the variable before and initialize it in the loop like so:

int i;
for ( i = 0; i < x ; i++){/*bla*/}

The reason why I prefer not to use more flags is because you want your code to be portable and compilable everywhere and by novices who don't know about flags.

Read up on string handling in C

Strings are virtually ubiquitous in coding. You just need them. In C a string is declared as a char array or using the pointer shortcut:

char * s = "Hello";

This not only automatically adds the string terminator (NUL or '\0'), it is a pointer. But because it's a pointer you can't do very much with it unless you use the <string.h> header functions such as strcmp, strcpy and concat. Two examples:

if ( s ==  "Hello); //wrong!
if ( strcmp (s, "Hello") == 0); //right! 

char * a = "Hello A";
char * b = a; //wrong!
strcpy ( b, a ); //right!

And another thing, long string literals, an alternative to HEREDOC syntax, is declared like so in C:

char * r = "ABC"
           "DEF"
           "GHI";

Pointers store the starting memory address of variables

It's really straightforward once you figure it out. Consider a variable i and it's pointer. i holds the actual value, while the pointer holds the memory address of i. To modify the contents of i through it's pointer you need to dereference it:

int i = 3; //initialise i to 3
int *iPtr = &i; //Ampersand returns a variables address to be stored in pointer
( *iPtr ) = 4; //dereference the pointer to access it's associated variable
printf("%d\n", i); //4

Pointers are used for arrays mainly as shown in the calloc example above. The pointer of an array is the start position of the first element in the array. You should know that if you pass an array to a function you are actually only passing its reference.