COMP1511 18s1 (webcms)
COMP1511 Programming Fundamentals
COMP1511 18s1 (flask)

COMP1511 Course Resources

Administrivia
Lab/Test/Assignment
Home computing
Resources
Other
Revision

COMP1511 Week-by-Week

Tutorial
Laboratory
Tuesday February 26 Lecture Topics
Wednesday February 27 Lecture Topics
Tuesday March 06 Lecture Topics
Wednesday March 07 Lecture Topics
Tuesday March 13 Lecture Topics
Wednesday March 14 Lecture Topics
Tuesday March 20 Lecture Topics
Wednesday March 21 Lecture Topics
Tuesday March 27 Lecture Topics
Wednesday March 28 Lecture Topics
Tuesday April 10 Lecture Topics
Wednesday April 11 Lecture Topics
Tuesday April 17 Lecture Topics
Tuesday May 01 Lecture Topics
Wednesday May 02 Lecture Topics
Wednesday May 08 Lecture Topics
Wednesday May 09 Lecture Topics
Tuesday May 15 Lecture Topics
Wednesday May 16 Lecture Topics
Tuesday May 22 Lecture Topics
Wednesday May 23 Lecture Topics
Tuesday May 29 Lecture Topics

COMP1511 Topic-by-Topic

Course Overview
Introduction To C

A simple program demonstrating the use of printf

Compile by typing
 dcc -o hello_world hello_world.c 
or at home
 gcc -Wall -O -o hello_world hello_world.c 

Run by typing:
 ./hello_world 

    #include <stdio.h>

int main(void) {
    printf("Hello World!\n");
    return 0;
}

Download hello_world.c

    // This is a simple template for your first C programs
// Description
// Author
// Date

#include <stdio.h>

int main(void) {

    printf("REPLACE THIS PRINTF WITH YOUR CODE\n");

    return 0;
}

Download simple_template.c

C Basics

A simple program demonstrating the use of scanf to sum 2 numbers
    #include <stdio.h>

int main(void) {
    int x, y, sum;
    printf("Enter x: ");
    scanf("%d", &x);
    printf("Enter y: ");
    scanf("%d", &y);
    sum = x + y;
    // These 6 printfs can be better replaced by a single printf
    printf("%d", x);
    printf(" + ");
    printf("%d", y);
    printf(" = ");
    printf("%d", sum);
    printf("\n");
    return 0;
}

Download sum2a.c


A simple program demonstrating the use of scanf to sum 2 numbers
    #include <stdio.h>

int main(void) {
    int x, y, sum;
    printf("Enter x: ");
    scanf("%d", &x);
    printf("Enter y: ");
    scanf("%d", &y);
    sum = x + y;
    printf("%d + %d = %d\n", x, y, sum);
    return 0;
}

Download sum2b.c


A simple program demonstrating the use of scanf to sum 2 numbers
    #include <stdio.h>

int main(void) {
    int x, y;
    printf("Enter x: ");
    scanf("%d", &x);
    printf("Enter y: ");
    scanf("%d", &y);
    printf("%d + %d = %d\n", x, y, x +y);
    return 0;
}

Download sum2c.c


A simple program demonstrating the use of scanf
    #include <stdio.h>

int main(void) {
    int x, y;
    int answer;

    printf("Enter x: ");
    scanf("%d", &x);
    printf("Enter y: ");
    scanf("%d", &y);
    answer = x * x + y * y;
    printf("x squared + y squared = %d\n", answer);
    return 0;
}

Download squares.c



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;
}

Download celsius2fahrenheit.c



Demonstrate approximate representation of reals producing error. sometimes if we subtract two approximations which are very close together we can can get a large relative error
correct answer if x == 0.000000011 (1 - cos(x)) / (x * x) is very close to 0.5 code prints 0.917540 which is wrong by a factor of almost two
    #include <stdio.h>
#include <math.h>

int main(void) {
    double x, y;
    x = 0.000000011;
    y = (1 - cos(x))  / (x * x);
    printf("correct answer = ~0.5 but y = %lf\n", y);
    return 0;
}

Download double_catastrophe.c



Demonstrate approximate representation of reals
The value 0.1 can not be precisely represented as a real
As a result a non-zero value is printed
    #include <stdio.h>

int main(void) {
    double a, b;
    a = 0.1;
    b = 1 - (a + a + a + a + a + a + a + a + a + a);
    printf("%g\n", b);
    return 0;
}

Download precision.c

If

A simple program demonstrating the use of scanf and if statements
    #include <stdio.h>

int main(void) {
    int a, b;
    printf("Enter a: ");
    scanf("%d", &a);
    printf("Enter b: ");
    scanf("%d", &b);
    if (a > b) {
        printf("a is greater than b\n");
    } else if (a < b) {
        printf("a is less than b\n");
    } else {
        printf("a is equal to b\n");
    }
    return 0;
}

Download larger_a.c


A simple program demonstrating the use of scanf and if statements
    #include <stdio.h>

int main(void) {
    int a, b;
    printf("Enter a: ");
    scanf("%d", &a);
    printf("Enter b: ");
    scanf("%d", &b);
    if (a > b) {
        printf("%d is greater than %d\n", a, b);
    } else if (a < b) {
        printf("%d is less than %d\n", a, b);
    } else {
        printf("%d is equal to %d\n", a, b);
    }
    return 0;
}

Download larger_b.c



Convert a measurement in feet to metres

A simple program demonstrating the use of scanf, printf and an if statement

    #include <stdio.h>

int main(void) {
    int x, absoluteValue;

    printf("Enter number: ");
    scanf("%d", &x);

    absoluteValue = x;
    if (x < 0) {
        absoluteValue = -1 * x;
    }

    printf("The absolute value of %d is %d\n", x, absoluteValue);
    return 0;
}

Download absolute.c



Print the result of an integer division

    #include <stdio.h>

int main(void) {
    int x, y;

    printf("Enter x: ");
    scanf("%d", &x);
    printf("Enter y: ");
    scanf("%d", &y);

    if (y != 0) {
        printf("%d/%d=%d\n", x, y, x/y);
    } else {
        printf("Can't divide by zero sorry\n");
    }
    return 0;
}

Download divide.c


A simple program demonstrating the use of scanf and if statements with complex conditions
    #include <stdio.h>

#include <stdio.h>

int main(void) {
    int x;
    printf("Enter x: ");
    scanf("%d", &x);

    printf("%d has ", x);
    if (x < 10 && x > -10) {
        printf("1 digit");
    }
    if ((x >= 10 && x < 100) || (x <= -10 && x > -100)) {
        printf("2 digits");
    }
    if (x >= 100 || x <= -100) {
        printf("more than 2 digits");
    }
    printf("\n");

    return 0;
}

Download digits.c


A simple program demonstrating the use of scanf and nested if statements
    #include <stdio.h>

int main(void) {
    int a;
    printf("Enter a: ");
    scanf("%d", &a);

    printf("%d is a ", a);
    if (a < 0) {
        if (a < -100) {
            printf("big");
        } else {
            printf("small");
        }
        printf(" negative");
    } else {
        if (a > 100) {
            printf("big");
        } else {
            printf("small");
        }
        printf(" positive");
    }
    printf(" number.\n");

    return 0;
}

Download nested_if.c



A simple program to check Pythagorean identity

Demonstrates danger of use == with doubles e.g. enter 1 for theta
    #include <stdio.h>
#include <math.h>

int main(void) {
    double theta, identity;

    printf("Enter theta: ");
    scanf("%lf", &theta);

    identity = 1 - (sin(theta) * sin(theta) + cos(theta) * cos(theta));

    if (identity == 0.0) {
        printf("Pythagorean identity true for %lf\n", theta);
    } else {
        printf("Pythagorean wrong by %g for %lf\n", identity,  theta);
    }

    return 0;
}

Download pythagorean_identity.c



Calculate relativistic-mass of an object
    #include <stdio.h>
#include <math.h>

#define SPEED_OF_LIGHT 299792458.0

int main(void) {
    double mass, rest_mass;
    double velocity;
    double ratio;

    printf("Enter rest mass: ");
    scanf("%lf", &rest_mass);

    printf("Enter velocity in metres/second: " );
    scanf("%lf", &velocity);

    // compute velocity as a fraction of speed of light
    ratio = velocity / SPEED_OF_LIGHT;

    if (ratio >= 1.0) {
        printf("Error: velocity exceeds speed of light.\n");
    } else {
        // compute observed mass using Einstein's equation
        mass = rest_mass / sqrt(1.0 - ratio*ratio);
        printf("Observed mass = %1.6f\n", mass);
    }

    return 0;
}

Download relativistic_mass.c

Functions

Lecture example illustrating simple function
    #include <stdio.h>

// 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;
}

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;
}

Download quadratic.c


Lecture example illustrating simple function
    #include <stdio.h>
#include <math.h>

// given x calculate value of polynomial with coefficients a, b, c

double quadratic_root(double a, double b,  double c) {
    return (-b + sqrt(b * b - 4 * a * c)) / (2 * a);
}

double evaluate_quadratic(double a, double b, double c, double x) {
    return (a * x * x) + (b * x) + c;
}

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;
}

Download quadratic_root.c


Simple lecture example of using functions
    #include <stdio.h>

// calculate x to the power of 3
double cube(double x) {
    double result;
    result = x * x * x;
    return result;
}

int main(void) {
    double a, b;
    printf("42 cubed is %lf\n", cube(42.03));
    a = 2;
    b = cube(a);
    printf("2 cubed is %lf\n", b);
    return 0;
}

Download cube.c


Simple lecture example of using functions
    #include <stdio.h>

void print_hundred_messages(void);
void print_ten_messages(void);
void print_message(void);

int main(int argc, char *argv[]) {
    print_hundred_messages();
    return 0;
}

void print_hundred_messages(void) {
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
    print_ten_messages();
}

void print_ten_messages(void) {
    print_message();
    print_message();
    print_message();
    print_message();
    print_message();
    print_message();
    print_message();
    print_message();
}

void print_message(void) {
    printf("C is good.\n");
    printf("C is great.\n");
    printf("We all love C.\n");
}

Download print_messages.c


Simple example illustrating call by value
    #include <stdio.h>

int f(int x) {
    int y;
    // these assignments will have no effect on variables
    // outside the function
    x = x + 1;
    y = 3;
    return x * y;
}

int main(int argc, char *argv[]) {
    int  x, y , z;
    x = 1;
    y = 2;
    z = f(y);
    // note the variables x & y are local to main
    // and are not changed by assignment to variables
    // of the same name in f
    printf("x=%d y=%d z=%d\n", x, y, z);
    return 0;
}

Download call_by_value.c


Simple recursive calculation of factorials & Fibonacci numbers http://en.wikipedia.org/wiki/Factorial http://en.wikipedia.org/wiki/Fibonacci_number

Fibonacci calculation is very inefficient

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

int fibonacci(int n) {
     if (n < 2) {
        return 1;
     }
     return fibonacci(n - 1) + fibonacci(n-2);
}

int factorial(int n) {
     if (n < 2) {
        return 1;
     }
     return n * factorial(n - 1);
}

int main(void) {
    int x;

    printf("Enter number: ");
    scanf("%d", &x);

    printf("factorial %d = %d\n", x, factorial(x));
    printf("fibonacci %d = %d\n", x, fibonacci(x));

    return 0;
}

Download fact_and_fib.c

While

A silly program which prints first 1000 multiples of 13

    #include <stdio.h>

