Broken courses.c

/**
 A program that prints out your favorite courses!
*/
#include <stdio.h>
#include <stdlib.h>

// Assuming a default of 3 courses
#define NUM_COURSES 3

/* Returns an array containing course numbers*/
int* courses_array(void);

int main() {
    printf("A list of my favorite courses:\n");

    int* courses = courses_array();

    for (int i = 0; i < NUM_COURSES; i++) {
        printf("%d\n", courses[i]);
    }

    return 0;
}

int* courses_array() {
    int arr[NUM_COURSES];  // Change this line

    // Feel free to change the numbers too
    arr[0] = 374;
    arr[1] = 474;
    arr[2] = 469;

    return arr;
}

Create a C file called courses.c and copy-paste the above code into it. Alternatively, you can run the following command to download the file:

wget https://courses.cs.washington.edu/courses/cse374/25su/lectures/code/courses.c

And use the following commands to compile and run your code:

gcc -g -Wall -std=c11 -o courses courses.c
./courses

Add in calls to malloc and free to fix the program!

FIXED courses.c

/**
 A program that prints out your favorite courses!
*/
#include <stdio.h>
#include <stdlib.h>

#define NUM_COURSES 3

int* courses_array(void);

int main() {
    printf("A list of my favorite courses:\n");
    int* courses = courses_array();
    for (int i = 0; i < NUM_COURSES; i++) {
        printf("%d\n", courses[i]);
    }

    // make sure to free the dynamically-allocated memory
    // before exiting the program

    free(courses);

    // optional, especially since it's the end of the program,
    // but is programming defensively  
    courses = NULL;

    return 0;
}
int* courses_array() {
    // use malloc (allocated NUM_COURSES number of ints)
    int* arr = (int*) malloc(NUM_COURSES * sizeof(int));

    // check if array was allocated
    if (arr == NULL) {
        perror("cannot allocate array"); // print error
        exit(EXIT_FAILURE);
    }

    arr[0] = 374;
    arr[1] = 474;
    arr[2] = 469;

    return arr;
}

heap_stack_example.c

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

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

  a2 = (int*) 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;

  printf("calling malloc(%d * sizeof(int)):\n", n);
  p = (int*) malloc(n*sizeof(int)); /* allocate block of n ints */

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

  for (i=0; i<n; i++)               /* initialize int array */
    p[i] = i;

  for (i=0; i<n; i++)              /* print array elements */
    printf("%d\n", p[i]);
                                    /* add space for m ints to end of p block */
  printf("calling realloc((%d+%d) * sizeof(int)):\n", n, m);
  p = (int*) realloc(p,(n+m)*sizeof(int));

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

  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 = (char*) malloc(size * num);
    if (arr == NULL) return NULL;
    for (int i = 0; i < size*num; i++) {
        arr[i] = 0;
    }
    return arr;
}