Programming Fundamentals
Course Resources
- Administrivia
- Resources
- Lab/Test/Assignment
- Other
- Revision
Week-by-Week
- Tutorial
- Laboratory
- Tuesday June 01 2021 Lecture Topics
- Thursday June 03 2021 Lecture Topics
- Tutorial
- Laboratory
- Tuesday June 08 2021 Lecture Topics
- Tuesday June 10 2021 Lecture Topics
- Tutorial
- Laboratory
- Weekly Test
- Tuesday June 29 2021 Lecture Topics
- Thursday July 01 2021 Lecture Topics
- Tutorial
- Laboratory
- Weekly Test
- Tuesday July 13 2021 Lecture Topics
- Thursday July 15 2021 Lecture Topics
- Tutorial
- Laboratory
- Weekly Test
- Tuesday July 20 2021 Lecture Topics
- Thursday July 22 2021 Lecture Topics
- Tutorial
- Laboratory
- Weekly Test
- Tuesday July 27 2021 Lecture Topics
- Thursday July 29 2021 Lecture Topics
- Tutorial
Topic-by-Topic
- Course Intro
-
#include <stdio.h>
int main(void) {
printf("Hello Andrew!\n");
return 0;
}
Convert a temperature in fahrenheit to celsius
#include <stdio.h>
int main(void) {
double fahrenheit, celsius;
printf("Enter Fahrenheit temperature: ");
scanf("%lf", &fahrenheit);
celsius = 5.0 / 9.0 * (fahrenheit - 32);
printf("%lf Fahrenheit = %lf Celsius\n", fahrenheit, celsius);
return 0;
}
Marc Chee, 2021
This small example will ask the user to input the result of rolling two dice.
It will then check the sum of them against its secret number.
It will report back: success (higher or equal) or failure (lower)
#include <stdio.h>
#define SECRET_TARGET 7
int main(void) {
int die_one;
int die_two;
// we start by asking the user for their dice rolls
printf("Please enter your first die roll: ");
// then read in a number they type in the terminal
scanf("%d", &die_one);
// repeat for the second die
printf("Please enter your second die roll: ");
scanf("%d", &die_two);
// calculate the total and report it
int total = die_one + die_two;
printf("Your total roll is: %d\n ", total);
// Now test against the secret number
if (total >= SECRET_TARGET) {
// success
printf("Skill roll succeeded!\n");
} else {
// the same as total < SECRET TARGET
// but we don't have to test it because
// we've already checked all other
// possibilities
printf("Skill roll failed!\n");
}
return 0;
}
Marc Chee, 2021
This small example will ask the user to input the result of rolling two dice.
It will then check the sum of them against its secret number.
It will report back: success (higher or equal) or failure (lower)
#include <stdio.h>
#define MIN_VALUE 1
#define MAX_VALUE 6
#define SECRET_TARGET 7
int main(void) {
int die_one;
int die_two;
// we start by asking the user for their dice rolls
printf("Please enter your first die roll: ");
// then read in a number they type in the terminal
scanf("%d", &die_one);
if (die_one < MIN_VALUE || die_one > MAX_VALUE) { // die_one is invalid
printf("%d is not a valid roll for a D%d.\n", die_one, MAX_VALUE);
die_one = die_one % MAX_VALUE;
// make any value < MIN_VALUE into MAX_VALUE
if (die_one < MIN_VALUE) {
die_one = MAX_VALUE;
}
}
// repeat for the second die
printf("Please enter your second die roll: ");
scanf("%d", &die_two);
if (die_two < MIN_VALUE || die_two > MAX_VALUE) { // die_two is invalid
printf("%d is not a valid roll for a D%d.\n", die_two, MAX_VALUE);
die_two = die_two % MAX_VALUE;
// make any value < MIN_VALUE into MAX_VALUE
if (die_two < MIN_VALUE) {
die_two = MAX_VALUE;
}
}
// calculate the total and report it
int total = die_one + die_two;
printf("Your total roll is: %d\n ", total);
// Now test against the secret number
if (total >= SECRET_TARGET) {
// success
printf("Skill roll succeeded!\n");
} else {
// the same as total < SECRET TARGET
// but we don't have to test it because
// we've already checked all other
// possibilities
printf("Skill roll failed!\n");
}
return 0;
}
A simple program demonstrating the use of a while loop
#include <stdio.h>
int main(void) {
// read an integer n
// print n asterisks
int n;
printf("How many asterisks? ");
scanf("%d", &n);
int loop_counter = 0;
while (loop_counter < n) {
printf("*");
loop_counter = loop_counter + 1;
}
printf("\n");
return 0;
}
Read numbers printing whether they are even or odd illustrates use of a sentinel variable (stop_loop)
Note for simplicity we are assuming scanf succeeds in reading an integer.
A robust program would check that scanf returns 1 to indicate an integer read.
#include <stdio.h>
int main(void) {
int stop_loop, number;
printf("Enter numbers, 0 to stop\n");
stop_loop = 0;
while (stop_loop != 1) {
scanf("%d", &number);
if (number == 0) {
stop_loop = 1;
} else if (number % 2 == 1) {
printf("%d is odd.\n", number);
} else {
printf("%d is even.\n", number);
}
}
return 0;
}
A simple program which prints a square
#include <stdio.h>
int main(void) {
int size;
printf("Enter size: ");
scanf("%d", &size);
// print `size` lines
int row = 0;
while (row < size) {
// print a row of `size` asterisks
int column = 0;
while (column < size) {
printf("*");
column = column + 1;
}
// the row is finished, start the next line
printf("\n");
row = row + 1;
}
return 0;
}
print all possible dice rolls
#include <stdio.h>
#define SIDE_LENGTH 13
int main(void) {
int die_one_size;
int die_two_size;
// User decides the two dice sizes
printf("Please enter the size of the first die: ");
scanf("%d", &die_one_size);
printf("Please enter the size of the second die: ");
scanf("%d", &die_two_size);
// Then loop through both dice
int die1 = 1;
while (die1 <= die_one_size) { // seen die1 - 1 values
int die2 = 1;
while (die2 <= die_two_size) { // seen die2 - 1 values
int total = die1 + die2;
printf("%d , %d total: %d\n", die1, die2, total);
die2++;
}
die1++;
}
return 0;
}
print all possible dice rolls
#include <stdio.h>
#define SIDE_LENGTH 13
int main(void) {
int die_one_size;
int die_two_size;
int target_value;
// User decides the two dice sizes and target
printf("Please enter the size of the first die: ");
scanf("%d", &die_one_size);
printf("Please enter the size of the second die: ");
scanf("%d", &die_two_size);
printf("Please enter the target value: ");
scanf("%d", &target_value);
// Then loop through both dice
int die1 = 1;
while (die1 <= die_one_size) { // seen die1 - 1 values
int die2 = 1;
while (die2 <= die_two_size) { // seen die2 - 1 values
int total = die1 + die2;
if (total == target_value) {
printf("%d , %d total: %d\n", die1, die2, total);
}
die2++;
}
die1++;
}
return 0;
}
print all possible dice rolls
#include <stdio.h>
#define SIDE_LENGTH 13
int main(void) {
int die_one_size;
int die_two_size;
int target_value;
// User decides the two dice sizes and target
printf("Please enter the size of the first die: ");
scanf("%d", &die_one_size);
printf("Please enter the size of the second die: ");
scanf("%d", &die_two_size);
printf("Please enter the target value: ");
scanf("%d", &target_value);
int num_successes = 0;
int num_rolls = 0;
// Then loop through both dice
int die1 = 1;
while (die1 <= die_one_size) { // seen die1 - 1 values
int die2 = 1;
while (die2 <= die_two_size) { // seen die2 - 1 values
num_rolls++;
int total = die1 + die2;
if (total == target_value) {
num_successes++;
printf("%d , %d total: %d\n", die1, die2, total);
}
die2++;
}
die1++;
}
int percentage = (100 * num_successes) / num_rolls;
printf("Percentage chance of getting your target number is: %d%%\n ",
percentage);
return 0;
}
Read 43 numbers and then print the sum of the numbers
A simple program demonstrating while & scanf
Note for simplicity we are assuming scanf succeeds in reading an integer.
A robust program would check that scanf returns 1 to indicate an integer read.
#define N_NUMBERS 42
#include <stdio.h>
int main(void) {
int sum = 0;
printf("Enter %d numbers:\n", N_NUMBERS);
int n = 0;
while (n < N_NUMBERS) {
int x;
scanf("%d", &x);
sum = sum + x;
n = n + 1;
}
printf("Sum of the numbers is %d\n", sum);
return 0;
}
Read n numbers and then print the sum of the numbers
A simple program demonstrating while & scanf
Note for simplicity we are assuming scanf succeeds in reading an integer.
A robust program would check that scanf returns 1 to indicate an integer read.
#include <stdio.h>
int main(void) {
int n_numbers;
printf("How many numbers do you wish to sum: ");
scanf("%d", &n_numbers);
printf("Enter %d numbers:\n", n_numbers);
int n = 0;
int sum = 0;
while (n < n_numbers) {
int x;
scanf("%d", &x);
sum = sum + x;
n = n + 1;
}
printf("Sum of the numbers is %d\n", sum);
return 0;
}
A simple program which prints a triangle
#include <stdio.h>
#define SIDE_LENGTH 13
int main(void) {
int size;
printf("Enter size: ");
scanf("%d", &size);
// print `size` lines
int row = 0;
while (row < size) {
// print a row of `row + 1` asterisks
int column = 0;
while (column <= row) {
printf("*");
column = column + 1;
}
// the row is finished, start the next line
printf("\n");
row = row + 1;
}
return 0;
}
A simple program demonstrating nested while loops
It prints all prime numbers < 1000
#define MAX 1000
#include <stdio.h>
int main(void) {
// loop through numbers 1..MAX
int n = 1;
while (n < MAX) {
// loop through numbers 1..n counting factors
int possible_factor = 1;
int n_factors = 0;
while (possible_factor <= n) {
if (n % possible_factor == 0) {
n_factors = n_factors + 1;
}
possible_factor = possible_factor + 1;
}
if (n_factors <= 2) {
printf("%d is prime\n", n);
}
n = n + 1;
}
return 0;
}
IMPORTANT NOTE:
Before reading this code, bear in mind that it's an example of how poor coding style can affect our ability to understand or work with code
#include <stdio.h>
#define constant 7
int main(void) {
int x;int a; int b;int y;
printf("Please enter how many sides are on your dice: ");scanf("%d", &x);
printf("Please enter the value of the first die: ");scanf("%d", &a);
if (a<1) { printf("Die roll value: %d is outside of the range 1 - %d.\n", a, x);
// this bit does the dice thing
a = a % x; if (a == 0) a = x;}
if( a > x) {
printf("Die roll value: %d is outside of the range 1 - %d.\n", a, x);
a = a %x; if (a== 0) a = x;}
printf ("Your roll is: %d\n", a);
printf("Please enter the value of the second die: ");scanf("%d", &b);
if (a < 1 || a > x) {
printf("Die roll value: %d is outside of the range 1 - %d.\n", b, x);b = b % x;
if (b ==0) b = x;
}printf ("Your roll is: %d\n",b);
y = a + b;
printf("Total roll is: %d\n", y);
// can't remember why but don't delete this next line
if (y>constant) {printf("Dice Check Succeeded!\n");} else if(y==constant) {
printf("Dice Check Tied.\n");} else {printf("Dice Check Failed!\n");}}
Simple lecture example of using functions
#include <stdio.h>
double cube(double x);
int main(void) {
printf("42 cubed is %lf\n", cube(42.03));
double a = 2;
double b = cube(a);
printf("2 cubed is %lf\n", b);
return 0;
}
// calculate x to the power of 3
double cube(double x) {
double result;
result = x * x * x;
return result;
}
Lecture example illustrating simple function
#include <stdio.h>
double evaluate_quadratic(double a, double b, double c, double x);
int main(int argc, char *argv[]) {
double x;
printf("Enter x: ");
scanf("%lf", &x);
double value = evaluate_quadratic(2.0, -3.0, 4.0, x);
printf("2x^2 - 3x + 4 = %lf\n", value);
return 0;
}
// given x calculate value of polynomial with coefficients a, b, c
double evaluate_quadratic(double a, double b, double c, double x) {
return (a * x * x) + (b * x) + c;
}
Lecture example illustrating simple function
#include <stdio.h>
#include <math.h>
double quadratic_root(double a, double b, double c);
double evaluate_quadratic(double a, double b, double c, double x);
int main(int argc, char *argv[]) {
double a, b, c;
printf("Enter a: ");
scanf("%lf", &a);
printf("Enter b: ");
scanf("%lf", &b);
printf("Enter c: ");
scanf("%lf", &c);
double root = quadratic_root(a, b, c);
printf("Calculated root is %lf\n", root);
double value = evaluate_quadratic(a, b, c, root);
printf("The value of the quadratic for %lf is %lf\n", root, value);
return 0;
}
double quadratic_root(double a, double b, double c) {
return (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
}
// given x calculate value of polynomial with coefficients a, b, c
double evaluate_quadratic(double a, double b, double c, double x) {
return (a * x * x) + (b * x) + c;
}
#include <stdio.h>
#define NUM_PLAYERS 4
int main(void) {
int scores[NUM_PLAYERS] = { 0 };
// assigning values directly to indexes
scores[0] = 55;
scores[1] = 84;
scores[2] = 32;
scores[3] = 61;
// loop through and display all scores
int i = 0;
while (i < NUM_PLAYERS) {
printf(
"Player %d has scored %d points.\n",
i,
scores[i]
);
i++;
}
// finding the highest score
int highest = 0;
int index_highest = -1;
i = 0;
while (i < NUM_PLAYERS) {
if (scores[i] > highest) {
highest = scores[i];
index_highest = i;
}
i++;
}
printf(
"Player %d has the highest score of %d.\n",
index_highest, highest
);
// finding the total
int total = 0;
while (i < NUM_PLAYERS) {
total += scores[i];
i++;
}
printf("Total points scored across the players is %d\n", total);
return 0;
}
#include <stdio.h>
#define NUM_PLAYERS 4
int main(void) {
int scores[NUM_PLAYERS] = { 0 };
// assigning scores using user input
int i = 0;
while (i < NUM_PLAYERS) {
printf("Please enter Player %d's score: ", i);
scanf("%d", &scores[i]);
i++;
}
// loop through and display all scores
i = 0;
while (i < NUM_PLAYERS) {
printf("Player %d has scored %d points.\n", i, scores[i]);
i++;
}
// finding the highest score
int highest = 0;
int index_highest = -1;
i = 0;
while (i < NUM_PLAYERS) {
if (scores[i] > highest) {
highest = scores[i];
index_highest = i;
}
i++;
}
printf("Player %d has the highest score of %d.\n", index_highest, highest);
// finding the total
int total = 0;
while (i < NUM_PLAYERS) {
total += scores[i];
i++;
}
printf("Total points scored across the players is %d\n", total);
return 0;
}
Read 5 numbers and print them in reverse order - the hard way
#include <stdio.h>
int main(void) {
// This code is inflexible and it won't handle e.g. 10000 numbers
// a much better approach is to use an array
int x0, x1, x2, x3, x4;
printf("Enter 5 numbers: ");
scanf("%d", &x0);
scanf("%d", &x1);
scanf("%d", &x2);
scanf("%d", &x3);
scanf("%d", &x4);
printf("Numbers reversed are:\n");
printf("%d\n", x4);
printf("%d\n", x3);
printf("%d\n", x2);
printf("%d\n", x1);
printf("%d\n", x0);
return 0;
}
Read 5 numbers and print them in reverse order
Note for simplicity we are assuming scanf succeeds in reading an integer.
A robust program would check that scanf returns 1 to indicate an integer read.
#include <stdio.h>
int main(void) {
// Flexible code using an array
int x[5]; // array size should be a #define not `5`
printf("Enter 5 numbers: ");
int i = 0;
while (i < 5) {
scanf("%d", &x[i]);
i = i + 1;
}
printf("Numbers reversed are:\n");
int j = 4;
while (j >= 0) {
printf("%d\n", x[j]);
j = j - 1;
}
return 0;
}
Read 5 numbers and print them in reverse order
#include <stdio.h>
// change this #define to change how many numbers read
#define N_NUMBERS 5
int main(void) {
int x[N_NUMBERS];
printf("Enter %d numbers: ", N_NUMBERS);
int i = 0;
while (i < N_NUMBERS) {
scanf("%d", &x[i]);
i = i + 1;
}
printf("Numbers reversed are:\n");
int j = N_NUMBERS - 1;
while (j >= 0) {
printf("%d\n", x[j]);
j = j - 1;
}
return 0;
}
Read 5 numbers and print them in reverse order
This version checks that the scanf was able to read the number
#include <stdio.h>
#define N_NUMBERS 5
int main(void) {
int x[N_NUMBERS];
printf("Enter %d numbers: ", N_NUMBERS);
int i = 0;
int keep_looping = 1;
while (i < N_NUMBERS && keep_looping) {
// stop loop if scanf doesn't read a number
if (scanf("%d", &x[i]) != 1) {
keep_looping = 0;
} else {
i = i + 1;
}
}
printf("Numbers reversed are:\n");
int j = i - 1;
while (j >= 0) {
printf("%d\n", x[j]);
j = j - 1;
}
return 0;
}
A Tourist Game
Marc Chee (cs1511@cse.unsw.edu.au)
#include <stdio.h>
// The dimensions of the map
#define MAP_ROWS 10
#define MAP_COLUMNS 10
#define EXPLORED 1
#define UNEXPLORED 0
// Helper Function: Print out the map as a 2D grid
void print_map(int map[MAP_ROWS][MAP_COLUMNS], int t_row, int t_column);
int main(void) {
int map[MAP_ROWS][MAP_COLUMNS] = {0};
// Set up tourist roughly in the middle of the map
int tourist_row = MAP_ROWS/2;
int tourist_column = MAP_COLUMNS/2;
print_map(map, tourist_row, tourist_column);
// Looping for multiple "turns"
int keep_looping = 1;
while (keep_looping) {
// Track where we've been
map[tourist_row][tourist_column] = EXPLORED;
printf("Type in 2,4,6 or 8 to move in that num-pad direction: ");
int input = 0;
int input_result = scanf("%d", &input);
if (input_result != 1) {
keep_looping = 0;
} else {
// input was a number
// check which direction to go
if (input == 8) {
// up
tourist_row--;
} else if (input == 6) {
// right
tourist_column++;
} else if (input == 4) {
// left
tourist_column--;
} else if (input == 2) {
// down
tourist_row++;
} else {
// invalid or any other number
keep_looping = 0;
}
}
// Check if we've gone off the map
// Clamp to legal map positions
if (tourist_row < 0) {
// top
tourist_row = 0;
} else if (tourist_row >= MAP_ROWS) {
// bottom
tourist_row = MAP_ROWS - 1;
} else if (tourist_column < 0) {
// left
tourist_column = 0;
} else if (tourist_column >= MAP_COLUMNS) {
// right
tourist_column = MAP_COLUMNS - 1;
}
print_map(map, tourist_row, tourist_column);
// check to see if current location was already explored
if (map[tourist_row][tourist_column] == EXPLORED) {
printf("I have already been here, HOW BORING!\n");
keep_looping = 0;
}
}
return 0;
}
// Prints the map, by printing the integer value stored in
// each element of the 2-dimensional map array.
// Prints a T instead at the position t_row, t_col
void print_map(int map[MAP_ROWS][MAP_COLUMNS], int t_row, int t_column) {
int row = 0;
while (row < MAP_ROWS) {
int column = 0;
while (column < MAP_COLUMNS) {
if(t_row == row && t_column == column) {
printf("T ");
} else {
printf("%d ", map[row][column]);
}
column++;
}
row++;
printf("\n");
}
}
a memory address as hexadecimal
#include <stdio.h>
int main(void) {
int i = 100;
// create a pointer called ip
int *ip ;
// make it point at i
ip = &i;
// prints something like this:
// address of x in hexadecimal is 0x7fff51155000
printf("address of x in hexadecimal is %p\n", (void *)ip);
return 0;
}
Some examples of using pointers
#include <stdio.h>
void increment_int(int n);
void increment_ptr(int *n);
int main(void) {
int i = 100;
// create a pointer called ip that points at i
// it stores the address of i
int *ip = &i;
increment_int(i);
printf("i, %d, hasn't changed.\n", i);
increment_ptr(ip);
printf("i, %d, has now changed.\n", i);
return 0;
}
// This function will have no effect!
// It only modifies it's own variable `n`,
void increment_int(int n) {
n = n + 1;
}
// This function will affect whatever n is pointing at
void increment_ptr(int *n) {
*n = *n + 1;
}
Simple example of using pointer to pass reference to variables
#include <stdio.h>
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(int argc, char *argv[]) {
int x = 42;
int y = 13;
printf("x=%d y=%d\n", x, y);
swap(&x, &y);
printf("x=%d y=%d\n", x, y);
return 0;
}
A program that scans input of a series of numbers and stores them in an array.
It then shuffles the order of those numbers and prints them back out.
A demo on using functions and pointers
#include <stdio.h>
#define MAX_CARDS 1024
int read_input(int deck[MAX_CARDS]);
void print_deck(int deck[MAX_CARDS], int length);
void swap_nums(int *num1, int *num2);
void shuffle(int deck[MAX_CARDS], int length);
int main(void) {
int deck[MAX_CARDS] = {0};
int num_cards = read_input(deck);
shuffle(deck, num_cards);
print_deck(deck, num_cards);
}
// Asks the user how many cards are in their deck
// Then reads that many cards (or MAX_CARDS if the user says too many)
// Returns how many cards were read in
int read_input(int deck[MAX_CARDS]) {
// scan in the number of cards
int num_cards;
printf("How many cards are in your deck?\n");
scanf("%d", &num_cards);
// loop through the deck, writing in the numbers that user types in
int i = 0;
while (i < num_cards && i < MAX_CARDS) { // have read i cards
scanf("%d", &deck[i]);
i++;
} // have read i cards
return i;
}
// Prints out the first 'length' elements from the deck array
void print_deck(int deck[MAX_CARDS], int length) {
int i = 0;
while (i < length && i < MAX_CARDS) {
printf("%d, ", deck[i]);
i++;
}
printf("\n");
}
// Swaps the integers at the destinations of the pointers num1 and num2
void swap_nums(int *num1, int *num2) {
int temp = *num1;
*num1 = *num2;
*num2 = temp;
}
// call swap multiple times on different pairs to shuffle the deck
void shuffle(int deck[MAX_CARDS], int length) {
int i = 0;
while (i < length) {
// find another index to swap with
int j = (i * 3) % length;
swap_nums(&deck[i], &deck[j]);
i++;
}
}
Simple example illustrating use of pointers to pass 3 values back from a function
#include <stdio.h>
void powers(double x, double *square, double *cube, double *fourth_power);
int main(void) {
double s, c, f;
powers(42, &s, &c, &f);
printf("42^2 = %lf\n", s);
printf("42^3 = %lf\n", c);
printf("42^4 = %lf\n", f);
return 0;
}
// given a number calculate sis 2nd third and 4th powers
void powers(double x, double *square, double *cube, double *fourth_power) {
*square = x * x;
*cube = x * x * x;
*fourth_power = x * x * x * x;
}
Some examples of using pointers
#include <stdio.h>
#define LENGTH 6
void print_fixed_size_array(int array[LENGTH]);
void print_any_size_array(int size, int array[size]);
void print_array_until_marker(int array[]);
int main(void) {
int a[LENGTH] = { 1, 2, 4, 8, 16, 32 };
print_fixed_size_array(a);
print_any_size_array(LENGTH, a);
int b[LENGTH + 1] = { 1, 2, 4, 8, 16, 32, -1 };
print_array_until_marker(b);
return 0;
}
// print an array containing LENGTH elements
void print_fixed_size_array(int array[LENGTH]) {
int i = 0;
while (i < LENGTH) {
printf("%d\n", array[i]);
i++;
}
}
// print size elements of array
void print_any_size_array(int size, int array[size]) {
int i = 0;
while (i < size) {
printf("%d\n", array[i]);
i++;
}
}
// print array elements until element containing -1 reached
void print_array_until_marker(int array[]) {
int i = 0;
while (array[i] != -1) {
printf("%d\n", array[i]);
i++;
}
}
#include <stdio.h>
void count_big(int length, int nums[length], int *big_positive, int *big_negative);
#define SIZE 7
int main(void) {
int array[SIZE] = {3, -4004, 110, 500, -6, 111, -3};
int big_p;
int big_n;
count_big(SIZE, array, &big_p, &big_n);
printf("big negative=%d big positive=%d\n", big_n, big_p);
return 0;
}
// Count the big positive and big negative values in the array nums.
// A value is big is < -100 or > 1000
// Counts are stored in the variables
// that big_positive & big_negative point to
void count_big(int length, int nums[length],
int *big_positive, int *big_negative) {
int big_pos = 0;
int big_neg = 0;
int i = 0;
while (i < length) {
if (nums[i] < -100) {
big_neg++;
} else if (nums[i] > 100) {
big_pos++;
}
i++;
}
// store counts in the variables that
// big_positive & big_negative point to
*big_positive = big_pos;
*big_negative = big_neg;
}
Print the printable ASCII characters
#include <stdio.h>
int main(void) {
int ascii = 33;
while (ascii < 127) {
printf("In ASCII %d prints as %c\n", ascii, ascii);
ascii = ascii + 1;
}
return 0;
}
Read characters until eof
#include <stdio.h>
int main(void) {
// getchar returns an int which will contain either
// the ASCII code of the character read or EOF
int ch = getchar();
while (ch != EOF) {
printf("'%c' read, ASCII code is %d\n", ch, ch);
ch = getchar();
}
return 0;
}
Read characters until eof, printing them with lower case letters convert to upper case
#include <stdio.h>
int make_upper_case(int character);
int main(void) {
// getchar returns an int which will contain either
// the ASCII code of the character read or EOF
int character = getchar();
while (character != EOF) {
int new_character = make_upper_case(character);
putchar(new_character);
character = getchar();
}
return 0;
}
// return upper case letter corresponding to lower case letter
// e.g. given 'f' return 'F'
// other characters returned unchanged
//
// library function toupper() in <ctype.h> does this task
int make_upper_case(int character) {
if (character >= 'a' && character <= 'z') {
int alphabetPosition = character - 'a';
return 'A' + alphabetPosition;
} else {
return character;
}
}
Print "Andrew Rocks!" - using ASCII codes for the characters
Compare the 8 andrew_rocks?.c programs which are all equivalent to get a better understanding of how & why C encodes character sequences
#include <stdio.h>
int main(void) {
// DO NOT PUT ASCII CODES IN YOUR PROGRAM LIKE THIS
putchar(65); // printf("%c", 65) is equivalent
putchar(110);
putchar(100);
putchar(114);
putchar(101);
putchar(119);
putchar(32);
putchar(82);
putchar(111);
putchar(99);
putchar(107);
putchar(115);
putchar(33);
putchar(10);
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters
'A' is the C shorthand for the ASCII code for the character A (65)
#include <stdio.h>
int main(void) {
putchar('A'); // equivalent to putchar(65) but readable!
putchar('n');
putchar('d');
putchar('r');
putchar('e');
putchar('w');
putchar(' ');
putchar('R');
putchar('o');
putchar('c');
putchar('k');
putchar('s');
putchar('\n');
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, store them in array, and print the array. Note we have to track the array length.
#include <stdio.h>
int main(void) {
int asciiCodes[14];
asciiCodes[0] = 'A';
asciiCodes[1] = 'n';
asciiCodes[2] = 'd';
asciiCodes[3] = 'r';
asciiCodes[4] = 'e';
asciiCodes[5] = 'w';
asciiCodes[6] = ' ';
asciiCodes[7] = 'R';
asciiCodes[8] = 'o';
asciiCodes[9] = 'c';
asciiCodes[10] = 'k';
asciiCodes[11] = 's';
asciiCodes[12] = '!';
asciiCodes[13] = '\n';
int i = 0;
while (i < 14) {
putchar(asciiCodes[i]);
i = i + 1;
}
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, initialize an array to the values , and print the array.
Note we have to track the array length.
#include <stdio.h>
int main(void) {
// we can put all the ASCII codes in array and
// then print every array element
// we need to track the array size (should be a #define)
int ascii_codes[14] = { 'A', 'n', 'd', 'r', 'e', 'w', ' ',
'R', 'o', 'c', 'k', 's', '!', '\n' };
int i = 0;
while (i < 14) {
putchar(ascii_codes[i]);
i = i + 1;
}
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, and initialize the array to the vales array using , and print the array.
This version has a extra special value in the array (0) to indicate the end of the sequence. This means we no longer have to keep track of how many characters in the array (note the while loop condition)
#include <stdio.h>
int main(void) {
// we can put all the ASCII codes in array
// if we put a special value (0) as last array element
// We don't need to track the array size which is more convenient.
// We don't specify the size of an array being initialized so
// C makes it big enough to hold all the v (15 in this case)
int ascii_codes[] = { 'A', 'n', 'd', 'r', 'e', 'w', ' ', 'R',
'o', 'c', 'k', 's', '!', '\n', 0 };
int i = 0;
while (ascii_codes[i] != 0) {
putchar(ascii_codes[i]);
i = i + 1;
}
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, and initialize the array to the vales array using , and print the array.
This version has switched to using the numeric type char. This type is almost always 8 bits and shouldn't be used for arithmetic. It is commonly used to hold ASCII encodings.
#include <stdio.h>
int main(void) {
// same as last version except use a char array
char ascii_codes[] = {'A', 'n', 'd', 'r', 'e', 'w', ' ',
'R', 'o', 'c', 'k', 's', '!', '\n', 0};
int i = 0;
while (ascii_codes[i] != 0) {
putchar(ascii_codes[i]);
i = i + 1;
}
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, and initialize the array to the vales array using , and print the array.
C has a convenient shorthand for char arrays containing a sequence of
ASCII codes with an extra 0 value marking the end of the sequence.
Its "Andrew Rocks!";
Compare the 8 andrew_rocks?.c programs which are all equivalent to get a better understand of how & why C encodes character sequences
#include <stdio.h>
int main(void) {
// C has a shorthand for char arrays containing a sequence of
// ASCII codes with an extra 0 value marking the end
// Its "Andrew Rocks!";
char ascii_codes[] = "Andrew Rocks!\n";
int i = 0;
while (ascii_codes[i] != 0) {
putchar(ascii_codes[i]);
i = i + 1;
}
return 0;
}
Print "Andrew Rocks!" - using character constants to get the ASCII codes for the characters, and initialize the array to the vales array using , and print the array.
C has a convenient shorthand for char arrays containing a sequence of
ASCII codes with an extra 0 value marking the end of the sequence.
Its "Andrew Rocks!";
A number of C library functions accept zero-terminated char arrays
For example printf with the "%s" specification (below)
#include <stdio.h>
int main(void) {
char asciiCodes[] = "Andrew Rocks!\n";
// Many C library functions work with zero-terminated char arrays
// puts prints a zero-terminated char array
fputs(asciiCodes, stdout);
// printf "%s" also prints a zero-terminated char array
printf("%s", asciiCodes);
return 0;
}
print command line argument
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("argc = %d\n", argc);
printf("My name is %s\n", argv[0]);
// print command line arguments
int i = 1;
while (i < argc) {
printf("Argument %d is: %s\n", i, argv[i]);
i = i + 1;
}
return 0;
}
Convert command-line arguments to integers and print their sum.
No check is made that the command-line arguments are actually integers.
See strtol for a more powerful library function which would allow checking.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int sum = 0;
int argument = 1;
while (argument < argc) {
// convert string to integer
int n = atoi(argv[argument]);
// you could use `strtol` instead of `atoi` like this
// int n = strtol(argv[argument], NULL, 10);
sum = sum + n;
argument= argument + 1;
}
printf("Total is %d\n", sum);
return 0;
}
Reads lines of input until end-of-input
Print snap! if two consecutive lines are identical
See snap_line1.c for how to use functions to produce simpler code
#include <stdio.h>
#define MAX_LINE 4096
int main(int argc, char *argv[]) {
char line[MAX_LINE];
char last_line[MAX_LINE];
printf("Enter line: ");
fgets(last_line, MAX_LINE, stdin);
printf("Enter line: ");
while (fgets(line, MAX_LINE, stdin) != NULL) {
// DOES NOT WORK - arrays can not be compared
if (line == last_line) {
// lines are identical
printf("Snap!\n");
}
// DOES NOT WORK - arrays can not be assigned
last_line = line;
printf("Enter line: ");
}
return 0;
}
Reads lines of input until end-of-input
Print snap! if two consecutive lines are identical
See snap_line2.c to see how to replace compare_arrays & copy_array calls to with (strcmp & strcpy) from <string.h>
#include <stdio.h>
#define MAX_LINE 4096
int compare_arrays(char array1[], char array2[]);
void copy_array(char destination_array[], char source_array[]);
int main(int argc, char *argv[]) {
char line[MAX_LINE];
char last_line[MAX_LINE];
// read first line into array last_line
printf("Enter line: ");
fgets(last_line, MAX_LINE, stdin);
printf("Enter line: ");
while (fgets(line, MAX_LINE, stdin) != NULL) {
if (compare_arrays(line, last_line) == 0) {
// lines are identical
printf("Snap!\n");
}
copy_array(last_line, line);
printf("Enter line: ");
}
return 0;
}
// return 1 if array1 & array2 differ in any element, 0 otherwise
// array1 & array2 must be null-terminated char arrays
// strcmp from <string.h> performs similar function
int compare_arrays(char array1[], char array2[]) {
int i = 0;
while (array1[i] != '\0') {
if (array1[i] != array2[i]) {
return 1;
}
i = i + 1;
}
if (array2[i] == '\0') {
return 0;
} else {
return 1;
}
}
// copy elements in source_array to destination_array
// source_array must be a null-terminated char array
// destination_array must be large enough to hold string
// strcpy from <string.h> performs the same function
void copy_array(char destination_array[], char source_array[]) {
int i = 0;
while (source_array[i] != '\0') {
destination_array[i] = source_array[i];
i = i + 1;
}
destination_array[i] = '\0';
}
Reads lines of input until end-of-input
Print snap! if two consecutive lines are identical
#include <stdio.h>
#include <string.h>
#define MAX_LINE 4096
int main(int argc, char *argv[]) {
char line[MAX_LINE];
char lastLine[MAX_LINE];
// read first line into array lastLine
printf("Enter line: ");
fgets(lastLine, MAX_LINE, stdin);
printf("Enter line: ");
while (fgets(line, MAX_LINE, stdin) != NULL) {
if (strcmp(line, lastLine) == 0) {
// lines are identical
printf("Snap!\n");
}
strncpy(lastLine, line, MAX_LINE);
printf("Enter line: ");
}
return 0;
}
simple example of using malloc to create an array
containing n odd numbers
#include <stdio.h>
#include <stdlib.h>
int *create_odd_array(int n);
int main(void) {
int n_odd_numbers = 10;
int *ptr = create_odd_array(n_odd_numbers);
int j = 0;
while (j < n_odd_numbers) {
printf("%d\n", ptr[j]);
j = j + 1;
}
// free the allocated memory
free(ptr);
return 0;
}
// create an array containing first n odd numbers
int *create_odd_array(int n) {
int *odd_ptr = malloc(n * sizeof (int));
int i = 0;
while (i < n) {
odd_ptr[i] = 2 * i + 1;
i = i + 1;
}
return odd_ptr;
}
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 100
struct bender {
char name[MAX_LENGTH];
char element[MAX_LENGTH];
int power;
};
int main(void) {
// create a struct variable
struct bender avatar;
// use . to access the field of a struct
avatar.power = 10;
strcpy(avatar.name, "Aang");
strcpy(avatar.element, "Air");
printf("%s's element is: %s.\n", avatar.name, avatar.element);
return 0;
}
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 100
struct bender {
char name[MAX_LENGTH];
char element[MAX_LENGTH];
int power;
};
void display_person(struct bender *person);
int main(void) {
// create a struct variable
struct bender avatar;
// create a pointer to the struct variable
struct bender *andrew = &avatar;
// given a pointer to a struct
// use can use . and * to access
(*andrew).power = 100;
// but there is a better way
// -> dereferences the pointer and
// accesses a field inside the struct:
andrew->power = 100;
strcpy(andrew->name, "Andrew");
strcpy(andrew->element, "Code");
display_person(andrew);
return 0;
}
void display_person(struct bender *person) {
printf("Name: %s\n", person->name);
printf("Element: %s\n", person->element);
printf("Power: %d\n", person->power);
}
Bender Team
A demonstration of structs and memory allocation using Element Benders as an example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LENGTH 100
#define TEAM_SIZE 4
// Structures
struct bender {
char name[MAX_LENGTH];
char element[MAX_LENGTH];
int power;
};
struct team {
char name[MAX_LENGTH];
int team_size;
struct bender *team_members[TEAM_SIZE];
};
// Functions
struct bender *create_bender(char *b_name, char *b_element, int b_power);
void print_team(struct team *print_team);
void free_team(struct team *f_team);
int main(void) {
struct team *companions = malloc(sizeof(struct team));
strcpy(companions->name, "My Cabbages!");
companions->team_size = 0;
companions->team_members[companions->team_size] =
create_bender("Aang", "Air", 10);
companions->team_size++;
companions->team_members[companions->team_size] =
create_bender("Katara", "Water", 6);
companions->team_size++;
print_team(companions);
free_team(companions);
}
// Allocate memory for a bender, populate it with
// the given information, then return a pointer
// to the allocated memory location
struct bender *create_bender(char *b_name, char *b_element, int b_power) {
struct bender *new_bender = malloc(sizeof(struct bender));
strcpy(new_bender->name, b_name);
strcpy(new_bender->element, b_element);
new_bender->power = b_power;
return new_bender;
}
// print_team will print out the details of the team members
// to the terminal. It will not change the team.
void print_team(struct team *print_team) {
printf("Team name is %s\n", print_team->name);
int i = 0;
while (i < print_team->team_size) {
printf("Team member %s uses the element: %s\n",
print_team->team_members[i]->name,
print_team->team_members[i]->element);
i++;
}
}
// Free all structs (from the team level)
void free_team(struct team *f_team) {
// free all the allocations (bender structs) the team points at
int i = 0;
while (i < f_team->team_size) {
free(f_team->team_members[i]);
i++;
}
// then free the team struct itself
free(f_team);
}
A demo of a basic linked list
#include <stdlib.h>
#include <stdio.h>
struct node {
int data;
struct node *next;
};
struct node *create_node(int data, struct node *next);
void print_data(struct node *n);
int main(void) {
// head will always point to the first element of our list
struct node *head = create_node(5, NULL);
head = create_node(4, head);
head = create_node(3, head);
head = create_node(2, head);
head = create_node(1, head);
print_data(head);
return 0;
}
// Create a node using the data and next pointer provided
// Return a pointer to this node
struct node *create_node(int data, struct node *next) {
struct node *n;
n = malloc(sizeof(struct node));
n->data = data;
n->next = next;
return n;
}
// Loop through a list of nodes, printing out their data
void print_data(struct node *n) {
while (n != NULL) { // have printed from list's head up to just before n
printf("%d\n", n->data);
n = n->next;
}
}
Battle Royale A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_NAME_LENGTH 100
// Structs
struct player {
struct player *next;
char name[MAX_NAME_LENGTH];
};
// Functions
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next);
void print_players(struct player *head);
int main(void) {
struct player *head = create_player("Marc", NULL);
head = create_player("Chicken", head);
head = create_player("Shrey", head);
head = create_player("Anusha", head);
print_players(head);
}
// Allocate memory for a player node
// Populate that node with new_name and new_next
// Return a pointer to the allocated memory
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next) {
struct player *new_player = malloc(sizeof (struct player));
new_player->next = new_next;
strcpy(new_player->name, new_name);
return new_player;
}
// Takes the head of the list
// Prints out everyone who is in the list
void print_players(struct player *head) {
struct player *current = head;
while (current != NULL) { // I'm looking at a valid player
printf("%s\n", current->name);
current = current->next;
}
}
/* Battle Royale - Header File
A linked list example that tracks players in a game.
We want to be able to maintain the list
as well as remove players as they are knocked out.
We also want to be able to display who is currently
still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
*/
#define MAX_NAME_LENGTH 100
// Create a player by allocating memory,
// populating their data then returning a pointer to them
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next);
// Loop through and display the players
// One per line in the terminal
void print_players(struct player *head);
// Insert into a list alphabetically
// Returns the head of the list (even if it has changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]);
Battle Royale - Main File A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include "battle_royale.h"
int main(void) {
struct player *head = NULL;
head = insert_alpha(head, "Marc");
print_players(head);
printf("-----\n");
head = insert_alpha(head, "Chicken");
print_players(head);
printf("-----\n");
head = insert_alpha(head, "Goku");
print_players(head);
}
Battle Royale - Implementation File A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "battle_royale.h"
// Structs
struct player {
struct player *next;
char name[MAX_NAME_LENGTH];
};
// Allocate memory for a player node
// Populate that node with new_name and new_next
// Return a pointer to the allocated memory
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next) {
struct player *new_player = malloc(sizeof (struct player));
new_player->next = new_next;
strcpy(new_player->name, new_name);
return new_player;
}
// Takes the head of the list
// Prints out everyone who is in the list
void print_players(struct player *head) {
struct player *current = head;
while (current != NULL) { // I'm looking at a valid player
printf("%s\n", current->name);
current = current->next;
}
}
// Inserts into a list (head) alphabetically.
// Assumes the list is already in alphabetical order
// Returns the head of the list (it may have changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]) {
// loop through and find the insertion point
struct player *current = head;
struct player *previous = NULL;
while (current != NULL && strcmp(current->name, new_name) < 0) {
// go past any names that are earlier than us alphabetically
previous = current;
current = current->next;
} // current is now the first player in the list with a name "higher or equal"
// than new_name
// previous is now the last player in the list with a name "lower"
// than new_name
if (previous == NULL) {
// Inserting at the head of a list
// also works for an empty list (head == NULL)
head = create_player(new_name, head);
} else {
// Inserting further down the list
previous->next = create_player(new_name, previous->next);
}
return head;
}
/* Battle Royale - Header File
A linked list example that tracks players in a game.
We want to be able to maintain the list
as well as remove players as they are knocked out.
We also want to be able to display who is currently
still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
*/
#define MAX_NAME_LENGTH 100
// Create a player by allocating memory,
// populating their data then returning a pointer to them
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next);
// Loop through and display the players
// One per line in the terminal
// Returns the number of players that it printed out
int print_players(struct player *head);
// Insert into a list alphabetically
// Returns the head of the list (even if it has changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]);
// Find the player that matches rem_name in the list starting at head
// Remove and free that player, return the head (it may have changed)
struct player *remove_player(struct player *head, char rem_name[MAX_NAME_LENGTH]);
// Ask for input from the user to remove a player.
// Return the head of the list (it may have changed)
struct player *remove_by_name(struct player *head);
// Free all the players in the given list
void free_list(struct player *head);
Battle Royale - Main File A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include "battle_royale.h"
int main(void) {
struct player *head = NULL;
head = insert_alpha(head, "Shrey");
head = insert_alpha(head, "Anosua");
head = insert_alpha(head, "Zoe");
head = insert_alpha(head, "Alvin");
head = insert_alpha(head, "Tom");
head = insert_alpha(head, "Andrew");
while (print_players(head) > 1) {
head = remove_by_name(head);
printf("----------\n");
}
printf("is the winner!\n");
free_list(head);
}
Battle Royale - Implementation File A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "battle_royale.h"
// Structs
struct player {
struct player *next;
char name[MAX_NAME_LENGTH];
};
// Allocate memory for a player node
// Populate that node with new_name and new_next
// Return a pointer to the allocated memory
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next) {
struct player *new_player = malloc(sizeof (struct player));
new_player->next = new_next;
strcpy(new_player->name, new_name);
return new_player;
}
// Takes the head of the list
// Prints out everyone who is in the list
int print_players(struct player *head) {
struct player *current = head;
int num_players = 0;
while (current != NULL) { // I'm looking at a valid player
printf("%s\n", current->name);
num_players++;
current = current->next;
}
return num_players;
}
// Inserts into a list (head) alphabetically.
// Assumes the list is already in alphabetical order
// Returns the head of the list (it may have changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]) {
// loop through and find the insertion point
struct player *current = head;
struct player *previous = NULL;
while (current != NULL && strcmp(current->name, new_name) < 0) {
// go past any names that are earlier than us alphabetically
previous = current;
current = current->next;
} // current is now the first player in the list with a name "higher or equal"
// than new_name
// previous is now the last player in the list with a name "lower"
// than new_name
if (previous == NULL) {
// Inserting at the head of a list
// also works for an empty list (head == NULL)
head = create_player(new_name, head);
} else {
// Inserting further down the list
previous->next = create_player(new_name, previous->next);
}
return head;
}
// Loop through list looking for a match of
// player's name to rem_name
// Remove and free that node (if it exists)
// Return the possibly-changed head of the list
// Note: head only changes if we remove the first player
struct player *remove_player(struct player *head,
char rem_name[MAX_NAME_LENGTH]) {
// Loop through and stop with curr->name == rem_name
struct player *curr = head;
struct player *prev = NULL;
while (curr != NULL && strcmp(rem_name, curr->name) != 0) {
prev = curr;
curr = curr->next;
}
if (curr != NULL) {
// curr now points at a player whose name matches rem_name
if (prev == NULL) { // (head == curr) also works
// removing the head of the list
head = curr->next;
} else {
// removing an element somewhere other than the head
prev->next = curr->next;
}
free(curr);
}
// or curr is NULL if it has reached the end of the list
return head;
}
// Ask the user for a player's name to remove.
// Remove that node and return the head of the list (may have changed)
struct player *remove_by_name(struct player *head) {
printf("Who's just been knocked out?\n");
char input[MAX_NAME_LENGTH];
fgets(input, MAX_NAME_LENGTH, stdin);
// fgets will store the \n that we type in in the input string
// if we find a \n at the end of input, remove it from the string
if (input[strlen(input) - 1] == '\n') {
input[strlen(input) - 1] = '\0';
}
head = remove_player(head, input);
return head;
}
// Free all elements of the list starting at head
void free_list(struct player *head) {
struct player *curr = head;
while (curr != NULL) {
struct player *free_node = curr;
curr = curr->next;
free(free_node);
}
}
// .h files sometimes include other .h files
// Sometimes because they need something in that filects
// Sometimes just for convenience
#include <stdio.h>
// prototypes of functions called from a different .c file
// should have a prototype in a .h file
// This .h file should be included in the file the function is defined
// and in every file where the function is called
int answer(double x);
// often #defines are used in multiple files
// if so they should be placed in a .h file
#define ANSWER 42
// often types are used in multiple files
// if so the typedefs should be placed in a .h file
typedef int answer_t;
// function definitions (code) should never be placed
// in a .h file, always a .c file
Simple example of a multi-file program, compile like this: dcc print_answer.c answer.c -o answer
#include "answer.h"
int main(void) {
int i = answer(2);
printf("%d\n", i);
return 0;
}
// First look at multi-file projects
//
// Marc Chee (cs1511@cse.unsw.edu.au), October 2020
//
// A header file like this contains information about a some code.
// It's usually enough to read this to be able to use the code
// without needing to actually delve into the C file.
#define MAX_NAME_LENGTH 50
#define MAX_POWER_LENGTH 50
#define MAX_NUM_POWERS 5
// This typedef declares that the type "Person" is the same as the type
// "pointer to struct person".
// The actual definition of "struct person" is not in person.h (this
// file), it's in person.c
// This means that you cannot directly access any of the fields of the
// person struct -- e.g. "person->name" is invalid.
typedef struct person *Person;
// Create a person and return a pointer to them
Person create_person(char name[MAX_NAME_LENGTH]);
// free_person frees any memory used for a person
void free_person(Person hero);
// give_power will add a power to a person
// It will add the string to the array of strings
// called powers if the person still has
// space to add powers
void give_power(char power[MAX_POWER_LENGTH], Person hero);
// Displays a person's information
void display_person(Person hero);
First look at multi-file projects
Marc Chee (cs1511@cse.unsw.edu.au)
This demo shows how we include a header file so that we can use its functionality in our main here compile like this: dcc batman.c person.c -o batman
#include "person.h"
int main(void) {
Person batman = create_person("Batman");
display_person(batman);
give_power("Ninjitsu", batman);
give_power("Tech gadgets", batman);
give_power("Brooding", batman);
give_power("Gravelly Christian Bale Voice", batman);
display_person(batman);
// Free our memory now that we're not going to use it
free_person(batman);
}
First look at multi-file projects
Implementation of the person that is declared in person.h
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "person.h"
struct person {
char name[MAX_NAME_LENGTH];
char powers[MAX_NUM_POWERS][MAX_POWER_LENGTH];
int num_powers;
};
// allocate memory for a struct person,
// initialise information
// and return the pointer to the memory
Person create_person(char name[MAX_NAME_LENGTH]) {
Person hero = malloc(sizeof (struct person));
strcpy(hero->name, name);
hero->num_powers = 0;
return hero;
}
void free_person(Person hero) {
free(hero);
}
// Add a power.
// Do nothing if the person already has MAX_NUM_POWERS powers
void give_power(char power[MAX_POWER_LENGTH], struct person *hero) {
if (hero->num_powers < MAX_NUM_POWERS) {
strcpy(hero->powers[hero->num_powers], power);
hero->num_powers++;
}
}
// print out information about the person
void display_person(struct person *hero) {
printf("Name: %s\n", hero->name);
printf("Powers:\n");
int i = 0;
while(i < hero->num_powers) {
fputs(hero->powers[i], stdout);
putchar('\n');
i++;
}
printf("----------\n");
}
// Abstract Data Type Stack demo
// Marc Chee, April 2021
// This file describes the interface to a stack of ints
// It must be included in other code files to be of use
// ======================================================
// The type "Stack" refers to a stack_internals pointer.
// In other files, programs can use Stack, but they will
// not get direct access to the stack's internal workings
// nor will they know exactly what they are
// ======================================================
// These functions are the only way external code can
// manipulate a stack.
// Stack type hides the struct that it is implemented as
typedef struct stack_internals *Stack;
// functions to create and destroy stacks
Stack stack_create();
void stack_free(Stack s);
// Add and remove items from stacks
// Removing the item returns the item for use
void stack_push(Stack s, int item);
int stack_pop(Stack s);
// Check on the size of the stack
int stack_size(Stack s);
Abstract Data Types Demo
Using a stack
#include <stdio.h>
#include "stack.h"
int main(void) {
Stack deck = stack_create();
int card = 42;
printf("Pushing %d on top of the deck.\n", card);
stack_push(deck, card);
card = 37;
printf("Pushing %d on top of the deck.\n", card);
stack_push(deck, card);
card = 13;
printf("Pushing %d on top of the deck.\n", card);
stack_push(deck, card);
printf("Taking %d off the top of the deck.\n", stack_pop(deck));
printf("Taking %d off the top of the deck.\n", stack_pop(deck));
printf("Taking %d off the top of the deck.\n", stack_pop(deck));
}
Linked List implementation of a Stack
#include "stack.h"
#include <stdlib.h>
#include <stdio.h>
struct stack_internals {
struct stack_node *head;
};
struct stack_node {
struct stack_node *next;
int data;
};
// Create the stack, intially empty
Stack stack_create() {
Stack new_stack = malloc(sizeof (struct stack_internals));
new_stack->head = NULL;
return new_stack;
}
// Add an element to the top of the stack
// The top of the stack is the head of the linked list
void stack_push(Stack s, int item) {
struct stack_node *new_node = malloc(sizeof (struct stack_node));
new_node->next = s->head;
new_node->data = item;
s->head = new_node;
}
// Remove the head (top of the stack) of the list
// return the value that was stored there
int stack_pop(Stack s) {
// Is the stack empty?
if (s->head == NULL) {
printf("Cannot pop from an empty stack.\n");
exit(1);
}
// retrieve data from the top of the stack
int data = s->head->data;
// remove the head of the stack
struct stack_node *rem_node = s->head;
s->head = s->head->next;
free(rem_node);
return data;
}
Array Implementation of a Stack
#include "stack.h"
#include <stdlib.h>
#include <stdio.h>
#define MAX_STACK_SIZE 1024
struct stack_internals {
int stack_data[MAX_STACK_SIZE];
int top;
};
// Create the stack, starting empty
Stack stack_create() {
struct stack_internals *new_stack = malloc(sizeof (struct stack_internals));
new_stack->top = 0;
return new_stack;
}
// Add an item to the top of the stack (at the index top)
void stack_push(Stack s, int item) {
if (s->top >= MAX_STACK_SIZE) {
// we have run out of space for our stack
printf("Maximum stack has overflowed, cannot push.\n");
exit(2);
}
s->stack_data[s->top] = item;
s->top++;
}
// Pop an item by reading the item in index top-1
// Move the top down one.
int stack_pop(Stack s) {
if (s->top <= 0) {
// No elements in the stack
printf("Cannot pop from an empty stack.\n");
exit(1);
}
s->top--;
return s->stack_data[s->top];
}
A list of 10 items is created with create_list summed with sum_list and then freed
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
int data;
};
struct node *create_list(int start, int finish);
int sum_list(struct node *head);
void free_list(struct node *head);
int main(int argc, char *argv[]) {
// creates a list containing 10 integers 11..20
struct node *head = create_list(11, 20);
int sum = sum_list(head);
printf("%d\n", sum); // prints 155
free_list(head);
return 0;
}
// return sum of data fields of list
int sum_list(struct node *head) {
struct node *n = head;
int total = 0;
while (n != NULL) {
total += n->data;
n = n->next;
}
return total;
}
// free all the node in a list
void free_list(struct node *head) {
struct node *p = head;
while (p != NULL) {
struct node *next_node = p->next;
free(p);
p = next_node;
}
}
// create a list of the integers start..finish
// return pointer to head
struct node *create_list(int start, int finish) {
struct node *head = NULL;
// create list starting from last node
int i = finish;
while (i >= start) {
struct node *new_node = malloc(sizeof (struct node));
new_node->data = i;
new_node->next = head;
head = new_node;
i--;
}
return head;
}
A list of 10 items is created with create_list summed with sum_list and then freed
recursive version of sum_list, free_list and create_list
#include <stdio.h>
#include <stdlib.h>
struct node {
struct node *next;
int data;
};
struct node *create_list(int start, int finish);
int sum_list(struct node *head);
void free_list(struct node *head);
int main(int argc, char *argv[]) {
// creates a list containing 10 integers 11..20
struct node *head = create_list(11, 20);
int sum = sum_list(head);
printf("%d\n", sum); // prints 155
free_list(head);
return 0;
}
// return sum of data fields of list
int sum_list(struct node *head) {
if (head == NULL) {
return 0;
} else {
return head->data + sum_list(head->next);
}
}
// free all the node in a list
void free_list(struct node *head) {
if (head != NULL) {
free_list(head->next);
free(head);
}
}
// create a list of the integers start..finish
// return pointer to head
struct node *create_list(int start, int finish) {
if (start > finish) {
return NULL;
} else {
struct node *new_node = malloc(sizeof (struct node));
new_node->data = start;
new_node->next = create_list(start + 1, finish);
return new_node;
}
}
/* Battle Royale - Header File
A linked list example that tracks players in a game.
We want to be able to maintain the list
as well as remove players as they are knocked out.
We also want to be able to display who is currently
still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
*/
#define MAX_NAME_LENGTH 100
// Create a player by allocating memory,
// populating their data then returning a pointer to them
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next);
// Loop through and display the players
// One per line in the terminal
// Returns the number of players that it printed out
int print_players(struct player *head);
// Print out the names stored in the list in reverse order
// This is a procedural programming implementation
void reverse_print(struct player *player_list);
// Print out the names stored in the list in reverse order
// This is a recursive programming implementation
void rev_print_rec(struct player *player_list);
// Insert into a list alphabetically
// Returns the head of the list (even if it has changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]);
// Find the player that matches rem_name in the list starting at head
// Remove and free that player, return the head (it may have changed)
struct player *remove_player(struct player *head, char rem_name[MAX_NAME_LENGTH]);
// Ask for input from the user to remove a player.
// Return the head of the list (it may have changed)
struct player *remove_by_name(struct player *head);
// Free all the players in the given list
void free_list(struct player *head);
Battle Royale - Implementation File A linked list example that tracks players in a game. We want to be able to maintain the list as well as remove players as they are knocked out. We also want to be able to display who is currently still in the game.
Marc Chee (cs1511@cse.unsw.edu.au) April 1st 2021
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "battle_royale.h"
// Structs
struct player {
struct player *next;
char name[MAX_NAME_LENGTH];
};
// Allocate memory for a player node
// Populate that node with new_name and new_next
// Return a pointer to the allocated memory
struct player *create_player(char new_name[MAX_NAME_LENGTH], struct player *new_next) {
struct player *new_player = malloc(sizeof (struct player));
new_player->next = new_next;
strcpy(new_player->name, new_name);
return new_player;
}
// Takes the head of the list
// Prints out everyone who is in the list
int print_players(struct player *head) {
struct player *current = head;
int num_players = 0;
while (current != NULL) { // I'm looking at a valid player
printf("%s\n", current->name);
num_players++;
current = current->next;
}
return num_players;
}
struct player *print_before(struct player *player_list,
struct player *after) {
// loop until you see the after pointer
struct player *curr = player_list;
struct player *prev = NULL;
while (curr != after) {
prev = curr;
curr = curr->next;
}
if (prev != NULL) {
// element exists, print its name
printf("%s\n", prev->name);
}
return prev;
}
// Print out the names stored in the list in reverse order
// This is a procedural programming implementation
void reverse_print(struct player *player_list) {
struct player *end = NULL;
int finished = 0;
// Loop once for each name in the list
while (!finished) {
end = print_before(player_list, end);
if (end == NULL) {
finished = 1;
}
}
}
// Print out the names stored in the list in reverse order
// This is a recursive programming implementation
void rev_print_rec(struct player *player_list) {
if (player_list != NULL) {
// there are element(s)
rev_print_rec(player_list->next);
printf("%s\n", player_list->name);
}
}
// Inserts into a list (head) alphabetically.
// Assumes the list is already in alphabetical order
// Returns the head of the list (it may have changed)
struct player *insert_alpha(struct player *head, char new_name[MAX_NAME_LENGTH]) {
// loop through and find the insertion point
struct player *current = head;
struct player *previous = NULL;
while (current != NULL && strcmp(current->name, new_name) < 0) {
// go past any names that are earlier than us alphabetically
previous = current;
current = current->next;
} // current is now the first player in the list with a name "higher or equal"
// than new_name
// previous is now the last player in the list with a name "lower"
// than new_name
if (previous == NULL) {
// Inserting at the head of a list
// also works for an empty list (head == NULL)
head = create_player(new_name, head);
} else {
// Inserting further down the list
previous->next = create_player(new_name, previous->next);
}
return head;
}
// Loop through list looking for a match of
// player's name to rem_name
// Remove and free that node (if it exists)
// Return the possibly-changed head of the list
// Note: head only changes if we remove the first player
struct player *remove_player(struct player *head,
char rem_name[MAX_NAME_LENGTH]) {
// Loop through and stop with curr->name == rem_name
struct player *curr = head;
struct player *prev = NULL;
while (curr != NULL && strcmp(rem_name, curr->name) != 0) {
prev = curr;
curr = curr->next;
}
if (curr != NULL) {
// curr now points at a player whose name matches rem_name
if (prev == NULL) { // (head == curr) also works
// removing the head of the list
head = curr->next;
} else {
// removing an element somewhere other than the head
prev->next = curr->next;
}
free(curr);
}
// or curr is NULL if it has reached the end of the list
return head;
}
// Ask the user for a player's name to remove.
// Remove that node and return the head of the list (may have changed)
struct player *remove_by_name(struct player *head) {
printf("Who's just been knocked out?\n");
char input[MAX_NAME_LENGTH];
fgets(input, MAX_NAME_LENGTH, stdin);
// fgets will store the \n that we type in in the input string
// if we find a \n at the end of input, remove it from the string
if (input[strlen(input) - 1] == '\n') {
input[strlen(input) - 1] = '\0';
}
head = remove_player(head, input);
return head;
}
// Free all elements of the list starting at head
void free_list(struct player *head) {
struct player *curr = head;
while (curr != NULL) {
struct player *free_node = curr;
curr = curr->next;
free(free_node);
}
}
Battle Royale a main function to test rev_print_rec
#include <stdlib.h>
#include <stdio.h>
#include "battle_royale.h"
int main(void) {
struct player *head = NULL;
head = insert_alpha(head, "Shrey");
head = insert_alpha(head, "Anosua");
head = insert_alpha(head, "Zoe");
head = insert_alpha(head, "Alvin");
head = insert_alpha(head, "Tom");
head = insert_alpha(head, "Andrew");
rev_print_rec(head);
free_list(head);
}
Battle Royale a main function to test reverse_print
#include <stdlib.h>
#include <stdio.h>
#include "battle_royale.h"
int main(void) {
struct player *head = NULL;
head = insert_alpha(head, "Shrey");
head = insert_alpha(head, "Anosua");
head = insert_alpha(head, "Zoe");
head = insert_alpha(head, "Alvin");
head = insert_alpha(head, "Tom");
head = insert_alpha(head, "Andrew");
reverse_print(head);
free_list(head);
}
All Links
- All Tutorial Questions
- All Tutorial Sample Answers
- All Laboratory Exercises
- All Laboratory Sample Solutions
-
- All Weekly Test Questions
- All Weekly Test Sample Answers
-
- Course Intro
- Introduction To C
- C Basics
- If
- While
- Style
- Functions
- Arrays
- Pointers
- Characters And Strings
- Malloc
- Structs
- Lists
- Multiple File C
- Abstract Data Types
- Recursion
- Exam
- Revision
Example Program showing output in C