int main(void) {
    printf("%d\n", 13);
    printf("%d\n", 26);
    printf("%d\n", 39);
    printf("%d\n", 52);
    printf("%d\n", 65);
    printf("%d\n", 78);
    printf("%d\n", 91);
    printf("%d\n", 104);
    printf("%d\n", 117);
    printf("%d\n", 130);
    printf("%d\n", 143);
    printf("%d\n", 156);
    printf("%d\n", 169);
    printf("%d\n", 182);
    printf("%d\n", 195);
    printf("%d\n", 208);
    printf("%d\n", 221);
    printf("%d\n", 234);
    printf("%d\n", 247);
    printf("%d\n", 260);
    printf("%d\n", 273);
    printf("%d\n", 286);
    printf("%d\n", 299);
    printf("%d\n", 312);
    printf("%d\n", 325);
    printf("%d\n", 338);
    printf("%d\n", 351);
    printf("%d\n", 364);
    printf("%d\n", 377);
...

Download thirteen_a.c


A silly program which prints first 1000 multiples of 13

    #include <stdio.h>

int main(void) {
    if (1 % 13 == 0) {
        printf("%d\n", 1);
    }
    if (2 % 13 == 0) {
        printf("%d\n", 2);
    }
    if (3 % 13 == 0) {
        printf("%d\n", 3);
    }
    if (4 % 13 == 0) {
        printf("%d\n", 4);
    }
    if (5 % 13 == 0) {
        printf("%d\n", 5);
    }
    if (6 % 13 == 0) {
        printf("%d\n", 6);
    }
    if (7 % 13 == 0) {
        printf("%d\n", 7);
    }
    if (8 % 13 == 0) {
        printf("%d\n", 8);
    }
    if (9 % 13 == 0) {
        printf("%d\n", 9);
    }
    if (10 % 13 == 0) {
        printf("%d\n", 10);
...

Download thirteen_b.c


A silly program which prints first 1000 multiples of 13

Note the same 4 lines are repeated 13000 times.
This means these lines could be replaced by a while loop which executes 13000 times.

    #include <stdio.h>

int main(void) {
    int i;
    i = 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
    i = i + 1;
    if (i % 13 == 0) {
        printf("%d\n", i);
    }
...

Download thirteen_c.c


A simple program which uses a while loop to print first 1000 multiples of 13


    #include <stdio.h>

int main(void) {
    int i;
    i = 1;
    while (i <= 13000) {
        if (i % 13 == 0) {
            printf("%d\n", i);
        }
        i = i + 1;
    }

    return 0;
}

Download thirteen_d.c


Another simple program which uses a while loop to print first 1000 multiples of 13


    #include <stdio.h>

int main(void) {
    int i;
    i = 13;
    while (i <= 13000) {
        printf("%d\n", i);
        i = i + 13;
    }
    return 0;
}

Download thirteen_e.c


Another simple program which uses a while loop to print first 1000 multiples of 13


    #include <stdio.h>

int main(void) {
    int i;
    i = 1;
    while (i <= 1000) {
        printf("%d\n", i*13);
        i = i + 1;
    }
    return 0;
}

Download thirteen_f.c


A simple program demonstrating the use of a while loop

    #include <stdio.h>

int main(void) {
    int n, upperBound, sum;
    sum = 0;
    upperBound = 10;
    n = 1;
    while (n <= upperBound) {
        sum = sum + n;
        n = n + 1;
    }
    printf("Sum of integers 1..%d is %d\n", upperBound, sum);
    return 0;
}

Download gauss.c



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 x, sum, n;

    sum = 0;
    printf("Enter %d numbers:\n", N_NUMBERS);

    n = 0;
    while (n < N_NUMBERS) {
        scanf("%d", &x);
        sum = sum + x;
        n = n + 1;
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_42_numbers.c



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 x, sum, n, nNumbers;

    sum = 0;
    printf("How many numbers do you wish to sum: ");
    scanf("%d", &nNumbers);
    printf("Enter %d numbers:\n", nNumbers);

    n = 0;
    while (n < nNumbers) {
        scanf("%d", &x);
        sum = sum + x;
        n = n + 1;
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_n_numbers.c


Read 5 numbers and print the largest

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>

#define N_NUMBERS 5

int main(void) {
    int howManyNumbers, number, maximum;
    scanf("%d", &maximum);
    howManyNumbers = 1;
    while (howManyNumbers < N_NUMBERS) {
        scanf("%d", &number);
        if (number > maximum) {
            maximum = number;
        }
        howManyNumbers = howManyNumbers + 1;
    }
    printf("Largest is %d\n", maximum);
    return 0;
}

Download large5.c



Read numbers until a negative number is read then print the sum of the numbers (not including the negative number)

Version 1

A simple program demonstrating stopping a while loop when a particular value is read by 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 x, sum;

    sum = 0;
    x = 0;
    printf("Enter numbers, terminate with a negative number:\n");

    while (x >= 0) {
        scanf("%d", &x);
        if (x > 0) {
            sum = sum + x;
        }
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_until_negative0.c



Read numbers until a negative number is read then print the sum of the numbers (not including the negative number)

Version 2

A simple program demonstrating stopping a while loop when a particular value is read by 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 x, sum;

    sum = 0;
    printf("Enter numbers, terminate with a negative number:\n");

    scanf("%d", &x);
    while (x >= 0) {
        sum = sum + x;
        scanf("%d", &x);
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_until_negative1.c


Sum the series 1 + 1/2 + 1/3 + 1/4 + ...


    #include <stdio.h>


#define N_SERIES_TERMS 1000

int main(void) {
    int n;
    double sum;

    n = 1;
    sum = 0;
    while (n <= N_SERIES_TERMS) {
        sum = sum + 1.0 / n;
        n = n + 1;
    }

    printf("1 + 1/2 + 1/3 + + ... + 1/%d = %f\n", N_SERIES_TERMS, sum);
    return 0;
}

Download series0.c


Calculate the mathematical constant e by summing the series 1 + 1/(1*2) + 1/(1*2*3) + 1/(1*2*3*4) + ... http://en.wikipedia.org/wiki/E_%28mathematical_constant%29


    #include <stdio.h>


#define N_SERIES_TERMS 20

int main(void) {
    int n;
    double sum, factorial;

    n = 1;
    sum = 0;
    factorial = 1;
    while (n <= N_SERIES_TERMS) {
        sum = sum + 1.0 / factorial;
        factorial = factorial * n;
        n = n + 1;
    }

    printf("1/1 + 1/1 + 1/(1*2) + 1/(1*2*3) + 1/(1*2*3*4)  + ... + 1/%.0f  = %.12f\n", factorial, sum);
    return 0;
}

Download calculate_e.c


Calculate the mathematical constant pi to 6 decimal places by summing the series 4 - 4/3 + 4/5 - 4/7 + 4/9 + ...

    #include <stdio.h>


#define N_SERIES_TERMS 1000000

int main(void) {
    int n;
    double sum;

    n = 0;
    sum = 0;
    while (n < N_SERIES_TERMS) {
        if (n % 2 == 0) {
            sum = sum + 4.0 / (2 * n + 1);
        } else {
            sum = sum - 4.0 / (2 * n + 1);
        }
        n = n + 1;
    }

    printf("4 - 4/3 + 4/5 - 4/7 + 4/9 + ... = %f\n", sum);
    return 0;
}

Download calculate_pi.c


Calculate the the series 1 + 1/2 + 1/4 + 1/8 + ... until it converges to within 10 decimal places


    #include <stdio.h>

#define ACCURACY  0.000000000001

int main(void) {
    double sum, term;

    sum = 0;
    term = 1;

    while (term > ACCURACY) {
        sum = sum + term;
        term = term / 2.0;
    }

    printf("1 + 1/2 + 1/4 + 1/8 + ...  = %.10f\n", sum);
    return 0;
}

Download converge.c



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;
}

Download even_odd.c



A simple program which prints a square

    #include <stdio.h>

#define SIDE_LENGTH 13

int main(void) {
    int row, column;
    row = 0;
    while (row < SIDE_LENGTH) {
        column = 0;
        while (column <= SIDE_LENGTH) {
            printf("*");
            column = column + 1;
        }
        printf("\n");
        row = row + 1;
    }
    return 0;
}

Download square.c



A simple program which prints a triangle

    #include <stdio.h>

#define SIDE_LENGTH 13

int main(void) {
    int row, column;
    row = 0;
    while (row < SIDE_LENGTH) {
        column = 0;
        while (column <= row) {
            printf("*");
            column = column + 1;
        }
        printf("\n");
        row = row + 1;
    }
    return 0;
}

Download triangle.c



A simple program which reads integers and and if a composite number is read exists printing the factor

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, possibleFactor, keepLooping;
    keepLooping = 1;
    while (keepLooping == 1) {
        printf("Enter a number: ");
        scanf("%d", &n);
        possibleFactor = 2;
        while (possibleFactor < n && keepLooping == 1) {
            if (n % possibleFactor == 0) {
                printf("%d is composite %d is a factor\n", n, possibleFactor);
                keepLooping = 0;
            }
            possibleFactor = possibleFactor + 1;
        }
    }
    return 0;
}

Download composite.c


A simple program demonstrating nested while loops

It prints all prime numbers < 10000


    #include <stdio.h>

int main(void) {
    int n, possibleFactor, nFactors;
    // loop through numbers 1..1000
    n = 1;
    while (n < 1000) {
        // loop through numbers 1..n counting factors
        possibleFactor = 1;
        nFactors = 0;
        while (possibleFactor <= n) {
            if (n % possibleFactor == 0) {
                nFactors = nFactors + 1;
            }
            possibleFactor = possibleFactor + 1;
        }
        if (nFactors <= 2) {
            printf("%d is prime\n", n);
        }
        n = n + 1;
    }
    return 0;
}

Download primes1000.c


A simple program which reads integers and prints snap and exits if the same number is read twice in a row

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, previousN;

    printf("Enter a number: ");
    scanf("%d", &previousN);

    printf("Enter a number: ");
    scanf("%d", &n);

    while (n != previousN) {
        previousN = n;
        printf("Enter a number: ");
        scanf("%d", &n);
    }

    printf("Snap!\n");
    return 0;
}

Download snap0.c



Read numbers until end of input (or a non-number) is reached then print the sum of the numbers

Version 1

A simple program demonstrating stopping a while loop when scanf fails to read a number e.g. because end-of-input is reached


    #include <stdio.h>

int main(void) {
    int sum, x, numbersRead;

    sum = 0;
    numbersRead = 1;
    printf("Enter numbers, indicate end-of-input with control-D:\n");

    while (numbersRead == 1) {

        // if scanf can read an integer it will place it in x and it will return 1
        // if scanf can't read an integer it will not change x and it will return 0 or -1
        numbersRead = scanf("%d", &x);

        if (numbersRead == 1) {
            sum = sum + x;
        }
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_numbers_until_end_of_input0.c



Read numbers until end of input (or a non-number) is reached then print the sum of the numbers

Version 1

A simple program demonstrating stopping a while loop when scanf fails to read a number e.g. because end-of-input is reached


    #include <stdio.h>

int main(void) {
    int sum, x, numbersRead;

    sum = 0;
    numbersRead = 1;
    printf("Enter numbers, indicate end-of-input with control-D:\n");

    // if scanf can read an integer it will place it in x and it will return 1
    // if scanf can't read an integer it will not change x and it will return 0 or -1
    numbersRead = scanf("%d", &x);
    while (numbersRead == 1) {
        sum = sum + x;
        numbersRead = scanf("%d", &x);
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_numbers_until_end_of_input1.c



Read numbers until end of input (or a non-number) is reached then print the sum of the numbers

Version 2

A simple program demonstrating stopping a while loop when scanf fails to read a number e.g. because end-of-input is reached


    #include <stdio.h>

int main(void) {
    int sum, x;

    sum = 0;

    printf("Enter number: ");
    while (scanf("%d", &x) == 1) {
        sum = sum + x;
        printf("Enter number: ");
    }

    printf("Sum of the numbers is %d\n", sum);
    return 0;
}

Download sum_numbers_until_end_of_input2.c

Arrays

Read 5 numbers and print them in reverse order - the hard way

This approach quickly becomes impractical if you want to read more numbers a much better approach is to use an array

    #include <stdio.h>

int main(void) {
    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;
}

Download reverse5stupid.c


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.
The constants 4 & 5 below would be better replaced with a #define
    #include <stdio.h>

int main(void) {
    int x[5], i, j;
    printf("Enter 5 numbers: ");
    i = 0;
    while (i < 5) {
        scanf("%d", &x[i]);
        i = i + 1;
    }
    printf("Numbers reversed are:\n");
    j = 4;
    while (j >= 0) {
        printf("%d\n", x[j]);
        j = j - 1;
    }
    return 0;
}

Download reverse5smart.c


Read 5 numbers and print them in reverse order
    #include <stdio.h>

#define N_NUMBERS 5

int main(void) {
    int x[N_NUMBERS], i, j;

    printf("Enter %d numbers: ", N_NUMBERS);
    i = 0;
    while (i < N_NUMBERS) {
        scanf("%d", &x[i]);
        i = i + 1;
    }
    printf("Numbers reversed are:\n");
    j = N_NUMBERS - 1;
    while (j >= 0) {
        printf("%d\n", x[j]);
        j = j - 1;
    }
    return 0;
}

Download reverse5smarter.c


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], i, j, scanfFailed;

    printf("Enter %d numbers: ", N_NUMBERS);
    i = 0;
    scanfFailed = 0;
    while (i < N_NUMBERS && scanfFailed == 0) {
        if (scanf("%d", &x[i]) != 1) {
            scanfFailed = 1;
        }
        i = i + 1;
    }
    if (scanfFailed == 1) {
        printf("Insufficient numbers read\n");
    } else {
        printf("Numbers reversed are:\n");
        j = N_NUMBERS - 1;
        while (j >= 0) {
            printf("%d\n", x[j]);
            j = j - 1;
        }
    }
    return 0;
}

Download reverse5check_scanf.c


Read n 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>

#define MAX_NUMBERS 1000000

int main(void) {
    int x[MAX_NUMBERS], i, j, howMany;
    printf("Read how many numbers? ");
    scanf("%d", &howMany);
    if (howMany > MAX_NUMBERS) {
        printf("I'm sorry, Dave. I'm afraid I can't do that.\n");
        printf("Reading %d numbers\n", MAX_NUMBERS);
        howMany = MAX_NUMBERS;
    }
    i = 0;
    while (i < howMany) {
        scanf("%d", &x[i]);
        i = i + 1;
    }
    printf("Numbers reversed are:\n");

    j = howMany - 1;
    while (j >= 0) {
        printf("%d\n", x[j]);
        j = j - 1;
    }
    return 0;
}

Download reverse_n.c


A simple program which reads integers and prints snap and exits if the same number is read twice

This version uses a sentinel variable (stopNow)
The use of a sentinel variable is very useful programming pattern which can be used in many situations

But see variant_snap1.c for a simpler solution using return

    #include <stdio.h>

#define MAX_NUMBERS 100000

int main(void) {
    int numbers[MAX_NUMBERS];
    int nNumbersRead, i, stopNow;

    nNumbersRead = 0;
    stopNow = 0;
    while (stopNow == 0) {
        printf("Enter a number: ");
        if (scanf("%d", &numbers[nNumbersRead]) != 1) {
            stopNow = 1;
        } else {
            i = 0;
            while (i < nNumbersRead) {
                if (numbers[i] == numbers[nNumbersRead]) {
                    printf("Snap!\n");
                    stopNow = 1;
                }
                i = i + 1;
            }
            nNumbersRead = nNumbersRead + 1;
            if (nNumbersRead == MAX_NUMBERS) {
                printf("Sorry my array is full I have to stop!\n");
                stopNow = 1;
            }
        }
    }
    return 0;
}

Download variant_snap0.c


A simple program which reads integers and prints snap and exits if the same number is read twice

Note the use of return to leave the main function and hence finish program execution

    #include <stdio.h>

#define MAX_NUMBERS 100000

int main(void) {
    int numbers[MAX_NUMBERS];
    int nNumbersRead, i;

    nNumbersRead = 0;
    while (nNumbersRead < MAX_NUMBERS) {
        printf("Enter a number: ");
        if (scanf("%d", &numbers[nNumbersRead]) != 1) {
            return 0;
        }
        i = 0;
        while (i < nNumbersRead) {
            if (numbers[i] == numbers[nNumbersRead]) {
                printf("Snap!\n");
                return 0;
            }
            i = i + 1;
        }
        nNumbersRead = nNumbersRead + 1;
    }
    printf("Sorry my array is full I have to stop!\n");
    return 0;
}

Download variant_snap1.c


Read annual rainfall and plot as bar graph
This version always reads N_YEARS of rainfall


Sample execution:
% dcc plot_rainfall0.c % a.out
Enter 10 years of rainfall totals
Enter year: 2005
Enter rainfall(mm): 816
Enter year: 2006
Enter rainfall(mm): 994.0
Enter year: 2007
Enter rainfall(mm): 1499.2
Enter year: 2008
Enter rainfall(mm): 1082.6
Enter year: 2009
Enter rainfall(mm): 956.2
Enter year: 2010
Enter rainfall(mm): 1153.8
Enter year: 2011
Enter rainfall(mm): 1369.2
Enter year: 2012
Enter rainfall(mm): 1213.6
Enter year: 2013
Enter rainfall(mm): 1344.4
Enter year: 2014
Enter rainfall(mm): 893.8
1 asterisk == 100 mm of rainfall 2005 ******** 2006 ********* 2007 ************** 2008 ********** 2009 ********* 2010 *********** 2011 ************* 2012 ************ 2013 ************* 2014 ********

    #include <stdio.h>

#define N_YEARS  10
#define SCALE    100

int main(void) {
    int    whichYear[N_YEARS];
    double rainfall[N_YEARS];
    int    year, asterisk, nAsterisks;

    printf("Enter %d years of rainfall totals\n", N_YEARS);

    year = 0;
    while (year < N_YEARS) {
        printf("Enter year: ");
        scanf("%d", &whichYear[year]);
        printf("Enter rainfall(mm): ");
        scanf("%lf", &rainfall[year]);
        year = year + 1;
    }

    printf("\n1 asterisk == %d mm of rainfall\n", SCALE);

    year = 0;
    while (year < N_YEARS) {
        printf("%4d ", whichYear[year]);
        nAsterisks = rainfall[year] / SCALE;
        asterisk = 0;
        while (asterisk < nAsterisks) {
            printf("*");
            asterisk = asterisk + 1;
        }
        printf("\n");
        year = year + 1;
    }

    return 0;
}

Download plot_rainfall0.c


Read annual rainfall and plot as bar graph
This version asks the user how many years of rainfall they wish to plot


Sample execution:
% dcc plot_rainfall1.c % a.out
How many years of rainfall do you want to graph: 10
Enter year: 2005
Enter rainfall(mm): 816
Enter year: 2006
Enter rainfall(mm): 994.0
Enter year: 2007
Enter rainfall(mm): 1499.2
Enter year: 2008
Enter rainfall(mm): 1082.6
Enter year: 2009
Enter rainfall(mm): 956.2
Enter year: 2010
Enter rainfall(mm): 1153.8
Enter year: 2011
Enter rainfall(mm): 1369.2
Enter year: 2012
Enter rainfall(mm): 1213.6
Enter year: 2013
Enter rainfall(mm): 1344.4
Enter year: 2014
Enter rainfall(mm): 893.8
1 asterisk == 100 mm of rainfall 2005 ******** 2006 ********* 2007 ************** 2008 ********** 2009 ********* 2010 *********** 2011 ************* 2012 ************ 2013 ************* 2014 ********

    #include <stdio.h>

#define MAXIMUM_YEARS 20000
#define SCALE    100

int main(void) {
    int    whichYear[MAXIMUM_YEARS];
    double rainfall[MAXIMUM_YEARS];
    int    year, asterisk, nAsterisks, nYears;

    printf("How many years of rainfall do you want to graph: ");
    scanf("%d", &nYears);
    if (nYears > MAXIMUM_YEARS) {
        printf("Limiting years read to  maximum possible: %d\n", MAXIMUM_YEARS);
        nYears = MAXIMUM_YEARS;
    }

    year = 0;
    while (year < nYears) {
        printf("Enter year: ");
        scanf("%d", &whichYear[year]);
        printf("Enter rainfall(mm): ");
        scanf("%lf", &rainfall[year]);
        year = year + 1;
    }

    printf("\n1 asterisk == %d mm of rainfall\n", SCALE);

    year = 0;
    while (year < nYears) {
        printf("%4d ", whichYear[year]);
        nAsterisks = rainfall[year] / SCALE;
        asterisk = 0;
        while (asterisk < nAsterisks) {
            printf("*");
            asterisk = asterisk + 1;
        }
        printf("\n");
        year = year + 1;
    }

    return 0;
}

Download plot_rainfall1.c


Read annual rainfall and plot as bar graph
This version reads years & their rainfall until the users enters 0 for a year


Sample execution:
% dcc plot_rainfall2.c % a.out
Enter year[0 to stop]: 2005
Enter rainfall(mm): 816
Enter year[0 to stop]: 2006
Enter rainfall(mm): 994.0
Enter year[0 to stop]: 2007
Enter rainfall(mm): 1499.2
Enter year[0 to stop]: 2008
Enter rainfall(mm): 1082.6
Enter year[0 to stop]: 2009
Enter rainfall(mm): 956.2
Enter year[0 to stop]: 2010
Enter rainfall(mm): 1153.8
Enter year[0 to stop]: 2011
Enter rainfall(mm): 1369.2
Enter year[0 to stop]: 2012
Enter rainfall(mm): 1213.6
Enter year[0 to stop]: 2013
Enter rainfall(mm): 1344.4
Enter year[0 to stop]: 2014
Enter rainfall(mm): 893.8
Enter year: 0
1 asterisk == 100 mm of rainfall 2005 ******** 2006 ********* 2007 ************** 2008 ********** 2009 ********* 2010 *********** 2011 ************* 2012 ************ 2013 ************* 2014 ********

    #include <stdio.h>

#define MAXIMUM_YEARS 20000
#define SCALE    100

int main(void) {
    int    whichYear[MAXIMUM_YEARS];
    double rainfall[MAXIMUM_YEARS];
    int    year, asterisk, nAsterisks, nYears;

    year = 0;
    nYears = MAXIMUM_YEARS;
    while (year < MAXIMUM_YEARS) {
        printf("Enter year[0 to stop]: ");
        scanf("%d", &whichYear[year]);
        if (whichYear[year] == 0) {
            nYears = year;
            year = MAXIMUM_YEARS;
        } else {
            printf("Enter rainfall(mm): ");
            scanf("%lf", &rainfall[year]);
            year = year + 1;
        }
    }

    printf("\n1 asterisk == %d mm of rainfall\n", SCALE);

    year = 0;
    while (year < nYears) {
        printf("%4d ", whichYear[year]);
        nAsterisks = rainfall[year] / SCALE;
        asterisk = 0;
        while (asterisk < nAsterisks) {
            printf("*");
            asterisk = asterisk + 1;
        }
        printf("\n");
        year = year + 1;
    }

    return 0;
}

Download plot_rainfall2.c


Read annual rainfall and plot as bar graph
This version reads years & their rainfall until end-of-file


Sample execution:
% dcc plot_rainfall3.c % a.out
Enter year: 2005
Enter rainfall(mm): 816
Enter year: 2006
Enter rainfall(mm): 994.0
Enter year: 2007
Enter rainfall(mm): 1499.2
Enter year: 2008
Enter rainfall(mm): 1082.6
Enter year: 2009
Enter rainfall(mm): 956.2
Enter year: 2010
Enter rainfall(mm): 1153.8
Enter year: 2011
Enter rainfall(mm): 1369.2
Enter year: 2012
Enter rainfall(mm): 1213.6
Enter year: 2013
Enter rainfall(mm): 1344.4
Enter year: 2014
Enter rainfall(mm): 893.8 <control-D>
1 asterisk == 100 mm of rainfall 2005 ******** 2006 ********* 2007 ************** 2008 ********** 2009 ********* 2010 *********** 2011 ************* 2012 ************ 2013 ************* 2014 ********

    #include <stdio.h>

#define MAXIMUM_YEARS 20000
#define SCALE    100

int main(void) {
    int    whichYear[MAXIMUM_YEARS];
    double rainfall[MAXIMUM_YEARS];
    int    year, asterisk, nAsterisks, nYears;

    year = 0;
    nYears = MAXIMUM_YEARS;
    while (year < MAXIMUM_YEARS) {
        printf("Enter year: ");
        if (scanf("%d", &whichYear[year]) == 0) {
            nYears = year;
            year = MAXIMUM_YEARS;
        } else {
            printf("Enter rainfall(mm): ");
            scanf("%lf", &rainfall[year]);
            year = year + 1;
        }
    }

    printf("\n1 asterisk == %d mm of rainfall\n", SCALE);

    year = 0;
    while (year < nYears) {
        printf("%4d ", whichYear[year]);
        nAsterisks = rainfall[year] / SCALE;
        asterisk = 0;
        while (asterisk < nAsterisks) {
            printf("*");
            asterisk = asterisk + 1;
        }
        printf("\n");
        year = year + 1;
    }

    return 0;
}

Download plot_rainfall3.c


Read annual rainfall and plot as bar graph
This version reads years & their rainfall until end-of-file and puts -1 in the array as a a marker


Sample execution:
% dcc plot_rainfall4.c % a.out
Enter year: 2005
Enter rainfall(mm): 816
Enter year: 2006
Enter rainfall(mm): 994.0
Enter year: 2007
Enter rainfall(mm): 1499.2
Enter year: 2008
Enter rainfall(mm): 1082.6
Enter year: 2009
Enter rainfall(mm): 956.2
Enter year: 2010
Enter rainfall(mm): 1153.8
Enter year: 2011
Enter rainfall(mm): 1369.2
Enter year: 2012
Enter rainfall(mm): 1213.6
Enter year: 2013
Enter rainfall(mm): 1344.4
Enter year: 2014
Enter rainfall(mm): 893.8 <control-D>
1 asterisk == 100 mm of rainfall 2005 ******** 2006 ********* 2007 ************** 2008 ********** 2009 ********* 2010 *********** 2011 ************* 2012 ************ 2013 ************* 2014 ********

    #include <stdio.h>

#define MAXIMUM_YEARS 20000
#define SCALE    100

int main(void) {
    int    whichYear[MAXIMUM_YEARS];
    double rainfall[MAXIMUM_YEARS];
    int    year, asterisk, nAsterisks;

    year = 0;
    while (year < MAXIMUM_YEARS) {
        printf("Enter year: ");
        if (scanf("%d", &whichYear[year]) == 0) {
            whichYear[year] = -1;
            year = MAXIMUM_YEARS;
        } else {
            printf("Enter rainfall(mm): ");
            scanf("%lf", &rainfall[year]);
            year = year + 1;
        }
    }
    whichYear[MAXIMUM_YEARS - 1] = -1;

    printf("\n1 asterisk == %d mm of rainfall\n", SCALE);

    year = 0;
    while (whichYear[year] >= 0) {
        printf("%4d ", whichYear[year]);
        nAsterisks = rainfall[year] / SCALE;
        asterisk = 0;
        while (asterisk < nAsterisks) {
            printf("*");
            asterisk = asterisk + 1;
        }
        printf("\n");
        year = year + 1;
    }

    return 0;
}

Download plot_rainfall4.c


Read SIZE x SIZE numbers and test if they form a magic square http://en.wikipedia.org/wiki/Magic_square
and exits if the same number is read twice


Lo Shu Square 4 9 2 3 5 7 8 1 6

Magic square of primes 17 89 71 113 59 5 47 29 101

    #include <stdio.h>

#define SIZE 3

int main(void) {
    int x[SIZE][SIZE];
    int row, column;
    int magicConstant, sum;
    int notMagicSquare;

    // read potential magic square
    printf("Enter %d numbers please:\n", SIZE*SIZE);
    row = 0;
    while (row < SIZE) {
        column = 0;
        while (column < SIZE) {
            if (scanf("%d", &x[row][column]) != 1) {
                printf("Couldn't read enough numbers\n");
                return 0;
            }
            column = column + 1;
        }
        row = row + 1;
    }
    printf("Numbers are:\n");
    // print potential magic square
    row = 0;
    while (row < SIZE) {
        column = 0;
        while (column < SIZE) {
            printf("%d ", x[row][column]);
            column = column + 1;
        }
        printf("\n");
        row = row + 1;
    }

    // sum first row
    magicConstant = 0;
    row = 0;
    while (row < SIZE) {
        magicConstant = magicConstant + x[0][row];
        row = row + 1;
    }

    // check if sum of each row matches sum of first row
    notMagicSquare = 0;
    row = 1;
    while (row < SIZE) {
        sum = 0;
        column = 0;
        while (column < SIZE) {
            sum = sum + x[row][column];
            column = column + 1;
        }
        if (sum != magicConstant) {
            notMagicSquare = 1;
        }
        row = row + 1;
    }

    // check if sum of each column matches sum of first row
    column = 0;
    while (column < SIZE) {
        sum = 0;
        row = 0;
        while (row < SIZE) {
            sum = sum + x[row][column];
            row = row + 1;
        }
        if (sum != magicConstant) {
            notMagicSquare = 1;
        }
        column = column + 1;
    }

    // summing diagonals left as an exercise

    if (notMagicSquare == 0) {
        printf("Is a magic square\n");
    } else {
        printf("Not a magic square\n");
    }
    return 0;
}

Download magic_square.c

Characters And Strings


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) {
    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;
}

Download andrew_rocks0.c



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)
    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;
}

Download andrew_rocks1.c



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>

#define LENGTH 14

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 < LENGTH) {
        putchar(asciiCodes[i]);
        i = i + 1;
    }

    return 0;
}

Download andrew_rocks2.c



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>

#define LENGTH 14

int main(void) {
    int asciiCodes[LENGTH] = {'A','n','d','r','e','w',' ','R','o','c','k','s','!','\n'};

    int i = 0;
    while (i < LENGTH) {
        putchar(asciiCodes[i]);
        i = i + 1;
    }

    return 0;
}

Download andrew_rocks3.c



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) {
    // if we don't specify the size of an array being initialized C will make
    // it big enough to hold all the initializing elements (15 in this case)
    int asciiCodes[] = {'A','n','d','r','e','w',' ','R','o','c','k','s','!','\n',0};

    int i = 0;
    while (asciiCodes[i] != 0) {
        putchar(asciiCodes[i]);
        i = i + 1;
    }

    return 0;
}

Download andrew_rocks4.c



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) {
    // if we don't specify the size of an array being initialized C will make
    // it big enough to hold all the initializing elements (15 in this case)
    char asciiCodes[] = {'A','n','d','r','e','w',' ','R','o','c','k','s','!','\n',0};

    int i = 0;
    while (asciiCodes[i] != 0) {
        putchar(asciiCodes[i]);
        i = i + 1;
    }

    return 0;
}

