You are on page 1of 99

BITS Pilani

K K Birla Goa Campus

CSF111: Computer Programming

Miscellaneous topics

Swaroop Joshi

2023
Multidimensional Arrays
Multidimensional Arrays

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


Multidimensional Arrays

Allocates storage for a two-


dimensional array that has 3
rows and 3 columns

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


Multidimensional Arrays

row⬇ | col ➡ 0 1 2
0 1 2 3
1 4 5 6
2 7 8 9

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; Assigns these 9 values to it
Multidimensional Arrays
void display_matrix(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%d ", mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


display_matrix(mat);
Multidimensional Arrays A function that takes a 2D array param
has a declaration similar to its prototype

void display_matrix(int mat[3][3])


{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%d ", mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


display_matrix(mat);
Multidimensional Arrays
void display_matrix(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%d ", mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}

1 2 3
4 5 6
7 8 9

int mat[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};


display_matrix(mat);
Multidimensional Arrays

row⬇ | col ➡ 0 1 2
0 1 2 3
1 4 5 6
2 7 8 9
Multidimensional Arrays Displaying the address of each
cell instead of its contents

void display_matrix_addr(int mat[3][3])


{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%p ", &mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}
Multidimensional Arrays
void display_matrix_addr(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%p ", &mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}
0x16fd6f444 0x16fd6f448 0x16fd6f44c
0x16fd6f450 0x16fd6f454 0x16fd6f458
0x16fd6f45c 0x16fd6f460 0x16fd6f464
Multidimensional Arrays
void display_matrix_addr(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%p ", &mat[r][c]); 1 4 5 6
printf("\n");
}
2 7 8 9
}
0x16fd6f444 0x16fd6f448 0x16fd6f44c
Note, address of ‘4’ is right
0x16fd6f450 0x16fd6f454 0x16fd6f458
after the address of ‘3’ 0x16fd6f45c 0x16fd6f460 0x16fd6f464
Multidimensional Arrays
void display_matrix_addr(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
for (int c = 0; c < 3; ++c)
printf("%p ", &mat[r][c]); 1 4 5 6
printf("\n");
} Elements of2a 2D array are7 stored 8 9
} consecutively; the row-size/col-size is
0x16fd6f444
arti 0x16fd6f448
cial; so you need to provide it0x16fd6f44c
in
0x16fd6f450
declarations 0x16fd6f454
and function 0x16fd6f458
parameters
0x16fd6f45c 0x16fd6f460 0x16fd6f464

1 2 3 4 5 6 7 8 9
fi
Multidimensional Arrays
void display_matrix_addr(int mat[3][3])
{
for (int r = 0; r < 3; ++r) row⬇ | col ➡ 0 1 2
{ 0 1 2 3
Think of it cas =an0;
for (int array
c <of3;arrays:
++c)
printf("%p
num_rows rows ", &mat[r][c]);
of num_cols each 1 4 5 6
printf("\n");
}
2 7 8 9
}
0x16fd6f444 0x16fd6f448 0x16fd6f44c
0x16fd6f450 0x16fd6f454 0x16fd6f458
0x16fd6f45c 0x16fd6f460 0x16fd6f464

1 2 3 4 5 6 7 8 9
A note about declaring -D arrays

✤ You cannot change num_rows or num_cols once xed

✤ C allows you to skip the num_rows when initialising

✤ So int arr2d[][2] = {{1},{2},{3}}; is allowed,

✤ But int arr2d[3][] = {{1},{2},{3}}; is not.

✤ Applicable to function parameters too

✤ Declaring without dimensions and without initialisation is not allowed:

✤ int arr2d[][2]; will lead to a syntax error.


fi
2
-D arrays on the heap
2
-D arrays on the heap

int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++;
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
}

int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++;
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
}

int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}

int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c)
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);

release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
m: int**
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
5 6
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
5 6
}
2
Write the code for release_matrix
-D arrays on the heap and trace it with the diagram

