OPC · C examples
C files in lecture order.
References 01 → 18, all in demos/allocation/. Follow the lecture runbook for when to run.
cd demos/allocation
vim 01-copy-alias.c
make run FILE=01-copy-alias.c
Files 01–04 develop a string copy: shared storage, a missing byte, a leak, then the repair. Files 11 and 12 are optional references, outside the slide sequence. File 05 introduces integers; each of 06–09 introduces one fault into 05-integers.c. Repair and rerun each.
Structure starter · copy to live-types.c for incremental coding.
Copy a string
01-copy-alias.c · Change the copy; the original changes too
vim 01-copy-alias.c
make run FILE=01-copy-alias.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char original[] = "hello";
char *copy = original;
copy[0] = 'H';
printf("original: %s\n", original);
printf("copy: %s\n", copy);
return EXIT_SUCCESS;
}
02-copy-short.c · Allocate and copy; inspect the invalid write
vim 02-copy-short.c
make valgrind FILE=02-copy-short.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char original[] = "hello";
char *copy = malloc(strlen(original));
if (copy == NULL)
return EXIT_FAILURE;
strcpy(copy, original);
copy[0] = 'H';
printf("original: %s\n", original);
printf("copy: %s\n", copy);
return EXIT_SUCCESS;
}
03-copy-leak.c · Add room for the terminator; inspect the leak
vim 03-copy-leak.c
make valgrind FILE=03-copy-leak.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char original[] = "hello";
char *copy = malloc(strlen(original) + 1);
if (copy == NULL)
return EXIT_FAILURE;
strcpy(copy, original);
copy[0] = 'H';
printf("original: %s\n", original);
printf("copy: %s\n", copy);
return EXIT_SUCCESS;
}
04-copy-free.c · Release the copy after printing
vim 04-copy-free.c
make valgrind FILE=04-copy-free.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char original[] = "hello";
char *copy = malloc(strlen(original) + 1);
if (copy == NULL)
return EXIT_FAILURE;
strcpy(copy, original);
copy[0] = 'H';
printf("original: %s\n", original);
printf("copy: %s\n", copy);
free(copy);
return EXIT_SUCCESS;
}
Arrays and memory errors
05-integers.c · Allocate and initialise a requested number of integers
vim 05-integers.c
make valgrind FILE=05-integers.c
Enter 100.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count;
if (scanf("%d", &count) != 1) return EXIT_FAILURE;
if (count <= 0 || count > 1000) return EXIT_FAILURE;
int *p = malloc(count * sizeof(int));
if (p == NULL) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
for (int i = 0; i < count; ++i)
p[i] = 0;
printf("first=%d, last=%d\n", p[0], p[count - 1]);
free(p);
return EXIT_SUCCESS;
}
06-uninitialised.c · Remove initialisation; inspect the read
vim 06-uninitialised.c
make valgrind FILE=06-uninitialised.c
Enter 4.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count;
if (scanf("%d", &count) != 1) return EXIT_FAILURE;
if (count <= 0 || count > 1000) return EXIT_FAILURE;
int *p = malloc(count * sizeof(int));
if (p == NULL) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
printf("first=%d, last=%d\n", p[0], p[count - 1]);
free(p);
return EXIT_SUCCESS;
}
07-overrun.c · Write one element too far
vim 07-overrun.c
make valgrind FILE=07-overrun.c
Enter 4.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count;
if (scanf("%d", &count) != 1) return EXIT_FAILURE;
if (count <= 0 || count > 1000) return EXIT_FAILURE;
int *p = malloc(count * sizeof(int));
if (p == NULL) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
for (int i = 0; i <= count; ++i)
p[i] = 0;
printf("first=%d, last=%d\n", p[0], p[count - 1]);
free(p);
return EXIT_SUCCESS;
}
08-dangling.c · Read after free
vim 08-dangling.c
make valgrind FILE=08-dangling.c
Enter 4.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count;
if (scanf("%d", &count) != 1) return EXIT_FAILURE;
if (count <= 0 || count > 1000) return EXIT_FAILURE;
int *p = malloc(count * sizeof(int));
if (p == NULL) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
for (int i = 0; i < count; ++i)
p[i] = 0;
free(p);
printf("first=%d, last=%d\n", p[0], p[count - 1]);
return EXIT_SUCCESS;
}
09-leak.c · Lose the address before free
vim 09-leak.c
make valgrind FILE=09-leak.c
Enter 4.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int count;
if (scanf("%d", &count) != 1) return EXIT_FAILURE;
if (count <= 0 || count > 1000) return EXIT_FAILURE;
int *p = malloc(count * sizeof(int));
if (p == NULL) {
fputs("Allocation failed\n", stderr);
return EXIT_FAILURE;
}
for (int i = 0; i < count; ++i)
p[i] = 0;
printf("first=%d, last=%d\n", p[0], p[count - 1]);
p = NULL;
free(p);
return EXIT_SUCCESS;
}
One row, then a grid
10-array.c · Array elements and their addresses
vim 10-array.c
make run FILE=10-array.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(4 * sizeof(int));
if (!a) return EXIT_FAILURE;
for (int i = 0; i < 4; ++i)
a[i] = (int)(10 * (i + 1));
for (int i = 0; i < 4; ++i)
printf("a[%d]=%d at %p\n", i, a[i], (void *)&a[i]);
free(a);
return EXIT_SUCCESS;
}
13-matrix-flat.c · Matrix in one allocation
vim 13-matrix-flat.c
make run FILE=13-matrix-flat.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int rows = 4, cols = 3;
int *m = malloc(rows * cols * sizeof(int));
if (!m) return EXIT_FAILURE;
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
m[i * cols + j] = (int)(10 * i + j);
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) printf("%3d", m[i * cols + j]);
puts("");
}
free(m);
return EXIT_SUCCESS;
}
14-matrix-rows.c · Fixed pointer table; allocated rows
vim 14-matrix-rows.c
make run FILE=14-matrix-rows.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *m[4];
int i = 0;
for (; i < 4; ++i) {
m[i] = malloc(3 * sizeof(int));
if (!m[i]) break;
}
if (i != 4) {
while (i > 0) free(m[--i]);
return EXIT_FAILURE;
}
for (i = 0; i < 4; ++i) {
for (int j = 0; j < 3; ++j) {
m[i][j] = (int)(10 * i + j);
printf("%3d", m[i][j]);
}
puts("");
}
for (i = 0; i < 4; ++i) free(m[i]);
return EXIT_SUCCESS;
}
15-matrix-dynamic.c · Allocated pointer table and rows
vim 15-matrix-dynamic.c
make run FILE=15-matrix-dynamic.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int rows = 4, cols = 3;
int **m = malloc(rows * sizeof(int *));
if (!m) return EXIT_FAILURE;
int i = 0;
for (; i < rows; ++i) {
m[i] = malloc(cols * sizeof(int));
if (!m[i]) break;
}
if (i != rows) {
while (i > 0) free(m[--i]);
free(m);
return EXIT_FAILURE;
}
for (i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
m[i][j] = (int)(10 * i + j);
printf("%3d", m[i][j]);
}
puts("");
}
for (i = 0; i < rows; ++i) free(m[i]);
free(m);
return EXIT_SUCCESS;
}
User-defined types
16-types.c · Enumerations and structure members
vim 16-types.c
make run FILE=16-types.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum day { mon, tue, wed, thu, fri, sat, sun };
struct address {
char street[100];
int number;
};
int main(void) {
enum day today;
today = wed;
printf("mon=%d, today=%d, sun=%d\n", mon, today, sun);
struct address home = { "Paul Bert", 12 };
printf("initial: %d %s\n", home.number, home.street);
strcpy(home.street, "Rue de Paris");
home.number = 14;
printf("dot: %d %s\n", home.number, home.street);
struct address *p = &home;
strcpy(p->street, "Rue de Paris");
p->number = 16;
printf("arrow: %d %s\n", home.number, home.street);
return EXIT_SUCCESS;
}
17-padding.c · Measure structure sizes and offsets
vim 17-padding.c
make run FILE=17-padding.c
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
struct grouped {
int id1, id2;
char c1, c2;
float ratio;
};
struct interleaved {
int id1; char c1;
int id2; char c2;
float ratio;
};
int main(void) {
// These small sizes fit in int; convert explicitly for printf("%d").
printf("int=%d float=%d\n", (int)sizeof(int), (int)sizeof(float));
printf("grouped: %d bytes; ratio at %d\n", (int)sizeof(struct grouped), (int)offsetof(struct grouped, ratio));
printf("mixed: %d bytes; ratio at %d\n", (int)sizeof(struct interleaved), (int)offsetof(struct interleaved, ratio));
return EXIT_SUCCESS;
}
18-nested.c · Nested structures
vim 18-nested.c
make run FILE=18-nested.c
#include <stdio.h>
#include <stdlib.h>
struct date { short day, month; int year; };
typedef enum { mon, tue, wed, thu, fri, sat, sun } DAY;
typedef struct { DAY day; struct date date; } A_DATE;
int main(void) {
A_DATE today = { wed, { 3, 9, 2014 } };
today.day = wed;
today.date.year = 2014;
A_DATE *p = &today;
p->day = today.day;
p->date.year = 2026;
printf("day code=%d; %d/%d/%d\n", today.day, today.date.day, today.date.month, today.date.year);
return EXIT_SUCCESS;
}
Optional reference
11-string.c · Characters and the terminator
vim 11-string.c
make run FILE=11-string.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *s = malloc(4 * sizeof(char));
if (!s) return EXIT_FAILURE;
strcpy(s, "cat"); // Three letters and the terminator.
for (int i = 0; i < 4; ++i)
printf("s[%d] = %u\n", i, (unsigned char)s[i]);
puts(s);
free(s);
return EXIT_SUCCESS;
}
12-string-assignment.c · Pointer assignment is not copying text
vim 12-string-assignment.c
make valgrind FILE=12-string-assignment.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *s = malloc(100);
if (!s) return EXIT_FAILURE;
// Intentional error from the original string example.
s = "hello"; // The allocated block is now unreachable.
char *p = s;
s = "bye";
printf("p=%s; s=%s\n", p, s);
// Neither pointer now points into the allocated block.
return EXIT_SUCCESS;
}