Download andrew_rocks5.c



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) {
    char asciiCodes[] = "Andrew Rocks!\n";
    int i;

    i = 0;
    while (asciiCodes[i] != 0) {
        putchar(asciiCodes[i]);
        i = i + 1;
    }

    return 0;
}

Download andrew_rocks6.c



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";
    printf("%s", asciiCodes);
    return 0;
}

Download andrew_rocks7.c



Print the 128 ASCII character encodings

    #include <stdio.h>

int main(void) {
    int ascii;
    ascii = 0;
    while (ascii < 128) {
        printf("In ASCII %d prints as %c\n", ascii, ascii);
        ascii = ascii + 1;
    }
    return 0;
}

Download ascii.c


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("you entered the character: '%c' which has ASCII code %d\n", ch, ch);
        ch = getchar();
    }
    return 0;
}

Download getchar_eof.c


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;
    }
}


Download upper_case.c

convert a single character to an int
    #include <stdio.h>

#define MAX_LINE 4096

int main(int argc, char *argv[]) {
    char line[MAX_LINE];
    int i;

    printf("Enter a single digit number: ");
    fgets(line, MAX_LINE, stdin);
    if (line[0] >= '0' && line[0] <= '9') {
        i = line[0] - '0';
        printf("You entered %d\n", i);
    }
    return 0;
}

