Monday's Lecture

The Stack and the Heap

alloc.c

// Introducing `calloc`, `malloc`, and friends.
// 2017-09-04   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>

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

typedef struct _complex {
    double re;
    double im;
} complex;

// void *calloc (unsigned int nThings, unsigned int thingSize);

int main (int argc, char *argv[]) {
    complex c = { 0, 0 };
    printf ("c is at %p\n", &c);
    printf ("sizeof(c) = %zu\n", sizeof (complex));

    /// Some textbooks will make you do an explicit cast; this is
    /// forbidden by our style guide, and isn't needed anyway:
    //
    // complex *cc = (complex *) calloc (1, sizeof (complex));
    //
    /// Instead, you should do:
    complex *cc = calloc (1, sizeof (complex));

    /// Allocation _can_ fail.  If it does, `malloc` and `calloc` will
    /// both return the magic value, `NULL`.  On most modern systems,
    /// `NULL` is usually zero, but it isn't always guaranteed to be.
    ///
    /// If the allocation fails, you can take two approaches:
    ///
    /// 1. the "I'm trying to develop my code in a hurry" approach:
    assert (cc != NULL);

    /// 2. the correct approach:
    if (cc == NULL) {
        printf ("Couldn't allocate memory!\n");
        return EXIT_FAILURE;
    }

    /// A nicer correct approach, which requires you to include
    /// `err.h` and `sysexits.h`:
    if (cc == NULL) {
        err (EX_OSERR, "couldn't allocate memory");
    }

    printf ("cc is at %p\n", cc);

    /// Newton's third law of memory management:
    /// "For every allocation, there is an equal and opposite free."
    free (cc);
    return EXIT_SUCCESS;
}

alloc2.c

// Using allocations to move values around.
// 2017-09-04   Jashank Jeremy <{jashankj,z5017851}@cse.unsw.edu.au>

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

typedef struct _complex {
    double re;
    double im;
} complex;

complex *readComplexNumbers (int n);

int main (int argc, char *argv[]) {
    printf ("# complex numbers: ");
    int n;
    scanf ("%d", &n);

    complex *values = readComplexNumbers (n);

    printf ("values[0] = %lf + i %lf\n", values[0].re, values[0].im);

    free (values);

    /// Say it with me, folks: USE AFTER FREE IS ILLEGAL.
    /// `dcc` will catch you if you do this; most compilers will not.
    /// This is of the same class of error as using a value
    // printf ("values[0] = %lf + i %lf\n", values[0].re, values[0].im);
    return EXIT_SUCCESS;
}

complex *readComplexNumbers (int n) {
    complex *values = calloc (n, sizeof (complex));
    assert (values != NULL);

    int i = 0;
    while (i < n) {
        printf ("x = ");
        scanf ("%lf", &(values[i].re));
        printf ("y = ");
        scanf ("%lf", &(values[i].im));
        i++;
    }

    return values;
}

I’m sorry, I’ll say that again, in case you missed it.

USE AFTER FREE IS ILLEGAL.