07/05

An Introduction to C

20150705

So, in this part of the C Intro, I would like to say a bit about memory management.

VARIABLES

In C, there are really only two ways that you can allocate memory. The first and most common way is by declaring a variable. The second way is to explicitly request memory. You have actually already seen both of these if you've read all of the preceeding articles on C.

So, first, let's reiterate the sizes of each variable type (this is for AMD64, and will differ slightly from what was stated earlier in the tutorial series, which was for 686 non-pae):

char                1 byte -- %c or %hhi or %hhu
short               2 bytes -- %hi or %hu
int                 4 bytes -- %i or %d or %u
long                8 bytes -- %li or %lu
long long           8 bytes -- %lli or %llu
single float        4 bytes -- %f
double float        8 bytes -- %f or %lf
long double        16 bytes -- %Lf

With those sizes let's look at minimum and maximum values:

signed variables

char                min: -128, max: 127
short               min: -32768, max: 32767
int                 min: -2147483648, max: 2147483647
long                min: -9223372036854775808, max: 9223372036854775807
long long           min: -9223372036854775808, max: 9223372036854775807

unsigned variables

char                min: 0, max: 255
short               min: 0, max: 65535
int                 min: 0, max: 4294967295
long                min: 0, max: 18446744073709551615
long long           min: 0, max: 18446744073709551615

If you need to compute these values on a different architecture, you can use the following code to do so:

#include <stdio.h>
#include <limits.h>
#include <unistd.h> /* For the ssize_t header */
int main(void) {
  printf("\n\nSigned    : Size %22s %22s\n", "Min", "Max");
  printf("--------------------------------------------------------------\n");
  printf("char      : %4d %22d %22d\n", (int) sizeof(char), CHAR_MIN,CHAR_MAX);
  printf("short     : %4d %22d %22d\n", (int) sizeof(short), SHRT_MIN,SHRT_MAX);
  printf("int       : %4d %22d %22d\n", (int) sizeof(int), INT_MIN,INT_MAX);
  printf("long      : %4d %22ld %22ld\n", (int) sizeof(long), LONG_MIN,LONG_MAX);
  printf("long long : %4d %22lld %22lld\n\n", (int) sizeof(long long),LLONG_MIN,LLONG_MAX);
  printf("Unsigned  : Size %22s %22s\n", "Min", "Max");
  printf("--------------------------------------------------------------\n");
  printf("char      : %4d %22d %22u\n", (int) sizeof(unsigned char), 0,UCHAR_MAX);
  printf("short     : %4d %22d %22u\n", (int) sizeof(unsigned short), 0,USHRT_MAX);
  printf("int       : %4d %22d %22u\n", (int) sizeof(unsigned int), 0,UINT_MAX);
  printf("long      : %4d %22d %22lu\n", (int) sizeof(unsigned long), 0,ULONG_MAX);
  printf("long long : %4d %22d %22llu\n\n",(int) sizeof(unsigned long long), 0, ULLONG_MAX);
  printf("Miscellaneous sizes:\n");
  printf("--------------------------------------------------------------\n");
  printf("Single precision float: %38d\n", (int) sizeof(float));
  printf("Double precision float: %38d\n", (int) sizeof(double));
  printf("size_t: %54d\n", (int) sizeof(size_t));
  printf("ssize_t: %53d\n", (int) sizeof(ssize_t));
  printf("Double Double: %38d\n", (int) sizeof(long double));
  return 0;
}

So, when you use a variable, you will automatically be allocated 1 to 16 bytes of memory. In the case of an array, the amount of memory allocated will be dependent upon the size and type of array. When using a user defined type (struct), it will depend upon the struct's contents.

When a pointer is declared in C, you just a get space for the pointer.

char *p;

4 consecutive bytes of memory are allocated for p. Note, the memory is not initialized, only allocated. It could contain a bunch of garbage. For this reason, you will want to initialize the pointer. A better declaration of the variable would be:

char *p = NULL;

Another note is that you shouldn't copy a variable directly into the pointer variable. You could cause a segmentation fault by doing so. By initialising p to NULL, you are ensuring that you can use p correctly. Trying to copy... a string, for instance, into location 0 (NULL) would result in a run-time Bus Error, and a program crash.

MANUAL ALLOCATION

To manually allocate memory you have malloc and calloc. You have also have realloc, which changes the size of a block of memory that was previously allocated with malloc() or calloc(). Variables are granted memory on stack. Manual allocations grants memory on heap. It won't be free'd when you quit using it, so you need to free any memory you manually allocate with the free() function. malloc, calloc, realloc, and free are all in stdlib.

Malloc (and calloc) will return a non-NULL value if the request for space has been successful, and NULL if it fails. Using the result of malloc (or calloc) after it has failed to locate memory WILL result in a run-time program crash.