Download char2int.c

convert a string read from stdin using getchar to an int

    #include <stdio.h>

int main(void) {

    printf("Enter a number: ");
    int c = getchar();

    int n = 0;
    while (c >= '0' && c <= '9') {
        n = 10 * n + (c - '0');
        c = getchar();
    }
    printf("You entered %d\n", n);

    return 0;
}

Download string2int_getchar.c

print last argument
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    if (argc == 1) {
        printf("I have no arguments\n");
    } else {
        printf("my last argument is %s\n", argv[argc - 1]);
    }
    return 0;
}

Download last_argument.c

print command line argument
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int i;
    printf("argc=%d\n", argc);
    i = 0;
    while (i < argc) {
        printf("argv[%d]=%s\n", i, argv[i]);
        i = i + 1;
    }
    return 0;
}

Download print_arguments.c


Convert command-line arguments to integers and print their sum.

No check is made that the command-line arguments are actually integers.
See strol 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) {
       sum = sum + atoi(argv[argument]);
       argument= argument + 1;
    }
    printf("sum of command-line arguments = %d\n", sum);

    return 0;
}

Download sum_arguments.c


Simple example reading a line of input and examining characters
    #include <stdio.h>

#define SIZE 8000

int main(void) {
    char x[SIZE];

    printf("Enter some input: ");
    if (fgets(x, SIZE, stdin) == NULL) {
        printf("Could not read any characters\n");
        return 0;
    }

    // the built-in function strlen could be used here
    int nCharacters = 0;
    while (x[nCharacters] != '\n' && x[nCharacters] != '\0') {
        nCharacters = nCharacters + 1;
    }

    // if we don't find a newline - the whole line can't have been read
    if (x[nCharacters] != '\n') {
        printf("Could not read read entire line\n");
        return 0;
    }

    printf("That line contained %d characters\n", nCharacters);

    if (nCharacters > 0) {
       printf("The first character was %c\n", x[0]);
       printf("The last character was %c\n", x[nCharacters-1]);
    }
    return 0;
}

Download last_character.c


Read lines until eof
    #include <stdio.h>

#define MAX_LINE 1024

int main(void) {
    char line[MAX_LINE];

    // fgets returns NULL if it can't read any characters
    while (fgets(line, MAX_LINE, stdin) != NULL) {
        printf("you entered the line: %s", line);
    }
    return 0;
}

Download fgets_eof.c

convert a string read from stdin to an int using the atoi function from the standard C library note no error checking

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

#define MAX_LINE 4096

int main(int argc, char *argv[]) {
    char line[MAX_LINE] = {0};
    int n;

    printf("Enter a number: ");
    fgets(line, MAX_LINE, stdin);
    n = atoi(line);
    printf("You entered %d\n", n);

    return 0;
}

Download string2int_atoi.c

convert a string read from stdin using fgets to an int

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

#define MAX_LINE 4096


int main(void) {
    char line[MAX_LINE] = {0};

    printf("Enter a number: ");
    fgets(line, MAX_LINE, stdin);
    int n = 0;
    int i = 0;
    while (line[i] > '0' && line[i] < '9') {
        n = 10 * n + (line[i] - '0');
        i = i + 1;
    }
    printf("You entered %d\n", n);
    return 0;
}

Download string2int_fgets.c


Read numbers until eof or non-number encountered
    #include <stdio.h>

int main(void) {
    int num;
    // scanf returns the number of items read
    while (scanf("%d", &num) == 1) {
        printf("you entered the number: %d\n", num);
    }
    return 0;
}

Download scanf_eof.c


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

    // using an assignment in a loop/if condition is
    // not recommended for novice programmers
    // but is used widely by experienced C programmers

    int ch;
    while ((ch = getchar()) != EOF) {
        printf("you entered the character: '%c' which has ASCII code %d\n", ch, ch);
    }
    return 0;
}

Download getchar_eof1.c


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 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) {
        int i = 0;

        // count how many characters differ
        // between line & lastLine

        int differences = 0;
        while (line[i] != '\0' && lastLine[i] != 0) {
            if (lastLine[i] != line[i]) {
                differences = differences + 1;
            }
            i = i + 1;
        }

        if (differences == 0) {
            // lines are identical
            printf("Snap!\n");
        }

        // arrays can't be assigned so copy elements
        // of lastLine to line using a loop
        int j = 0;
        while (line[j] != '\0') {
            lastLine[j] = line[j];
            j = j + 1;
        }
        lastLine[j] = '\0';

        printf("Enter line: ");
    }

    return 0;
}

Download snap_line0.c


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 compareArrays & copyArray calls to with (strcmp & strcpy) from <string.h>

    #include <stdio.h>

#define MAX_LINE 4096