int **alloc_matrix(int num_rows, int num_cols)


{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
5 6
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols)
{
int **m = calloc(num_rows, sizeof(int *));
for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int));
return m;
}
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
5 6
}
2
-D arrays on the heap
int **alloc_matrix(int num_rows, int num_cols) void release_matrix(int **m,
{ int num_rows,
int **m = calloc(num_rows, sizeof(int *)); int num_cols) {
for (int i = 0; i < num_rows; ++i) for (int i = 0; i < num_rows; ++i)
m[i] = calloc(num_cols, sizeof(int)); free(m[i]);
return m; free(m);
} }
Heap
int main() {
int **m1 = alloc_matrix(3, 2);
int k = 1;
for (int r = 0; r < 3; ++r)
for (int c = 0; c < 2; ++c) 1 2
m1[r][c] = k++; m1: int**
display_matrix(m1, 3, 2);
3 4
release_matrix(m1, 3, 2);
return 0;
5 6
}
2
Generalise to multidimensional arrays

✤ Example: int enrolment[3][5][4];

✤ Each cell contains the number of


students in one of the 3 campuses’
5 courses over 4 semesters

✤ 3 tables of size 5x4 each

✤ Each of its 3 x 5 x 4 elements is an int


Generalise to multidimensional arrays

✤ Example: int enrolment[3][5][4];

✤ Each cell contains the number of


students in one of the 3 campuses’
5 courses over 4 semesters

✤ 3 tables of size 5x4 each

✤ Each of its 3 x 5 x 4 elements is an int


Global variables

✤ Sometimes you want a variable (more likely, a constant) available


throughout the program and passing it as a function parameter does not
make sense

✤ You can declare such variables as global variables

✤ Their scope will be from the point of declaration to the end of the le

✤ Be careful with global variables as a local variable can mask their scope

fi
Preprocessor

✤ What happens when you #include a library?

✤ All its contents are copied into your program verbatim!

✤ This happens before compilation, in a phase called preprocessing

✤ The result of preprocessing is a single le which is then passed to the actual


compiler
fi
Other preprocessor commands

✤ #de ne

✤ De nes a macro

✤ De ned in stdio.h: #define FILENAME_MAX 1024

✤ Now you can use FILENAME_MAX to mean 1024 anywhere; it will be


expanded to 1024 before compilation
fi
fi
fi
Other preprocessor commands

This is not a constant!


✤ #de ne No compile time checks (e.g.,
type checking) is performed
✤ De nes a macro

✤ De ned in stdio.h: #define FILENAME_MAX 1024

✤ Now you can use FILENAME_MAX to mean 1024 anywhere; it will be


expanded to 1024 before compilation
fi
fi
fi
Conditional compilation
#include <stdio.h>

int max(int x, int y) { return x > y ? x : y; }

