static_data_example.c

#include <stdio.h>
#include <stdlib.h>

int counter = 0;    // global var

int main(int argc, char** argv) {
  counter++;
  printf("count = %d\n",counter);
  return EXIT_SUCCESS;
}

stack_data_example.c

#include <stdio.h>
#include <stdlib.h>

int foo(int a) {
  int x = a + 1;     // local var
  return x;
}

int main(int argc, char** argv) {
  int y = foo(10);   // local var
  printf("y = %d\n",y);
  return EXIT_SUCCESS;
}

heap_stack_example.c

#include <stdio.h>
#include <stdlib.h>

int* copy(int a[], int size) {
  int i, *a2;

  a2 = malloc(size*sizeof(int));
  if (a2 == NULL)
    return NULL;

  for (i = 0; i < size; i++)
    a2[i] = a[i];

  return a2;
}

int main(int argc, char** argv) {
  int nums[4] = {1, 2, 3, 4};
  int* ncopy = copy(nums, 4);

  // .. do stuff with the array ..
  printf("--- nums array elements ---\n");
  for (int i = 0; i < 4; i++) {
      printf("nums[%d] = %d\n", i, nums[i]);
  }

  printf("--- ncopy array elements ---\n");
  for (int i = 0; i < 4; i++) {
      printf("ncopy[%d] = %d\n", i, ncopy[i]);
  }

  // Finish using the array
  free(ncopy);
  return EXIT_SUCCESS;
}

read_uninit_mem.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int main() {
  int i;
  printf("%d\n", i);  // Invalid read!
  i = 374;
  printf("%d\n", i);  // OK, was initialized to 374

  float* fptr = (float*) malloc(sizeof(float));
  if (fptr == NULL) {
    return errno;
  }
  printf("%f\n", *fptr);  // Invalid read!
}

mem_alloc_example.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void foo(int n, int m) {
  int i, *p;

  p = (int*) malloc(n*sizeof(int)); /* allocate block of n ints */

  if (p == NULL) {                  /* check for allocation error */
    perror("malloc");
    exit(0);
  }

  for (i=0; i<n; i++)               /* initialize int array */
    p[i] = i;
                            /* add space for m ints to end of p block */
  p = (int*) realloc(p,(n+m)*sizeof(int));

  if (p == NULL) {                  /* check for allocation error */
    perror("realloc");
    exit(0);
  }

  for (i=n; i < n+m; i++)           /* initialize new spaces */
    p[i] = i;

  for (i=0; i<n+m; i++)             /* print new array */
    printf("%d\n", p[i]);

  free(p);                          /* free p */
}

int main() {
    printf("--- n = 0, m = 2 ---\n");
    foo(0, 2);
    printf("\n--- n = 6, m = 2 ---\n");
    foo(6, 2);
    printf("\n--- n = 3, m = 4 ---\n");
    foo(3, 4);

    // Notice that realloc can reduce the size of the array (or not change the
    // size of the array at all). See below for example.
    printf("\n--- n = 3, m = 0 ---\n");
    foo(3, 0);
    printf("\n--- n = 5, m = -2 ---\n");
    foo(5, -2);
}

calloc_example.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void* my_calloc(int size, int num);

int main() {
    // allocate a 10-double array
    double* arr = (double*) calloc(10, sizeof(double));
    if (arr == NULL) {
        return errno;
    }
    printf("%f\n", arr[0]); // OK, will print 0.00000

    // my_calloc implementation usage
    double* arr2 = (double*) my_calloc(sizeof(double), 10);
    if (arr == NULL) {
        return errno;
    }
    printf("%f\n", arr2[0]); // OK, will print 0.00000
}

void* my_calloc(int size, int num) {
    char* arr = malloc(size * num);
    if (arr == NULL) return NULL;
    for (int i = 0; i < size*num; i++) {
        arr[i] = 0;
    }
    return arr;
}