int compareArrays(char array1[], char array2[]);
void copyArray(char destinationArray[], char sourceArray[]);


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 (compareArrays(line, lastLine) == 0) {
            // lines are identical
            printf("Snap!\n");
        }

        copyArray(lastLine, 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 compareArrays(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 sourceArray to destinationArray
// sourceArray must be a null-terminated char array
// destinationArray must be large enough to hold string
// strcpy from  <string.h> performs the same function

void copyArray(char destinationArray[], char sourceArray[]) {
    int i = 0;
    while (sourceArray[i] != '\0') {
        destinationArray[i] = sourceArray[i];
        i = i + 1;
    }
    destinationArray[i] = '\0';
}

Download snap_line1.c

Reading And Writing Files

Simple example of file creation creates file "andrew.txt" containing 1 line ("Andrew rules!")
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    FILE *outputStream;

    outputStream = fopen("andrew.txt", "a");
    if (outputStream == NULL) {
        fprintf(stderr, "%s: open of '%s' failed\n", argv[0], "andrew.txt");
        return 1;
    }

    fprintf(outputStream, "Andrew rules!\n");
    fclose(outputStream);

    return 0;
}

Download create_file.c


Simple example of file creation appends to file "andrew.txt" the line "Andrew rules!"
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    FILE *outputStream;

    outputStream = fopen("andrew.txt", "a");
    if (outputStream == NULL) {
        perror("andrew.txt"); // prints why the open failed
        return 1;
    }

    fprintf(outputStream, "Andrew rules!\n");
    fclose(outputStream);

    return 0;
}

Download append_file.c


Simple implementation of reading files passed as command line arguments using fgetc - in other words cat
    #include <stdio.h>

int main(int argc, char *argv[]) {

    // go through a list of files specified on the command line
    // printing their contents in turn to standard output

    int argument = 1;
    while (argument < argc) {

        // FILE is an opaque (hidden type) defined in stdio.h
        // "r" indicate we are opening file to read contents

        FILE *stream = fopen(argv[argument], "r");
        if (stream == NULL) {
            perror(argv[argument]);  // prints why the open failed
            return 1;
        }

        // fgetc returns next the next byte (ascii code if its a text file)
        // from a stream
        // it returns the special value EOF if not more bytes can be read from the stream

        int c = fgetc(stream);

        // return  bytes from the stream (file) one at a time

        while (c != EOF) {
            fputc(c, stdout); // write the byte to standard output
            c = fgetc(stream);
        }

        argument = argument + 1;
    }
    return 0;
}

Download cat_fgetc.c


Simple implementation of reading files passed as command line arguments using fgets - in other words cat
    #include <stdio.h>
#define MAX_LINE 1024

int main(int argc, char *argv[]) {
    int argument = 1;
    while (argument < argc) {

        FILE *stream = fopen(argv[argument], "r");
        if (stream == NULL) {
            perror(argv[argument]);  // prints why the open failed
            return 1;
        }

        char line[MAX_LINE];
        while (fgets(line, MAX_LINE, stream) != NULL) {
            printf("%s", line);
        }

        argument = argument + 1;
    }
    return 0;
}

Download cat_fgets.c


Simple example of cp command copy contents of file specified as first argument to file specified as 2nd argument 8/5//18
    #include <stdio.h>

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <source file> <destination file>\n", argv[0]);
        return 1;
    }

    FILE *inputStream = fopen(argv[1], "r");
    if (inputStream == NULL) {
        perror(argv[1]);  // prints why the open failed
        return 1;
    }

    FILE *outputStream = fopen(argv[2], "w");
    if (outputStream == NULL) {
        // perror could be used for a better error message here
        fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[2]);
        return 1;
    }

    int c = fgetc(inputStream);
    while (c != EOF) {
        fputc(c, outputStream);
        c = fgetc(inputStream);
    }
    fclose(outputStream);

    return 0;
}

Download copy.c


Simple implementation of Unix wc command
It counts lines, word & characters in the file specified as an argument

This version uses fgetc, see also wc_fgets.c
See later version for more sophisticated argument handling

    #include <stdio.h>
#include <ctype.h>

#define MAX_LINE 4096

void process_stream(FILE *stream, char stream_name[]);

int main(int argc, char *argv[]) {

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    FILE *in = fopen(argv[1], "r");
    if (in == NULL) {
        // perror could be used for a better error message here
        fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[1]);
        return 1;
    }

    process_stream(in, argv[1]);

    return 0;
}

void process_stream(FILE *stream, char stream_name[]) {
    int line_count = 0;
    int character_count = 0;
    int word_count = 0;

    int lastc = ' ';
    int c = fgetc(stream);

    while (c != EOF) {
        if (c == '\n') {
            line_count = line_count + 1;
        }
        if (isspace(c) && !isspace(lastc)) {
            word_count = word_count + 1;
        }
        character_count = character_count + 1;
        lastc = c;
        c = fgetc(stream);
    }

    if (!isspace(lastc)) {
            word_count = word_count + 1;
    }

    printf("%s contains %d lines %d words %d characters\n", stream_name, line_count, word_count, character_count);
}

Download wc_fgetc0.c

/ Simple implementation of Unix wc command
It counts lines, word & characters from the files specified as arguments

If no files are specified instead stdin is processed
This allows use in a pipeline, e.g.: % dcc grep.c -o grep % dcc wc_fgetc1.c -o wc % ./grep return grep.c grep.c:30: return 1; grep.c:38: return 1; grep.c:44: return 0; % ./grep return grep.c | ./wc <stdin> contains 3 lines 9 words 85 characters

    #include <stdio.h>
#include <ctype.h>

#define MAX_LINE 4096

void process_stream(FILE *stream, char stream_name[]);

int main(int argc, char *argv[]) {

    if (argc == 1) {
        // if no files are specified, process stdin
        process_stream(stdin, "<stdin>");
    } else {
        int argument = 1;
        while (argument < argc) {
            FILE *in = fopen(argv[argument], "r");
            if (in == NULL) {
                // perror could be used for a better error message here
                fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[argument]);
                return 1;
            }

            process_stream(in, argv[argument]);

            argument = argument + 1;
        }
    }

    return 0;
}

void process_stream(FILE *stream, char stream_name[]) {
    int line_count = 0;
    int character_count = 0;
    int word_count = 0;

    int lastc = ' ';
    int c = fgetc(stream);

    while (c != EOF) {
        if (c == '\n') {
            line_count = line_count + 1;
        }
        if (isspace(c) && !isspace(lastc)) {
            word_count = word_count + 1;
        }
        character_count = character_count + 1;
        lastc = c;
        c = fgetc(stream);
    }

    if (!isspace(lastc)) {
            word_count = word_count + 1;
    }

    printf("%s contains %d lines %d words %d characters\n", stream_name, line_count, word_count, character_count);
}

Download wc_fgetc1.c


Simple implementation of Unix wc command
It counts lines, word & characters in the file specified as an argument

This version uses fgets
    #include <stdio.h>
#include <ctype.h>

#define MAX_LINE 4096

void process_stream(FILE *stream, char stream_name[]);

int main(int argc, char *argv[]) {
    FILE *in;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
        return 1;
    }

    in = fopen(argv[1], "r");
    if (in == NULL) {
        // perror could be used for a better error message here
        fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[1]);
        return 1;
    }
    process_stream(in, argv[1]);

    return 0;
}

void process_stream(FILE *stream, char stream_name[]) {
    char line[MAX_LINE];

    int line_count = 0;
    int character_count = 0;
    int word_count = 0;

    while (fgets(line, MAX_LINE, stream) != NULL) {
        int i = 0;
        while (line[i] != '\0') {
            if (i > 0 && isspace(line[i]) && !isspace(line[i - 1])) {
                word_count = word_count + 1;
            }
            character_count = character_count + 1;
            i = i + 1;
        }

        // this if handles case of line being longer than MAX_LINE
        if (!isspace(line[i - 1])) {
            word_count = word_count + 1;
        }  else if (line[i - 1] == '\n') {
            line_count = line_count + 1;
        }
    }

    printf("%s contains %d lines %d words %d characters\n", stream_name, line_count, word_count, character_count);
}

Download wc_fgets.c


Print lines containing specified pattern from the files specified as arguments
This version provides the unix filter behaviour where if no files are specified it process stdin

Note this code will produce incorrect results if matched lines contain >= MAX_LINE characters. Fixing this left as an exercise

    #include <stdio.h>
#include <string.h>

#define MAX_LINE 65536

void search_stream(FILE *stream, char stream_name[], char search_for[]);

int main(int argc, char *argv[]) {

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <prefix> <files>\n", argv[0]);
        return 1;
    } if (argc == 2) {
        search_stream(stdin, "<stdin>", argv[1]);
    } else {

        int argument = 2;
        while (argument < argc) {
            FILE *in = fopen(argv[argument], "r");
            if (in == NULL) {
                // perror could be used for a better error message here
                fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[argument]);
                return 1;
            }

            search_stream(in, argv[argument], argv[1]);
            argument = argument + 1;
        }

    }

    return 0;
}

void search_stream(FILE *stream, char stream_name[], char search_for[]) {
    char line[MAX_LINE];

    int line_number = 1;
    while (fgets(line, MAX_LINE, stream) != NULL) {
        if (strstr(line, search_for) != NULL) {
            printf("%s:%d:%s", stream_name, line_number, line);
        }
        line_number = line_number + 1;
    }
}


Download grep.c


Print lines starting with specified string from specified files

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

#define MAX_LINE 1024

int is_prefix(char prefix[], char str[]);

int main(int argc, char *argv[]) {

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <prefix> <files>\n", argv[0]);
        exit(1);
    }

    char *searchString = argv[1];
    int argument = 2;
    while (argument < argc) {

        FILE *stream = fopen(argv[argument], "r");
        if (stream == NULL) {
            // perror could be used for a better error message here
            fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[argument]);
            return 1;
        }

        char line[MAX_LINE];
        while (fgets(line, MAX_LINE, stream) != NULL) {
            if (is_prefix(searchString, line)) {
                printf("%s", line);
            }
        }

        fclose(stream);
        argument = argument + 1;
    }
    return 0;
}

// test if str starts with prefix
int is_prefix(char prefix[], char str[]) {
    int length = strlen(prefix);
    return strncmp(prefix, str, length) == 0;
}


Download prefix.c

print lines form file after replacing specified pattern after replacing specified pattern
    #include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINE 1024
#define MAX_REPLACEMENT_LINE 32768

void replace(char string[], char target[], char replacement[], char new_string[], int new_string_len);

int main(int argc, char *argv[]) {
    char line[MAX_LINE];
    char changed_line[MAX_REPLACEMENT_LINE];

    if (argc < 3) {
        fprintf(stderr, "Usage: %s <target> <replacement> <files>\n", argv[0]);
        exit(1);
    }

    char *target_string = argv[1];
    char *replacement_string = argv[2];

    int argument = 0;
    while (argument < argc) {
        FILE *stream = fopen(argv[argument], "r");
        if (stream == NULL) {
            // perror could be used for a better error message here
            fprintf(stderr, "%s: open of '%s' failed\n", argv[0], argv[argument]);
            return 1;
        }

        while (fgets(line, MAX_LINE, stream) != NULL) {
            replace(line, target_string, replacement_string, changed_line, MAX_REPLACEMENT_LINE);
            printf("%s", changed_line);
        }

        argument = argument + 1;
    }

    return 0;
}

// copy string to new_string replacing all instances of target with replacement

void replace(char string[], char target[], char replacement[], char new_string[], int new_string_len) {
    int target_length = strlen(target);
    int replacement_length = strlen(replacement);

    int i = 0;
    int j = 0;
    while (string[i] != '\0' && j < new_string_len - 1) {

        // if we have found the target string

        if (strncmp(target, &string[i], target_length) == 0) {

            // instead copy the replacement string to the new array

            strncpy(&new_string[j], replacement, replacement_length);
            i = i + target_length;
            j = j + replacement_length;
        } else {
            new_string[j] = string[i];
            i = i + 1;
            j = j + 1;
        }
    }

    new_string[j] = '\0';
}


Download replace.c

Pointers
a memory address as decimal & hexadecimal
    #include <stdio.h>

int main(void) {
    int x;

    printf("memory address of x in hexadecimal is %p\n", &x);

    return 0;
}

Download memory_address.c


Simple example illustrating use of pointers to return values from a function
    #include <stdio.h>

void powers(double x, double *square, double *cube) {
    *square = x * x;
    *cube = x * x * x;
}

int main(void) {
    double s, c;

    powers(42, &s, &c);

    printf("42^2 = %lf\n", s);
    printf("42^3 = %lf\n", c);
    return 0;
}

Download call_by_reference.c


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;
}

Download swap.c