int greatest_of_3(int x, int y, int z) {


x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
These printf statements are not
compiled if DEBUG is not #de ned
Conditional compilation
#include <stdio.h>

int max(int x, int y) { return x > y ? x : y; }

int greatest_of_3(int x, int y, int z) {


x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
fi
These printf statements are not
compiled if DEBUG is not #de ned
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>

int max(int x, int y) { return x > y ? x : y; }

int greatest_of_3(int x, int y, int z) {


x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
fi
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
#define DEBUG 1
int max(int x, int y) { return x > y ? x : y; }

int greatest_of_3(int x, int y, int z) {


x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
#define DEBUG 1
int max(int x, int y) { return x > y ? x : y; }

int greatest_of_3(int x, int y, int z) {


x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} Now these statements are compiled and} executed
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
> gcc ifdebug.c ; ./a.out
#define DEBUG 1 Value of x is 20
int max(int x, int y) { return x > y ? x : y; } Value of x is 30
Largest = 30
int greatest_of_3(int x, int y, int z) {
x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} Now these statements are compiled and} executed
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
> gcc ifdebug.c ; ./a.out
#define DEBUG 1 Does not have to be de ned to 1 Value of x is 20
int max(int x, int y) { return x > y ? x : y; } Value of x is 30
Largest = 30
int greatest_of_3(int x, int y, int z) {
x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
fi
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
> gcc ifdebug.c ; ./a.out
#define DEBUG 1 Value of x is 20
int max(int x, int y) { return x > y ? x : y; } Value of x is 30
Largest = 30
int greatest_of_3(int x, int y, int z) {
x = max(x, y);
#ifdef DEBUG
printf("Value of x is %d\n", x);
#endif

x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
> gcc ifdebug.c ; ./a.out
Value of x is 20
int max(int x, int y) { return x > y ? x : y; } Value of x is 30
Largest = 30
int greatest_of_3(int x, int y, int z) {
x = max(x, y);
#ifdef DEBUG Can also be de ned while compiling > gcc ifdebug.c -DDEBUG; ./a.out
printf("Value of x is %d\n", x); Value of x is 20
#endif Value of x is 30
Largest = 30
x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
fi
Conditional compilation > gcc ifdebug.c ; ./a.out
Largest = 30
#include <stdio.h>
> gcc ifdebug.c ; ./a.out
Value of x is 20
int max(int x, int y) { return x > y ? x : y; } Value of x is 30
Largest = 30
int greatest_of_3(int x, int y, int z) {
x = max(x, y);
#ifdef DEBUG > gcc ifdebug.c -DDEBUG; ./a.out
printf("Value of x is %d\n", x); Value of x is 20
#endif Value of x is 30
Largest = 30
x = max(x, z);
#ifdef DEBUG int main() {
printf("Value of x is %d\n", x); int m3 = greatest_of_3(10, 20, 30);
#endif printf("Largest = %d\n", m3);

return x; return 0;
} }
Enums

✤ Sometimes you want to name some numeric values for better code
comprehension

✤ For example, instead of using ints 1, 2, 3, … for the seven days of the week,
you may want to create constants int MONDAY = 1, etc. so you can use
MONDAY, TUESDAY, etc. in your code and not worry about whether
MONDAY is 1 or 2

✤ But these constants have no relation to one another and maintaining them
can be cumbersome too
Enums
Enums

✤ Enumerations allow you to create


custom types with speci c values

✤ With some operations on them


fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

✤ Enumerations allow you to create


custom types with speci c values

✤ With some operations on them


fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

By default, the rst one is 0 and


the next ones are automatically
assigned prev+1;
✤ Enumerations allow you to create So wed = tue + 1

custom types with speci c values

✤ With some operations on them


fi
fi
If you assign a value to the rst
typedef enum {
Enums one, the remaining ones are
initialised accordingly
mon = 1, tue, wed, thu, fri, sat, sun
} day;

✤ Enumerations allow you to create


custom types with speci c values

✤ With some operations on them


fi
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

✤ Enumerations allow you to create


custom types with speci c values

✤ With some operations on them

✤ Relational, assignment, and


arithmetic operations are allowed
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day d = mon;

✤ Enumerations allow you to create


custom types with speci c values

✤ With some operations on them

✤ Relational, assignment, and


arithmetic operations are allowed
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day d = mon;

printf("Enter today's day as an integer \


✤ Enumerations allow you to create (starting with Monday as 1): ");
scanf("%d", &d);
custom types with speci c values

✤ With some operations on them

✤ Relational, assignment, and


arithmetic operations are allowed
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day d = mon;

printf("Enter today's day as an integer \


✤ Enumerations allow you to create (starting with Monday as 1): ");
scanf("%d", &d);
custom types with speci c values
if (d < sat)
✤ With some operations on them printf("It's not weekend\n");

✤ Relational, assignment, and


arithmetic operations are allowed
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day d = mon;

printf("Enter today's day as an integer \


✤ Enumerations allow you to create (starting with Monday as 1): ");
scanf("%d", &d);
custom types with speci c values
if (d < sat)
✤ With some operations on them printf("It's not weekend\n");

✤ Relational, assignment, and if (d < sat)


printf("%d days to weekend!\n", sat - d);
arithmetic operations are allowed
fi
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

✤ Write a function tomorrow that


takes a day and returns the next
day
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day tomorrow(day d)
✤ Write a function tomorrow that {
return d == sun ? mon : d + 1;
takes a day and returns the next }
day
typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day tomorrow(day d)
✤ Write a function tomorrow that {
return d == sun ? mon : d + 1;
takes a day and returns the next }
day

✤ Can also be used as array subscripts


typedef enum {
Enums mon = 1, tue, wed, thu, fri, sat, sun
} day;

day tomorrow(day d)
✤ Write a function tomorrow that {
return d == sun ? mon : d + 1;
takes a day and returns the next }
day

double daily_earning[5];
✤ Can also be used as array subscripts daily_earning[mon] = 1329.56;
Switch-case
int watts;
printf("Enter wattage for your bulb: ");
scanf("%d", &watts);
int life;
switch (watts)
{
case 25:
life = 2500;
✤ Alternative to if-else chains for break;
case 40:
multiple alternative decisions
case 60:
life = 1000;
✤ The expression after case must be a break;
case 75:
constant → strings not supported
case 100:
life = 750;
✤ Careful with break break;
default:
life = 0;
✤ Use of default }
printf("The bulb should last %d hours\n", life);
char grade

Doesn’t work for ranges marks>90

char grade(int marks) {


char grade; grade='O' marks>80
if (marks > 90) {
grade = 'O';
marks>70
} else if (marks > 80) { grade='E'
grade = 'E';
} else if (marks > 70) {
grade = 'A'; grade='A'
} else {
grade='P'
grade = 'P';
}
return grade;
return grade
}
char grade

Doesn’t work for ranges marks>90

char grade(int marks) { Some compilers, like GCC, can


char grade; grade='O'
handle marks>80
this using the GNU Case
if (marks > 90) { Range Extension; not part of
grade = 'O'; standard C
marks>70
} else if (marks > 80) { grade='E'
grade = 'E';
} else if (marks > 70) {
grade = 'A'; grade='A'
} else {
grade='P'
grade = 'P';
}
return grade;
return grade
}
Break

✤ Causes the enclosing loop or


switch statement to terminate.

✤ Used when it is otherwise


awkward to terminate the loop
using the condition expression and
conditional statements.
Break
for (int j = 0; j < 2; j++)
for (int k = 0; k < 5; k++)
printf("%d%d ", j, k);
printf(“\n");
✤ Causes the enclosing loop or
for (int j = 0; j < 2; j++) {
switch statement to terminate. for (int k = 0; k < 5; k++) {
if (k == 2)
break;
✤ Used when it is otherwise printf("%d%d ", j, k);
awkward to terminate the loop }
}
using the condition expression and
conditional statements.
Break
for (int j = 0; j < 2; j++)
for (int k = 0; k < 5; k++)
printf("%d%d ", j, k);
printf(“\n");
✤ Causes the enclosing loop or
Only the for (int j = 0; j < 2; j++) {
switch statement toinner loop is affected
terminate. for (int k = 0; k < 5; k++) {
by the break statement if (k == 2)
break;
✤ Used when it is otherwise printf("%d%d ", j, k);
awkward to terminate the loop }
}
using the condition expression and
conditional statements.
Break
for (int j = 0; j < 2; j++)
for (int k = 0; k < 5; k++)
printf("%d%d ", j, k);
printf(“\n");
✤ Causes the enclosing loop or
Only the for (int j = 0; j < 2; j++) {
switch statement toinner loop is affected
terminate. for (int k = 0; k < 5; k++) {
by the break statement if (k == 2)
break;
✤ Used when it is otherwise printf("%d%d ", j, k);
awkward to terminate the loop }
}
using the condition expression and
conditional statements.
00 01 02 03 04 10 11 12 13 14
00 01 10 11
Continue

✤ Causes the remaining portion of


the enclosing loop body to be
skipped.

✤ Used when it is otherwise


awkward to ignore the remaining
portion of the loop using
conditional statements.
Continue

✤ Causes the remaining portion of for (int j = 0; j < 2; j++) {


for (int k = 0; k < 5; k++) {
the enclosing loop body to be if (k == 3)
continue;
skipped. printf("%d%d ", j, k);
}
}
✤ Used when it is otherwise
awkward to ignore the remaining
portion of the loop using
conditional statements.
Continue

✤ Causes the remaining portion


Only the inner of
loop is affected for (int j = 0; j < 2; j++) {
for (int k = 0; k < 5; k++) {
by the continue
the enclosing loop body to be statement if (k == 3)
continue;
skipped. printf("%d%d ", j, k);
}
}
✤ Used when it is otherwise
awkward to ignore the remaining
portion of the loop using
conditional statements.
Continue

✤ Causes the remaining portion of for (int j = 0; j < 2; j++) {


for (int k = 0; k < 5; k++) {
the enclosing loop body to be if (k == 3)
continue;
skipped. printf("%d%d ", j, k);
}
}
✤ Used when it is otherwise
This printf is skipped every
awkward to ignore the remaining time k is 3
portion of the loop using
conditional statements.
Continue

✤ Causes the remaining portion of for (int j = 0; j < 2; j++) {


for (int k = 0; k < 5; k++) {
the enclosing loop body to be if (k == 3)
continue;
skipped. printf("%d%d ", j, k);
}
}
✤ Used when it is otherwise
This printf is skipped every
awkward to ignore the remaining time k is 3
portion of the loop using
conditional statements.
00 01 02 04 10 11 12 14
Command line arguments

✤ Remember our le copy program


> ./copyfile
Enter the source file name: pooh.txt
Enter the destination file name: nothing.txt

Copied file pooh.txt to file nothing.txt (81 characters)

✤ Users may prefer sending the le names as command line arguments

✤ With CL support, it can become a complete software in itself


fi
fi
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
printf("%s: No such file or directory\n\n", argv[1]);
return -1;
}

if (!(dst_fp = fopen(argv[2], “w"))) {


printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char

fclose(src_fp); fclose(dst_fp);

return 0;
}
int main(int argc, char **argv) { main can take two parameters: a count of CL args,
if (argc != 3) { and an array of CL args as strings
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
printf("%s: No such file or directory\n\n", argv[1]);
return -1;
}

if (!(dst_fp = fopen(argv[2], “w"))) {


printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char

fclose(src_fp); fclose(dst_fp);

return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
printf("%s: No such file or directory\n\n", argv[1]);
Check if the
return -1; number of arguments match; if they
} don’t show an error message and exit

if (!(dst_fp = fopen(argv[2], “w"))) {


printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char

fclose(src_fp); fclose(dst_fp);

return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
Remember, fprintf
printf("%s: No such file or directory\n\n", argv[1]); is just like printf, but it takes an
return -1; additional argument, the stream to write to.
} stdout is the standard output;
if (!(dst_fp = fopen(argv[2], “w"))) { stderr is for error messages
printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char

fclose(src_fp); fclose(dst_fp);

return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
printf("%s: No such file or directory\n\n", argv[1]);
return -1;
}

if (!(dst_fp = fopen(argv[2], “w"))) {


printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char


You can use argv[i] like any
fclose(src_fp); fclose(dst_fp); other string variable
return 0;
}
int main(int argc, char **argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <src_file> <dest_file>\n", argv[0]);
return 1;
}
FILE *src_fp, *dst_fp;
if (!(src_fp = fopen(argv[1], “r"))) {
printf("%s: No such file or directory\n\n", argv[1]);
return -1;
}

if (!(dst_fp = fopen(argv[2], “w"))) {


printf("Cannot open %s for writing\n\n", argv[2]);
return -2;
}

// code to copy the file char by char


> gcc copyfile-cli.c -o copyfile
fclose(src_fp); fclose(dst_fp); > ./copyfile pooh.txt nothing.txt

return 0;
}
Your turn

> ./avg-cli
✤ Write a program that takes one or Usage: ./avg-cli <num> [<more nums>]

more real numbers as command line


> ./avg-cli 1
arguments and prints their mean Mean = 1.000000

✤ The function atof in stdlib > ./avg-cli 1 2


Mean = 1.500000
interprets a real number value in a
char string
> ./avg-cli 1 2 3
Mean = 2.000000
✤ Ex.: atof(“3.14”) → 3.14
Other basic types

✤ We concerned ourselves only with int and double for Z and R, respectively

✤ C has many other types – most of which are variants of these based on the range of
values to be represented or operations to be performed on them

✤ Signed and unsigned variants of

✤ char, short int, int, long, long long

✤ Real numbers: oat, double, and long double

✤ Complex numbers: oat complex, double complex, long double complex


fl
fl
Other basic types

✤ We concerned ourselves only with int and double for Z and R, respectively

✤ C has many other types – most of which are variants of these based on the range of
values to be represented or operations to be performed on them
The language defines a minimum
✤ Signed and unsigned variants of size for each type and

✤ char, short int, int, long, long long 1 == sizeof(char) ≤ sizeof(short)


≤ sizeof(int) ≤ sizeof(long)
≤ sizeof(long long)
✤ Real numbers: oat, double, and long double

✤ Complex numbers: oat complex, double complex, long double complex


fl
fl
Function Declaration
v. Definition
✤ Write a program that takes a non-negative
integer and reports if it is odd or even,
without using the % operator
Function Declaration #include <stdio.h>

v. Definition #include <stdbool.h>

✤ Write a program that takes a non-negative


bool is_even(unsigned int n)
integer and reports if it is odd or even, {
without using the % operator return n == 0 ? true : is_odd(n - 1);
}

bool is_odd(unsigned int n)


{
return n == 0 ? false : is_even(n - 1);
}

int main()
{ ... }
Function Declaration Cannot compile!
It does not understand is_odd at
#include <stdio.h>

v. Definition #include <stdbool.h> this point!

✤ Write a program that takes a non-negative


bool is_even(unsigned int n)
integer and reports if it is odd or even, {
without using the % operator return n == 0 ? true : is_odd(n - 1);
}

bool is_odd(unsigned int n)


{
return n == 0 ? false : is_even(n - 1);
}

int main()
{ ... }
Function Declaration #include <stdio.h>

v. Definition
Declare the function (without de ning it)
#include <stdbool.h>

bool is_even(unsigned int n);


before its use, so the program compiles bool is_odd(unsigned int n);
→ remember function headers
✤ Write a program that takes a non-negative
bool is_even(unsigned int n)
integer and reports if it is odd or even, {
without using the % operator return n == 0 ? true : is_odd(n - 1);
}

bool is_odd(unsigned int n)


{
return n == 0 ? false : is_even(n - 1);
}

int main()
{ ... }
fi
Function Declaration #include <stdio.h>

v. Definition #include <stdbool.h>

bool is_even(unsigned int n);


bool is_odd(unsigned int n);
✤ Write a program that takes a non-negative
bool is_even(unsigned int n)
integer and reports if it is odd or even, {
without using the % operator return n == 0 ? true : is_odd(n - 1);
}

bool is_odd(unsigned int n)


{
The libraries we #include are full of such return n == 0 ? false : is_even(n - 1);
function headers - that’s why they are }
called header les and named .h
int main()
{ ... }
fi
Function Declaration #include <stdio.h>

v. Definition #include <stdbool.h>

bool is_even(unsigned int n);


bool is_odd(unsigned int n);
✤ Write a program that takes a non-negative
bool is_even(unsigned int n)
integer and reports if it is odd or even, {
without using the % operator return n == 0 ? true : is_odd(n - 1);
}

bool is_odd(unsigned int n)


{
return n == 0 ? false : is_even(n - 1);
}

int main()
{ ... }
Multi file programs

✤ Large programs are spread across multiple les

✤ Typically, .h les and corresponding .c les

✤ Each .h le is included wherever you are using the functions declared in it

✤ Each .c le is compiled to an unlinked object le

✤ An unlinked le is a compiled program with gaps for de nitions of some function


calls

✤ You ll these gaps by linking all the object les together


fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
Multi file programs You could compile all .c les every
time, but in large projects, you often
modify a small part and compiling
everything all over again just for that
✤ Large programs are spread across multiple les change is unnecessary

✤ Typically, .h les and corresponding .c les

✤ Each .h le is included wherever you are using the functions declared in it

✤ Each .c le is compiled to an unlinked object le

✤ An unlinked le is a compiled program with gaps for de nitions of some function


calls

✤ You ll these gaps by linking all the object les together


fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
fi
#include <stdio.h>
#include <stdbool.h>
bool is_even(unsigned int n);
bool is_odd(unsigned int n);
📄 evenodd.h
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
📄 evenodd.c
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv)


{
if (argc != 2) { /* error check */ }

int n = atoi(argv[1]);
printf("%d is %s\n”,
n,
is_even(n) ? "even" : "odd");

return 0;
}
📄 evenodd-cli.c
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


{
if (argc != 2) { /* error check */ }

int n = atoi(argv[1]);
printf("%d is %s\n”,
n,
is_even(n) ? "even" : "odd");

return 0;
}
📄 evenodd-cli.c
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


Creates an unlinked le evenodd.o
{
if (argc != 2) { /* error check */ }

int n = atoi(argv[1]);
printf("%d is %s\n”,
n,
is_even(n) ? "even" : "odd");

return 0;
}
📄 evenodd-cli.c
fi
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


{
if (argc != 2) { /* error check */ }
> gcc evenodd-cli.c -c
intCreates an unlinked le evenodd-cli.o
n = atoi(argv[1]);
printf("%d is %s\n”,
n,
is_even(n) ? "even" : "odd");

return 0;
}
📄 evenodd-cli.c
fi
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


{
if (argc != 2) { /* error check */ }
> gcc evenodd-cli.c -c
int n = atoi(argv[1]);
printf("%d is %s\n”,
n, > gcc evenodd.o evenodd-cli.o
Links them together to produce the
is_even(n) ? "even" : "odd");
executable evenodd —o evenodd
return 0;
}
📄 evenodd-cli.c
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


{
if (argc != 2) { /* error check */ }
> gcc evenodd-cli.c -c
int n = atoi(argv[1]);
printf("%d is %s\n”,
n, > gcc evenodd.o evenodd-cli.o
is_even(n) ? "even" : "odd");
—o evenodd
return 0;
} > ./evenodd 4
📄 evenodd-cli.c 4 is even
#include <stdio.h> #include "evenodd.h"
#include <stdbool.h>
bool is_even(unsigned int n); bool is_even(unsigned int n) {
bool is_odd(unsigned int n); return n == 0 ? true : is_odd(n - 1);
}
📄 evenodd.h
bool is_odd(unsigned int n) {
return n == 0 ? false : is_even(n - 1);
}
#include "evenodd.h"
📄 evenodd.c
#include <stdlib.h>

int main(int argc, char **argv) > gcc evenodd.c -c


{
if (argc != 2) { /* error check */ }
> gcc evenodd-cli.c -c
int n = atoi(argv[1]);
printf("%d is %s\n”,
n, > gcc evenodd.o evenodd-cli.o
is_even(n) ? "even" : "odd");
—o evenodd
return 0;
} > ./evenodd 4 > ./evenodd 5
📄 evenodd-cli.c 4 is even 5 is odd

You might also like