Simple example illustrating use of pointers with array elements
    #include <stdio.h>


int main(void) {
    int nums[7] = {5,6,7,8,9,10,11};

    int *n = &nums[3];
    printf("n[0]=%d n[1]=%d n[2]=%d \n", n[0], n[1], n[2]);

    char string[12] = "Hello World";
    char *s = &string[6];
    printf("string = %s\n", string);
    printf("s = %s\n", s);
    printf("&string[9] = %s\n", &string[9]);

    s = &string[2];
    s[2] = '\0';     // equivalent to string[4] = '\0'
    printf("string = %s\n", string);
    printf("s = %s\n", s);

    return 0;
}

Download pointer_array.c


Simple example illustrating use of pointers with array elements
    #include <stdio.h>

void print_array(int array[], int array_length);

int main(void) {
    int nums[10] = {5,6,7,8,9,10,11,12,13,14};

    printf("Entire array: ");
    print_array(nums, 10);

    printf("Elements 3..6: ");
    print_array(&nums[3], 4);

    return 0;
}

void print_array(int array[], int array_length) {
    int i = 0;
    while (i < array_length) {
        printf("%d", array[i]);
        if (i != array_length - 1) {
            printf(",");
        }
        i = i + 1;
    }
    printf("\n");
}

Download subarray.c

print lines form file after replacing specified pattern after replacing specified pattern
    #include <stdio.h>
#include <string.h>

#define MAX_LINE 1024
#define MAX_REPLACEMENT_LINE 32768

void replace(char string[], char target[], char replacement[], char new_string[], int new_string_len);

int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usage: %s <target> <replacement> <files>\n", argv[0]);
        return 1;
    }
    char *target_string = argv[1];
    char *replacement_string = argv[2];

    int argument = 0;
    while (argument < argc) {
        FILE *stream = fopen(argv[argument], "r");
        if (stream == NULL) {
            perror(argv[argument]);
            return 1;
        }

        char line[MAX_LINE];
        while (fgets(line, MAX_LINE, stream) != NULL) {
            char changed_line[MAX_REPLACEMENT_LINE];
            replace(line, target_string, replacement_string, changed_line, MAX_REPLACEMENT_LINE);
            printf("%s", changed_line);
        }

        argument = argument + 1;
    }
    return 0;
}

// copy string to new_string replacing all instances of target with replacement

void replace(char string[], char target[], char replacement[], char new_string[], int new_string_len) {
    int target_length = strlen(target);
    int replacement_length = strlen(replacement);

    int i = 0;
    int j = 0;
    while (string[i] != '\0' && j < new_string_len - 1) {

        // if we have found the target string

        if (strncmp(target, &string[i], target_length) == 0) {

            // instead copy the replacement string to the new array

            strncpy(&new_string[j], replacement, replacement_length);
            i = i + target_length;
            j = j + replacement_length;
        } else {
            new_string[j] = string[i];
            i = i + 1;
            j = j + 1;
        }
    }

    new_string[j] = '\0';
}

Download replace.c

Extra C
    #include <stdio.h>

int x;

void f(int j) {
    x = j;
}

int main(void) {
    printf("%d\n", x); // prints 0
    f(42);
    printf("%d\n", x); // prints 42
    x = 1;
    printf("%d\n", x); // prints 1
    return 0;
}

Download global.c

    #include <stdio.h>

int f(int j) {
    static int x;
    x = x + j;
    return x;
}
int main(void) {
    printf("%d\n", f(1)); // prints 1
    printf("%d\n", f(2)); // prints 3
    printf("%d\n", f(4)); // prints 7
    return 0;
}

Download static.c

    #include <stdio.h>

int main(void) {
    int x = 42;
    int y = 11;
    double f;

    f = x / y;
    printf("42/11=%f\n", f); // prints 3.000000
    f = x/((double)y);       // convert y to a double
    printf("42/11=%f\n", f); // prints 3.818182
    return 0;
}

Download cast.c

Malloc
simple examples of using sizeof
    #include <stdio.h>

int main(void) {

    printf("sizeof (char) = %d\n", (int)sizeof (char));
    printf("sizeof (int) = %d\n", (int)sizeof (int));
    printf("sizeof (double) = %d\n", (int)sizeof (double));
    printf("sizeof int[10] = %d\n", (int)sizeof (int[10]));
    printf("sizeof int * = %d\n", (int)sizeof (int *));
    printf("sizeof \"hello\" = %d\n", (int)sizeof "hello");

    return 0;
}

Download sizeof.c

simple example of using malloc to create an array
Read n numbers and print them in reverse order
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {

    int n;
    printf("Read how many numbers? ");
    scanf("%d", &n);

    int *numbers = malloc(n * sizeof (int));
    if (numbers == NULL) {
        fprintf(stderr, "%s: malloc failed\n", argv[0]);
        return 1;
    }

    for (int i = 0; i < n; i = i + 1) {
        scanf("%d", &numbers[i]);
    }

    printf("Numbers reversed are:\n");
    for (int i = n - 1; i >= 0; i = i - 1) {
        printf("%d\n", numbers[i]);
    }

    // free the allocated storage
    // this would happen on program exit anyway
    free(numbers);
    return 0;
}

Download malloc_array.c

example of using malloc to progressively allocate larger array as needed
Read n numbers and print them in reverse order
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int n = 0;
    int arraySize = 4;
    int *array = malloc(arraySize * sizeof (int));
    if (array == NULL) {
        fprintf(stderr, "%s: malloc failed\n", argv[0]);
        return 1;
    }

    while (scanf("%d", &array[n]) == 1) {
        n = n + 1;
        if (n == arraySize) {

            // allocate larger array
            int newArraySize = 2 * arraySize;
            int *newArray = malloc(newArraySize * sizeof (int));
            if (newArray == NULL) {
                fprintf(stderr, "%s: malloc failed\n", argv[0]);
                return 1;
            }

            // copy contents of old array to new array
            for (int i = 0; i < arraySize; i = i + 1) {
                newArray[i] = array[i];
            }

            // deallocate old array
            free(array);

            // change pointer to new array
            array = newArray;
            arraySize = newArraySize;
            printf("Array size increased to %d\n", arraySize);
        }
    }


    printf("Numbers reversed are:\n");
    for (int i = n - 1; i >= 0; i = i - 1) {
        printf("%d\n", array[i]);
    }

    // free the allocated storage
    // this would happen on program exit anyway
    free(array);
    return 0;
}

Download grow_array0.c

example of using realloc to progressively allocate larger array as needed
Read n numbers and print them in reverse order
    #include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    int n = 0;
    int arraySize = 4;
    int *array = malloc(arraySize * sizeof (int));
    if (array == NULL) {
        fprintf(stderr, "%s: malloc failed\n", argv[0]);
        return 1;
    }

    while (scanf("%d", &array[n]) == 1) {
        n = n + 1;
        if (n == arraySize) {
            // allocate larger array
            arraySize = 2 * arraySize;
            array = realloc(array, arraySize * sizeof (int));
            if (array == NULL) {
                fprintf(stderr, "%s: realloc failed\n", argv[0]);
                return 1;
            }
            printf("Array size increased to %d\n", arraySize);
        }
    }


    printf("Numbers reversed are:\n");
    for (int i = n - 1; i >= 0; i = i - 1) {
        printf("%d\n", array[i]);
    }

    // free the allocated storage
    // this would happen on program exit anyway
    free(array);
    return 0;
}

Download grow_array1.c

Lists
$ dcc list.c
$ a.out

Enter a number: 1
Enter a number: 2
Enter a number: 3
Enter a number: 4
Enter a number: 5
Enter a number:
List entered was: [1, 2, 3, 4, 5]
First element in list is: 1.
Last element in list is: 5.
Length of list is: 5.
Sum of the list is: 15. 42 is not in the list.

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

struct node {
    struct node *next;
    int         data;
};

struct node *create_node(int data, struct node *next);
struct node *last(struct node *head);
struct node *append(struct node *head, int value);
int sum(struct node *head);
void print_list(struct node *head);
int length(struct node *head);
struct node *find_node(struct node *head, int data);

int
main(int argc, char *argv[]) {
    struct node *head = NULL;

    while (1) {
        int number;
        printf("Enter a number: ");
        if (scanf("%d", &number) != 1) {
            break;
        }
        head =  append(head, number);
    }

    if (head == NULL) {
        printf("List is empty.\n");
        return 0;
    }
    printf("\nList entered was: ");
    print_list(head);

    printf("\nFirst element in list is: %d.\n", head->data);
    printf("Last element in list is: %d.\n", last(head)->data);
    printf("Length of list is: %d.\n", length(head));
    printf("Sum of the list is: %d.\n", sum(head));

    if (find_node(head, 42) != NULL) {
        printf("42 is in the list.\n");
    } else {
        printf("42 is not in the list.\n");
    }
    return 0;
}


// Create a new struct node containing the specified data,
// and next fields, return a pointer to the new struct node.

struct node *create_node(int data, struct node *next) {
    struct node *n = malloc(sizeof (struct node));
    if (n == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    n->data = data;
    n->next = next;
    return n;
}

// return pointer to last node in list
// NULL is returned if list is empty

struct node *last(struct node *head) {
    if (head == NULL) {
        return NULL;
    }

    struct node *n = head;
    while (n->next != NULL) {
        n = n->next;
    }
    return n;
}


// create a new list node containing value
// and append it to end of list

struct node *append(struct node *head, int value) {
    // new node will be last in list, so next field is NULL
    struct node *n = create_node(value, NULL);
    if (head == NULL) {
        // new node is now  head of the list
        return n;
    } else {
        // change next field of last list node
        // from NULL to new node
        last(head)->next = n;  /* append node to list */
        return head;
    }
}

// return sum of list data fields

int sum(struct node *head) {
    int sum = 0;
    struct node *n = head;
    // execute until end of list
    while (n != NULL) {
        sum += n->data;
        // make n point to next item
        n = n->next;
    }
    return sum;
}

// return sum of list data fields: using for loop

int sum1(struct node *head) {
    int sum = 0;
    for (struct node *n = head; n != NULL; n = n->next) {
        sum += n->data;
    }
    return sum;
}


// print contents of list in Python syntax

void print_list(struct node *head) {
    printf("[");
    for (struct node *n = head; n != NULL; n = n->next) {
        printf("%d", n->data);
        if (n->next != NULL) {
            printf(", ");
        }
    }
    printf("]");
}


// return count of nodes in list

int length(struct node *head) {
    int len = 0;
    for (struct node *n = head; n != NULL; n = n->next) {
        len = len + 1;
    }
    return len;
}


// return pointer to first node with specified data value
// return NULL if no such node

struct node *find_node(struct node *head, int data) {
    struct node *n = head;

    // search until end of list reached
    while (n != NULL) {
        // if matching item found return it
        if (n->data == data) {
            return n;
        }

        // make node point to next item
        n = n->next;
    }

    // item not in list
    return NULL;
}

// previous function written as for loop

struct node *find_node1(struct node *head, int data) {
    for (struct node *n = head; n != NULL; n = n->next) {
        if (n->data == data) {
            return n;
        }
    }
    return NULL;
}

// previous function written as a more concise while loop

struct node *find_node2(struct node *head, int data) {
    struct node *n = head;
    while (n != NULL && n->data != data) {
       n = n->next;
    }
    return n;
}

Download list.c

linked list processing functions from list.c - recursive versions
    #include <stdio.h>
#include <stdlib.h>

struct node {
    struct node *next;
    int         data;
};

struct node *create_node(int data, struct node *next);
struct node *last(struct node *head);
struct node *append(struct node *head, int value);
int sum(struct node *head);
void print_list(struct node *head);
void print_list_items(struct node *head);
int length(struct node *head);
struct node *find_node(struct node *head, int data);

int
main(int argc, char *argv[]) {
    struct node *head = NULL;

    while (1) {
        int number;
        printf("Enter a number: ");
        if (scanf("%d", &number) != 1) {
            break;
        }
        head = append(head, number);
    }

    if (head == NULL) {
        printf("List is empty.\n");
        return 0;
    }
    printf("\nList entered was: ");
    print_list(head);

    printf("\nFirst element in list is: %d.\n", head->data);
    printf("Last element in list is: %d.\n", last(head)->data);
    printf("Length of list is: %d.\n", length(head));
    printf("Sum of the list is: %d.\n", sum(head));

    if (find_node(head, 42) != NULL) {
        printf("42 is in the list.\n");
    } else {
        printf("42 is not in the list.\n");
    }
    return 0;
}


// Create a new struct node containing the specified data,
// and next fields, return a pointer to the new struct node.

struct node *create_node(int data, struct node *next) {
    struct node *n = malloc(sizeof (struct node));
    if (n == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(1);
    }
    n->data = data;
    n->next = next;
    return n;
}

// return pointer to last node in list
// NULL is returned if list is empty

struct node *last(struct node *head) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    return last(head->next);
}


// create a new list node containing value
// and append it to end of list

struct node *append(struct node *head, int value) {
    if (head == NULL) {
        return create_node(value, NULL);
    }
    head->next = append(head->next, value);
    return head;
}

// return sum of list data fields: using recursive call

int sum(struct node *head) {
    if (head == NULL) {
        return 0;
    }
    return head->data + sum(head->next);
}

// print contents of list in Python syntax

void print_list(struct node *head) {
    printf("[");
    if (head != NULL) {
        print_list_items(head);
    }
    printf("]");
}

void print_list_items(struct node *head) {
    printf("%d", head->data);
    if (head->next != NULL) {
        printf(", ");
        print_list_items(head->next);
    }
}

// return count of nodes in list

int length(struct node *head) {
    if (head == NULL) {
        return 0;
    }
    return 1 + length(head->next);
}


// return pointer to first node with specified data value
// return NULL if no such node

struct node *find_node(struct node *head, int data) {
    if (head == NULL || head->data == data) {
        return head;
    }
    return find_node(head->next, data);
}

Download list_recursive.c

Stacks And Queues

Three implementations of a Stack Abstract Data Type https://en.wikipedia.org/wiki/Abstract_data_type
$ dcc stack_example.c stack_list.c -o stack_example $ a.out 3 12 12 11 10 0 $ dcc stack_example.c stack_array.c -o stack_example $ a.out 3 12 12 11 10 0 $ dcc stack_example.c stack_realloc.c -o stack_example $ a.out 3 12 12 11 10 0


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

int main(void) {
    stack s;

    s = stack_create();

    stack_push(s, 10);
    stack_push(s, 11);
    stack_push(s, 12);

    printf("%d\n", stack_size(s)); // prints 3

    printf("%d\n", stack_top(s)); // prints 12

    printf("%d\n", stack_pop(s)); // prints 12
    printf("%d\n", stack_pop(s)); // prints 11
    printf("%d\n", stack_pop(s)); // prints 10

    printf("%d\n", stack_size(s)); // prints 0

    return 0;
}

Download stack_example.c

    /*
Stack Abstract Data Type
https://en.wikipedia.org/wiki/Abstract_data_type

Actual implementation of stack opaque to (hidden from) user
*/

typedef struct stack_internals *stack;

stack stack_create(void);           // create a new stack
void stack_free(stack s);           // free a stack
void stack_push(stack s, int item); // add new item to stack
int stack_pop(stack s);             // remove top item from stack and return it
int stack_is_empty(stack s);        // return true if stack is empty
int stack_top(stack s);             // return top item from stack but don't remove it
int stack_size(stack s);            // return number elements in stack

Download stack.h


Implementation of stack Abstract Data Type with an array


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

#define MAX 2048

struct stack_internals {
    int elements[MAX];
    int top;
};

// create a new stack
stack stack_create(void) {
    stack s = malloc(sizeof *s);
    if (s == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    s->top = 0;
    return s;
}

// add new item to stack
void stack_push(stack s, int item) {
    if (s->top == MAX) {
        fprintf(stderr, "push() exceeds maximum stack size %d\n", MAX);
        exit(1);
    }
    s->elements[s->top] = item;
    s->top = s->top + 1;
}

// remove top item from stack and return it
int stack_pop(stack s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "pop() of empty stack\n");
        exit(1);
    }
    s->top = s->top - 1;
    return s->elements[s->top];
}

// return true if stack is empty
int stack_is_empty(stack s) {
    return s->top == 0;
}

// return top item from stack but don't remove it
int stack_top(stack s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "top() of empty stack\n");
        exit(1);
    }
    return s->elements[s->top-1];
}

// return number elements in stack
int stack_size(stack s) {
    return s->top;
}

// free a stack
void stack_free(stack s) {
    free(s);
}

Download stack_array.c


Implementation of stack Abstract Data Type with a linked list



Implementation of stack ADT with a linked list
    #include <stdio.h>
#include <stdlib.h>
#include "stack.h"

struct stack_internals {
    struct node   *top;
    int            size;
};

struct node {
    int       data;
    struct node *next;
};

// create a new stack
stack stack_create(void) {
    stack s = malloc(sizeof *s);
    if (s == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    s->top = NULL;
    s->size = 0;
    return s;
}

// add new item to stack
void stack_push(stack s, int item) {
    struct node *n = malloc(sizeof *n);
    n->data = item;
    n->next  = s->top;
    s->top = n;
    s->size = s->size + 1;
}

// remove top item from stack and return it
int stack_pop(stack s) {
    int i;
    struct node *n;

    if (stack_is_empty(s)) {
        fprintf(stderr, "pop() of empty stack\n");
        exit(1);
    }

    n = s->top;
    i = n->data;
    s->top = s->top->next;
    s->size = s->size - 1;
    free(n);
    return i;
}

// return true if stack is empty
int stack_is_empty(stack s) {
    return s->top == NULL;
}

// return top item from stack but don't remove it
int stack_top(stack s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "top() of empty stack\n");
        exit(1);
    }
    return s->top->data;
}

// return number elements in stack
int stack_size(stack s) {
    return s->size;
}

// free a stack
void stack_free(stack s) {
    while (!stack_is_empty(s)) {
        stack_pop(s);
    }
    free(s);
}

Download stack_list.c


Implementation of stack Abstract data Type with malloc/realloc


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

#define INITIAL_STACK_SIZE 1024

struct stack_internals {
    int *elements;
    int size;
    int top;
};

// create a new stack
stack stack_create(void) {
    stack s = malloc(sizeof *s);
    if (s == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    s->size = INITIAL_STACK_SIZE;
    s->elements = malloc(s->size * sizeof s->elements[0]);
    if (s->elements == NULL) {
        fprintf(stderr, "Out of memory\n");
        exit(1);
    }
    s->top = 0;
    return s;
}

// add new item to stack
void stack_push(stack s, int item) {
    if (s->top == s->size) {
        s->size = s->size * 2;
        s->elements = realloc(s->elements, s->size * sizeof s->elements[0]);
        if (s->elements == NULL) {
            fprintf(stderr, "Out of memory\n");
            exit(1);
        }
    }
    s->elements[s->top] = item;
    s->top = s->top + 1;
}

// remove top item from stack and return it
int stack_pop(stack s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "pop() of empty stack\n");
        exit(1);
    }
    s->top = s->top - 1;
    return s->elements[s->top];
}

// return true if stack is empty
int stack_is_empty(stack s) {
    return s->top == 0;
}

// return top item from stack but don't remove it
int stack_top(stack s) {
    if (stack_is_empty(s)) {
        fprintf(stderr, "top() of empty stack\n");
        exit(1);
    }
    return s->elements[s->top-1];
}

// return number elements in s
int stack_size(stack s) {
    return s->top;
}

// free a stack
void stack_free(stack s) {
    free(s->elements);
    free(s);
}

Download stack_realloc.c



Read stdin checking { [ ( left brackets match ) ] } right brackets
Other characters ignored.
$ dcc brackets.c stack_list.c -o brackets # or stack_array.c or stack_realloc.c $ ./brackets [ {{ ( ) } ]
Error: bracket mismatch '{' versus ']'


    #include <stdio.h>

#include "stack.h"


int main(void) {

    stack s = stack_create();

    int ch = getchar();
    while (ch != EOF) {

        if (ch == '{' || ch == '(' || ch == '[') {
            stack_push(s, ch);
        } else if (ch == '}' || ch == ')' || ch == ']') {
            if (stack_is_empty(s)) {
                printf("Error: unbalanced '%c'\n", ch);
                return 1;
            }

            int left_bracket = stack_pop(s);
            if (
                (ch == '}' && left_bracket != '{') ||
                (ch == ')' && left_bracket != '(') ||
                (ch == ']' && left_bracket != '[')
                ) {
                printf("Error: bracket mismatch '%c' versus '%c'\n", left_bracket, ch);
                return 1;
            }
        }

        ch = getchar();
    }

    if (!stack_is_empty(s)) {
        printf("Error: unbalanced '%c'\n", stack_pop(s));
        return 1;
    }

    return 0;
}

Download brackets.c


Reverse Polish notation calculator using stack ADT
https://en.wikipedia.org/wiki/Reverse_Polish_notation
$ dcc postfix.c stack_list.c -o postfix # or stack_array.c or stack_realloc.c $ ./postfix 15 7 1 1 + - / 3 * 2 1 1 + + -
Result: 5


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

#include "stack.h"

#define MAX_LINE 4096
int main(void) {

    char line[4096];
    while (fgets(line, sizeof line, stdin) != NULL) {
        stack s = stack_create();

        int i = 0;
        while (line[i] != '\0') {
            int ch = line[i];

            if (isdigit(ch)) {
                // convert chars to num push number onto stack
                // and skip over digits

                int num = atoi(&line[i]);

                stack_push(s, num);

                while (isdigit(line[i])) {
                    i = i + 1;
                }
            } else if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {

                // pop 2 values from stack
                // calculate result
                // push result onto stack

                int a = stack_pop(s);
                int b = stack_pop(s);

                int result;
                if (ch == '+') {
                    result = b + a;
                } else if (ch == '-') {
                    result = b - a;
                } else if (ch == '*') {
                    result = b * a;
                } else {
                    result = b / a;
                }

                stack_push(s, result);
            }
            i = i + 1;
        }

        printf("Result: %d\n", stack_pop(s));
    }

    return 0;
}

Download postfix.c

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

#include "queue.h"

int main(void) {
    queue q;

    q = queue_create();
    queue_enqueue(q, 10);
    queue_enqueue(q, 11);
    queue_enqueue(q, 12);

    printf("%d\n", queue_size(q)); // prints 3
    printf("%d\n", queue_front(q)); // prints 10
    printf("%d\n", queue_dequeue(q)); // prints 10
    printf("%d\n", queue_dequeue(q)); // prints 11
    printf("%d\n", queue_dequeue(q)); // prints 12

    return 0;
}

Download queue_example.c

    /*
Queue Abstract Data Type

https://en.wikipedia.org/wiki/Abstract_data_type
 
Actual implementation of queue opaque to (hidden from) user
*/

typedef struct queue_internals *queue;

queue queue_create(void);                  // create a new queue
void queue_free(queue q);              // free a queue
void queue_enqueue(queue q, int item); // add new item to queue
int queue_dequeue(queue q);            // remove next item from queue and return it
int queue_is_empty(queue q);           // return true if queue is empty
int queue_front(queue q);              // return next item from queue but don't remove it
int queue_size(queue q);               // return number elements in queue

Download queue.h


Implementation of stack ADT with a linked list
completion left as an exercise
    #include <stdio.h>
#include <stdlib.h>
#include "queue.h"

struct queue_internals {
};

struct node {
    struct node *next;
    int       data;
};

// create a new queue
queue queue_create(void) {
    return NULL;
}

// add new item to queue
void queue_enqueue(queue queue, int item) {
}

// remove top item from queue and return it
int queue_dequeue(queue queue) {
    return 0;
}

// return true if queue is empty
int queue_is_empty(queue queue) {
    return 0;
}

// return top item from queue but don't remove it
int queue_front(queue queue) {
    return 0;
}

// return number elements in queue
int queue_size(queue queue) {
    return 0;
}

// free a queue
void queue_free(queue queue) {
}

Download queue_list.c

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

void f() {
    int i;
    int x = 9;
    int a[10];

    for (i = 0; i < 16; i++)
        printf("%2d: Address %x contains %p\n", i, &a[10+i], a[10+i]);
}

int main(void) {
    int a = 7;
    printf("function main is at address 0x%x\n", &main);
    printf("function f is at address 0x%x\n", &f);
    f();
    return 0;
}

Download stack_inspect.c



Run at CSE like this
$ gcc-7 invalid0.c -o invalid0 $ ./invalid0 42 42 42 77 77 77 77 77 77 77


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

int main(void) {
    int a[10];
    int b[10];
    printf("a[0] is at address %p\n",&a[0]);
    printf("a[9] is at address %p\n", &a[9]);
    printf("b[0] is at address %p\n",&b[0]);
    printf("b[9] is at address %p\n", &b[9]);

    for (int i = 0; i < 10; i++) {
        a[i] = 77;
    }

    // loop writes to b[10] .. b[12] which don't exist -
    // with gcc 7.3 on x86_64/Linux
    // b[12] is stored where a[0] is stored
    // with gcc 7 on CSE lab machines
    // b[10] is stored where a[0] is stored

    for (int i = 0; i <= 12; i++) {
        b[i] = 42;
    }

    // prints 42 77 77 77 77 77 77 77 77 77 on x86_64/Linux
    // prints 42 42 42 77 77 77 77 77 77 77 at CSE
    for (int i = 0; i < 10; i++) {
        printf("%d ", a[i]);
    }
    printf("\n");

    return 0;
}

Download invalid0.c



Run at CSE like this
$ gcc-7 invalid1.c -o invalid1 $ ./invalid1 42 42 42 77 77 77 77 77 77 77


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

int main(void) {
    int i;
    int a[10];
    printf("i is at address %p\n", &i);
    printf("a[0] is at address %p\n", &a[0]);
    printf("a[9] is at address %p\n", &a[9]);
    printf("a[10] would be stored at address %p\n", &a[10]);

    // loop writes to a[10] .. a[11] which don't exist -
    // but with gcc 7 on x86_64/Linux
    // i would be stored where a[11] is stored

    for (i = 0; i <= 11; i++) {
        a[i] = 0;
    }

    return 0;
}

Download invalid1.c



Run at CSE like this
$ gcc-7 invalid2.c -o invalid2 $ ./invalid2 answer=42


    #include <stdio.h>

void f(int x);

int main(void) {
    int answer = 36;
    printf("answer is stored at address %p\n", &answer);

    f(5);
    printf("answer=%d\n", answer); // prints 42 not 36g

    return 0;
}

void f(int x) {
    int a[10];

    // a[19] doesn't exist
    // with gcc-7 at CSE variable answer in main
    // happens to be where a[21] would be
    // on 64-bit Linux try 19 instead of 21

    printf("a[21] would be stored at address %p\n", &a[21]);

    a[21] = 42;
}

Download invalid2.c



Run at CSE like this
$ gcc-7 invalid3.c -o invalid3 $ ./invalid3
I will never be printed. argc was 1 $
    #include <stdio.h>
#include <stdlib.h>

void f(void);


void f(void);

int main(int argc, char *argv[]) {

    f();

    if (argc > 0) {
        printf("I will always be printed.\n");
    }

    if (argc <= 0) {
        printf("I will never be printed.\n");
    }

    printf("argc was %d\n", argc);
    return 0;
}


void f() {
    int a[10];

    // function f has it return address on the stack
    // the call of function f from main should return to
    // the next statement which is:  if (argc > 0)
    //
    // with gcc7 at CSE  f's return address is stored where a[11] would be
    //
    // so changing a[11] changes where the function returns
    //
    // adding 28 to a[11] happens to cause it to return several statements later
    // at the printf("I will never be printed.\n");
    //
    // on 64 bit linux  machines try instead a[14] += 24

    a[11] += 28;
}


Download invalid3.c



Run at CSE like this
$ gcc-7 invalid4.c -o invalid4 $ ./invalid4 authenticated is at address 0xff94bf44 password is at address 0xff94bf3c
Enter your password: 123456789
Welcome. You are authorized. $
    #include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    int authenticated = 0;
    char password[8];

    printf("authenticated is at address %p\n",&authenticated);
    printf("password[8] would be at address %p\n",&password[8]);

    printf("Enter your password: ");
    int i = 0;
    int ch = getchar();
    while (ch != '\n' && ch != EOF) {
        password[i] = ch;
        ch = getchar();
        i = i + 1;
    }
    password[i] = '\0';

    if (strcmp(password, "secret") == 0) {
        authenticated = 1;
    }

    // a password longer than 8 characters will overflow the array password
    // the variable authenticated is at the address where
    // where password[8] would be and gets overwritten
    //
    // This allows access without knowing the correct password

    if (authenticated) {
        printf("Welcome. You are authorized.\n");
    } else {
        printf("Welcome. You are unauthorized.  Your death will now be implemented.\n");
        printf("Welcome. You will experience a tingling sensation and then death. \n");
        printf("Remain calm while your life is extracted.\n");
    }

    return 0;
}

Download invalid4.c

Sorting And Searching
$ dcc compare_search.c
$ ./a.out 1000000

Array size is 1000000, elements are: 3 10 14 6 26 49 61 69 72 73 105 130 36 137 141 58 150 184 197 159 209 ...

Search for? 49
Linear search: 49 is in the numbers - search took 6 operations
Binary search: 49 is in the numbers - search took 20 operations

Search for? 42
Linear search: 42 is not in the numbers - search took 1000000 operations
Binary search: 42 is not in the numbers - search took 20 operations


Instrument linear search and binary search with an operation counter and compare their performance on a sorted arrays of random numbers.

Array size is specified as a command line argument

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

int linear_search(int array[], int length, int x);
int binary_search(int array[], int length, int x);
void quicksort(int array[], int length);
void quicksort1(int array[], int lo, int hi);
int partition(int array[], int lo, int hi);
void sorted_random_ints(int array[], int length);
void random_ints(int array[], int length);

// we use a global variable to instrument the program
// and count operations performed

int operation_counter;

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <array-size>\n", argv[0]);
        exit(1);
    }
    int length = atoi(argv[1]);

    // use malloc to create an array so we can
    // because we may want an array too large to be a global variable

    int *numbers = malloc(length * sizeof (int));
    if (numbers == NULL) {
        fprintf(stderr, "%s: <array-size>\n", argv[0]);
        exit(1);
    }

    sorted_random_ints(numbers, length);

    printf("Array size is %d, elements are: ", length);

    for (int i = 0; i < length; i = i + 1) {
        printf(" %d", numbers[i]);
        if (i == 20) {
            printf(" ... ");
            i = length;
        }
    }
    printf("\n");

    while (1) {
        int x;
        printf("Search for? ");
        if (scanf("%d", &x) != 1) {
            free(numbers);
            return 0;
        }

        operation_counter = 0;
        printf("\nLinear search: ");
        if (linear_search(numbers, length, x) == 1) {
            printf("%d is in the numbers", x);
        } else {
            printf("%d is not in the numbers", x);
        }
        printf(" - search took %d operations\n", operation_counter);

        operation_counter = 0;
        printf("Binary search: ");
        if (binary_search(numbers, length, x) == 1) {
            printf("%d is in the numbers", x);
        } else {
            printf("%d is not in the numbers", x);
        }
        printf(" - search took %d operations\n\n", operation_counter);
    }
}

int linear_search(int array[], int length, int x) {

    for (int i = 0; i < length; i = i + 1) {
        operation_counter++;
        if (array[i] == x) {
            return 1;
        }
    }

    return 0;
}

int binary_search(int array[], int length, int x) {
    int lower = 0;
    int upper = length - 1;
    while (lower <= upper) {
        int mid = (lower + upper)/ 2;
        operation_counter++;
        if (array[mid] == x) {
            return 1;
        } else if (array[mid] > x) {
            upper = mid - 1;
        } else {
            lower = mid + 1;
        }
    }
    return 0;
}

// fill array with pseudo-random ints

void random_ints(int array[], int length) {
     for (int i = 0; i < length; i = i + 1) {
        array[i] = rand() % (10 * length);
    }
}

// fill array with pseudo-random ints in sorted (non-decreasing) order

void sorted_random_ints(int array[], int length) {
    random_ints(array, length);
    quicksort(array, length);
}

// https://en.wikipedia.org/wiki/Quicksort

void quicksort(int array[], int length) {
    quicksort1(array, 0, length - 1);
}

void quicksort1(int array[], int lo, int hi) {
    if (lo >= hi) {
        return;
    }
    // rearrange array so that
    // all elements smaller than pivot value are below it and
    // all element larger than pivot value are above it
    int p = partition(array, lo, hi);
    // sort lower part of array
    quicksort1(array, lo, p);

    // sort upper part of array
    quicksort1(array, p + 1, hi);
}


int partition(int array[], int lo, int hi) {
    int i = lo;
    int j = hi;

    // use middle value as pivot
    int pivotValue = array[(lo + hi) / 2];

    // start from left and right ends
    while (1) {

        // Look for pair to swap

        while (array[i] < pivotValue) {
            i = i + 1;
            operation_counter++;
        }

        while (array[j] > pivotValue) {
            j = j - 1;
            operation_counter++;
        }

        // No pair to swap so return
        if (i >= j) {
            return j;
        }
        // and swap them over
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
        i = i + 1;
        j = j - 1;
    }
}

Download compare_search.c

$ dcc compare_sort.c
$ ./a.out

Array size 10: bubblesort took 81 operations, quicksort took 24 operations
Array size 100: bubblesort took 8415 operations, quicksort took 457 operations
Array size 1000: bubblesort took 981018 operations, quicksort took 9351 operations
Array size 10000: bubblesort took 98790120 operations, quicksort took 102807 operations


Instrument quicksort and bubblesort with an operation counter and compare performance on arrays of random numbers of size 10..10000

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

// use a global variable to count operations
// at key points for both sorting algorithms
int operation_counter;

void bubblesort(int array[], int length);
void quicksort(int array[], int length);
void quicksort1(int array[], int lo, int hi);
int partition(int array[], int lo, int hi);
void random_ints(int array[], int length);

int main(void) {
    for (int n = 10; n <= 10000; n = n * 10) {
        int numbers1[n];
        int numbers2[n];

        random_ints(numbers1, n);
        for (int i = 0; i < n; i = i + 1) {
            numbers2[i] = numbers1[i];
        }

        printf("Array size %5d: ", n);
        operation_counter = 0;
        bubblesort(numbers1, n);
        printf(" bubblesort took %8d operations,", operation_counter);
        operation_counter = 0;
        quicksort(numbers2, n);
        printf("  quicksort took %6d operations\n", operation_counter);

        for (int i = 0; i < n; i = i + 1) {
            if(numbers2[i] != numbers1[i]) {
                printf("arrays differ at index %d\n", i);
                return 1;
            }
        }
    }
    return 0;
}

// https://en.wikipedia.org/wiki/Bubble_sort

void bubblesort(int array[], int length) {
    int swapped = 1;
    while (swapped) {
        swapped = 0;
        for (int i = 1; i < length; i = i + 1) {
            operation_counter++;
            if (array[i] < array[i - 1]) {
                int tmp = array[i];
                array[i] = array[i - 1];
                array[i - 1] = tmp;
                swapped = 1;
            }
        }
    }
}

// https://en.wikipedia.org/wiki/Quicksort

void quicksort(int array[], int length) {
    quicksort1(array, 0, length - 1);
}

void quicksort1(int array[], int lo, int hi) {
    if (lo >= hi) {
        return;
    }
    // rearrange array so that
    // all elements smaller than pivot value are below it and
    // all element larger than pivot value are above it
    int p = partition(array, lo, hi);
    // sort lower part of array
    quicksort1(array, lo, p);

    // sort upper part of array
    quicksort1(array, p + 1, hi);
}


int partition(int array[], int lo, int hi) {
    int i = lo;
    int j = hi;

    // use middle value as pivot
    int pivotValue = array[(lo + hi) / 2];

    // start from left and right ends
    while (1) {

        // Look for pair to swap

        while (array[i] < pivotValue) {
            i = i + 1;
            operation_counter++;
        }

        while (array[j] > pivotValue) {
            j = j - 1;
            operation_counter++;
        }

        // No pair to swap so return
        if (i >= j) {
            return j;
        }
        // and swap them over
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
        i = i + 1;
        j = j - 1;
    }
}

// fill array with pseudo-random ints

void random_ints(int array[], int length) {
     for (int i = 0; i < length; i = i + 1) {
        array[i] = rand() % (10 * length);
    }
}

Download compare_sort.c

Exam