Download as pdf or txt
Download as pdf or txt
You are on page 1of 126

C/CPS 393

Introduction to UNIX, C and C++


Prof. Alex Ufkes

Topic 9: Data structures in C


Notice!

Obligatory copyright notice in the age of digital


delivery and online classrooms:

The copyright to this original work is held by Alex Ufkes. Students


registered in course C/CPS 393 can use this material for the purposes
of this course but no other use is permitted, and there can be no sale
or transfer or use of the work for any other purpose without explicit
permission of Alex Ufkes.

© Alex Ufkes, 2022 2


Course Administration

Three weeks to go!


Final exam covers C, takes
place during exam period.

© Alex Ufkes, 2022 3


Today

Structured Data in C
2D arrays (static VS dynamic)
Arrays of strings
Structs, Linked Lists

© Alex Ufkes, 2022 4


© Alex Ufkes, 2022 5
2D Arrays
Recall: 1D Static Arrays

#include <stdio.h>
int main()
{
int nums[100]; An array of 100 integers
return 0;
}
2D Static Arrays

We simply add another set of square brackets [ ]

#include <stdio.h>
int main()
{
int nums[10][10]; A 2D array, 10 by 10
return 0;
}
ND Static Arrays

As many dimensions as you want:

#include <stdio.h>
int main()
{
int nums[5][5][5][5][5];
return 0;
}
#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
return 0;
} Row 1 Row 2 Row 3
3 rows 2 columns

1 2 3 4 5 6 Memory

Row 1 Row 2 Row 3


2D Memory

Memory is NOT 2D!

Addressing is one dimensional!


Static 2D arrays are still allocated as contiguous 1D chunks.

1 2 3 4 5 6 Memory

Row 1 Row 2 Row 3


#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
return 0;
}
The name of a static, 2D array is STILL
just a pointer to the first element!

1 2 3 4 5 6 Memory

nums == &nums[0][0]
#include <stdio.h>
int main()
{
int matrix[2][2]; 2 rows, 2 columns
Row index Column index
matrix[0][0] = 17; /* row 0, col 0 */
matrix[0][1] = -3; /* row 0, col 1 */
matrix[1][0] = 0; /* row 1, col 0 */
matrix[1][1] = 57; /* row 1, col 1 */

return 0;
}
#include <stdio.h>
int main()
{
int matrix[2][2];

scanf( , &matrix[0][0]);
scanf( , &matrix[0][1]);
scanf( , &matrix[1][0]);
Just like 1D arrays!
scanf( , &matrix[1][1]);

return 0;
}
#include <stdio.h>
int main()
{
int matrix[][] = {{1,2,3},{4,5,6},{7,8,9}};
int row, col;
for (row = 0; row < 3; row++) {
for (col = 0; col < 3; col++) {
printf( , matrix[row][col]);
}
printf( \ );
}
return 0;
}
2D Static Arrays as Arguments

Create a function for matrix addition. It will take in


three arguments. The two matrices to be added, and a
third matrix to store the result.
#define M 3 /* number of matrix rows */
#define N 3 /* number of matrix columns */
void addMatrix(int a[M][N], int b[M][N], int c[M][N])
{
int row, col;
for (row = 0; row < M; row++) {
for (col = 0; col < N; col++) {
c[row][col] = a[row][col] + b[row][col];
}
}
}
#define M 3 /* number of matrix rows */
#define N 3 /* number of matrix columns */
void addMatrix(int a[M][N], int b[M][N], int c[M][N])
{ /* addMatrix code from previous slide here */ }
int main()
{
int mat1[M][N] = {{1,2,2},{2,-3,6},{1,0,-3}};
int mat2[M][N] = {{1,1,1},{1,6,2},{1,-1,-1}};
int result[M][N];
addMatrix(mat1, mat2, result);
return 0;
}
#define M 3 /* number of matrix rows */
#define N 3 /* number of matrix columns */
void addMatrix(int a[M][N], int b[M][N], int c[M][N])
{
/* addMatrix code here */
}

Notice: We are specifying the array size!

At minimum, we must specify the size of


each row (number of columns)
#define M 3 /* number of matrix rows */
#define N 3 /* number of matrix columns */
void addMatrix(int a[][N], int b[][N], int c[][N])
{
/* addMatrix code here */
}

Notice: We are specifying the array size!

At minimum, we must specify the size of


each row (number of columns). Why?
#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
printf( , nums[1][1]);
return 0;
}
If nums is just a pointer to the first element,
how do we know where the 2nd row begins?

1 2 3 4 5 6 Memory
#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
printf( , nums[1][1]);
return 0;
}

The compiler knows that the 2nd row starts at index 2


because it knows how many columns there are.

1 2 3 4 5 6 Memory
#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
printf( , nums[1][1]);
return 0;
}

one row ends and another begins. 2D indexing would not be possible.

1 2 3 4 5 6 Memory
void addMatrix(int a[][N], int b[][N], int c[][N])
{
int row, col;
for (row = 0; row < M; row++)
for (col = 0; col < N; col++)
c[row][col] = a[row][col] + b[row][col];
}

Therefore, this is sufficient, but omitting the


number of rows and columns entirely is not.
2D Array Allocation: CS

Recall: A dynamic 1D array is a pointer to a chunk of


reserved memory (calloc)

arr

int *arr = (int*) calloc(4, sizeof(int));


2D Array Allocation: CS

Treat a 2D array as an array of 1D arrays


2D Array Allocation: CS

Treat a 2D array as an array of 1D arrays

How can we
use calloc to
achieve this?
int i, nrows = 3, ncols = 4;
int **nums; /* Double pointer! A pointer to an array of pointers */
/* Allocate the array of pointers */
nums = (int**) calloc(nrows, sizeof(int*));

/* Allocate the arrays of integers, one for each row */


for (i = 0; i < nrows; i++)
nums[i] = (int*) calloc(ncols, sizeof(int));
/* At this point, nums can be treated like ANY OTHER statically declared
2D array. Rules for accessing and modifying elements are THE SAME. */

/* Free each row, then free the array of pointers */


for (i = 0; i < nrows; i++)
free(nums[i]);
free(nums);
int i, nrows = 3, ncols = 4;
int **nums;
nums = (int**) calloc(nrows, sizeof(int*));
for (i = 0; i < nrows; i++)
nums[i] = (int*) calloc(ncols, sizeof(int));
for (i = 0; i < nrows; i++)
free(nums[i]);
free(nums);
Accessing elements is the same!

nums[2][2]
2D Array Allocation: ENG

Simulate a 2D array using a 1D array:

Stack each row one after another


#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
return 0;
}

1 2 3 4 5 6 Memory

This is what happens in memory when declaring a static 2D array.


However, there is one key
#include <stdio.h>
int main()
{
int nums[3][2] = {{1, 2}, {3, 4}, {5, 6}};
return 0;
}

1 2 3 4 5 6 Memory

We can no longer access elements using two


indices (nums[0][0]
int nrows = 3, ncols = 4;
int *nums; /* Regular pointer! We are going to create a 1D array */

/* Allocate the 1D array of integers */


nums = (int*) calloc(nrows*ncols, sizeof(int));
TOTAL number of array elements
/* Do stuff with the array. Unlike the computer science method, accessing

/* Free the array */


free(nums);
2D Array Allocation: ENG

Accessing array elements when using the engineering method:


int *nums, nrows = 3, ncols = 4;
nums = (int*) calloc(nrows*ncols, sizeof(int));

We use a general formula to access row X, column Y:

nums[X*(num_cols) + Y];
Linear index of 2D array
2 columns
3 rows
first row second row third row

To access element [0][0]?


nums[X*(num_cols) + Y];
nums[0*(2) + 0];
nums[0];
2 columns
3 rows
first row second row third row

To access element [1][0]?


nums[X*(num_cols) + Y];
nums[1*(2) + 0];
nums[2];
2 columns
3 rows
first row second row third row

To access element [2][1]?


nums[X*(num_cols) + Y];
nums[2*(2) + 1];
nums[5];
Zuck VS Iron Man

Computer science method:


Harder to set up, easier to use once set up.
Cost: follow two pointers, 1+nrow calloc calls

Engineering method:
Easier to set up, harder to use once set up.
Cost: Calculate linear index. One multiplication,
one addition. Single calloc call.
Zuck AND Iron Man

Best of both worlds: Cache locality AND 2D indexing!

int R = 3, C = 3;
ENG int *arr = (int*) calloc(R*C, sizeof(int));
CS int **mat = (int**) calloc(R, sizeof(int*));
mat[0] = arr;
for (int i = 1; i < R; i++)
mat[i] = mat[i-1] + C;
Two 1D arrays:
First to hold all elements in the ENG style.
Second to enable 2D indexing in the CS style

Each int* in mat points to the start of a row in arr

Fill and print mat elements using 2D indexing!

Print addresses stored in mat.


Adjacent addresses are separated
by 12: C*sizeof(int)

integer
→ 4 bytes
Printing this pointer as %d gives a compile warning.
© Alex Ufkes, 2022 int is 4 bytes, int* is 8 bytes. We print the lower 4 bytes. 47
int R = 3, C = 3;
int *arr = (int*) calloc(R*C, sizeof(int));
int **mat = (int**) calloc(R, sizeof(int*));
mat[0] = arr; Address
of the
first element
first in the position .

for (int i = 1; i < R; i++)


mat[i] = mat[i-1] + C;

Memory

arr mat[0] mat[1] mat[2]


© Alex Ufkes, 2022 48
mat[0][0] mat[1][0]
mat[2][0]
mat[0][1] mat[1][1]
mat[2][1]
mat[0][2] mat[1][2]
mat[2][2]

Memory

arr mat[0] mat[1] mat[2]


© Alex Ufkes, 2022 49
Arrays of

© Alex Ufkes, 2020, 2021 50


Array of Strings

#include <stdio.h>
int main()
{
char months[12][10];
return 0;
}
Maximum length
Number of strings
of each string
Array of Strings

Initialize using literals:

char months[12][10] =
{ , , ,
, , ,
, , ,
, , };
Value of months[7][3]?
Value of months[4][3]?
Value of months[2][8]?
The memory is ours, but we

Value of months[9]?
Address of the first character
of October - &months[9][0]

printf( , months[9]);
Console
January
February
March char months[12][10] =
{ , , ,
April , , ,
May , , ,
June , , };

July
August
September for (i = 0; i < 12; i++)
October printf( \ , months[i]);
November
December
Structs

A collection of variables, types can vary

struct ball
{
char style[10];
double radius;
double weight;
};
#include <stdio.h>
#include <math.h>
struct ball
{ Structure definitions:
char style[10]; Typically placed between
double radius; preprocessor directives
double weight; and function prototypes.
};

int abc(int x);


double xyz();

int main()
{
return 0;
}
struct ball
{
char style[10];
double radius;
double weight;
};
int main()
{
struct ball b1, b2, b3, b[50]; Or as an array

Declare individually
}
struct ball
{
char style[10];
double radius;
double weight;
};
Use the dot operator to access a
int main() individual variables.
{
struct ball b1;
b1.radius = 4.6;
b1.weight = 22.1;
strcpy(b1.style, );
} ↓
destination element
the first
of
address
struct ball
{
char style[10];
double radius;
double weight;
};
int main()
{
struct ball b[50];
int i;
for (i = 0; i < 50; i++) {
Initialize radius
b[i].radius = 0.0;
b[i].weight = 0.0; and weight to 0.0
}
}
struct1 = struct2;
Assigns one struct to another
Assuming the same structure type

All member variable values are copied!


struct BirthdayInfo int main()
{ {
int year;
struct BirthdayInfo x, y;
int month;
int day; x.year = 1975;
}; x.month = 8;
x.day = 15;
y.year = 2008;
y.month = 12;
y.day = 2;
y.year = x.year;
y.month = x.month; y = x;
y.day = x.day; printf( \ , y.year,
equivalent y.month, y.day);
}
struct BirthdayInfo int main()
{ {
int year;
struct BirthdayInfo x, y;
int month;
int day; x.year = 1975;
}; x.month = 8;
x.day = 15;
y.year = 2008;
stdout: y.month = 12;
y.day = 2;
1975/8/15
y = x;
printf( \ , y.year,
y.month, y.day);
}
typedef
Create an Alias

#include <stdio.h>
typedef int integer;
alias for type int
int main()
{
integer x, y, z;
x = 1; integer can now be used as a type!
y = 2; same as int, except for the
z = x + y; name.
}
Common for Structures

typedef struct ball Now, instead of declaring:


{ struct ball b1, b2, b3;
char style[10];
double radius; We can simply declare:
double weight;
} ball; ball b1, b2, b3;
Common for Structures

Alias can be different from struct name:

typedef struct ball Declaration:


{ basketball b1, b2, b3;
char style[10];
double radius; Can still declare:
double weight; struct ball a, b, c;
} basketball;
typedef struct ball
{
char style[10];
double radius;
double weight;
} basketball;

int main()
{
basketball b1 = { , 3.4, 6.8};
return 0;
}
typedef struct ball
{
char style[10];
double radius;
double weight;
} basketball;

Can read values directly into a


int main() member variables.
{
basketball b1, b2;
printf( );
scanf( lf , &b1.radius);
return 0;
}
Structures & Functions

Structures passed as input to a function are COPIED into


the corresponding function parameter. All member
variables are copied as well.

This is DIFFERENT from arrays, which are NOT copied. Only the
base address of the array is copied, not the elements.
typedef struct ball
{ struct ball is defined and
char style[10];
given an alias before the
double radius;
double weight;
function printElements
} basketball;

void printElements(basketball b)
{
printf( \ , b.style);
printf( lf\ , b.radius);
printf( lf\ , b.weight);
}
typedef struct ball void printElements(basketball b)
{ {
char style[10]; printf( \ , b.style);
double radius; printf( lf\ , b.radius);
double weight; printf( lf\ , b.weight);
} basketball; }
b1 and its member
int main() values are copied into b
{
basketball b1 = { , 11.4, 212.8};
printElements(b1);
return 0;
}
Write a user-defined function that does the following:
Takes in two basketball structs as arguments and
compares the radius and the weight. Returns 1 if they
are the same, and 0 if they are different.
Two basketball structs as input arguments

int comp(basketball b1, basketball b2)


{
int isEqual;

isEqual = (b1.radius == b2.radius) &&


(b1.weight == b2.weight);

return isEqual; What is the output of a


} logical expression?
int comp(basketball b1, basketball b2)
{
return (b1.radius == b2.radius) && (b1.weight == b2.weight);
}

int main()
{
basketball b1 = { , 11.4, 212.8};
basketball b2 = { , 11.4, 212.8};
if (comp(b1, b2))
printf( \ );
else
printf( \ );
return 0;
}
Write a user-defined function that does the following:
Takes in zero arguments, and returns a basketball struct.
The function will ask the user to enter values for each of
basketball
basketball readElements(void)
{
basketball b;
printf( );
scanf( , b.style);
printf( );
scanf( lf , &b.radius);
printf( );
scanf( lf , &b.weight);
return b;
}
basketball readElements(void) void printElements(basketball b)
{ {
basketball b; printf( \ , b.style);
printf( ); printf( lf\ , b.radius);
scanf( , b.style); printf( lf\ , b.weight);
printf( ); }
scanf( lf , &b.radius);
printf( );
scanf( lf , &b.weight); It is possible to return an
return b;
}
entire struct. Unlike arrays,
ALL values are copied.
int main()
{
basketball b1 = readElements();
printElements(b1);
return 0;
}
yapacagim
.

ilene

hell Zeynep
why
the dur
dagan
.

Neyapmam
Mike
feeling
m'
man
i am yasmam mi
gonna

outsider with AM Yamamura ,


sonra neaten
yanmadm
an
around me

i rtaiti yor
'

oilman beni
.

people tephra no
-

these
void swap(struct foo input)
{
int tmp = input.a;
struct foo { input.a = input.b;
input.b = tmp;
int a, b;
}
};

int main()
{
struct foo f1 = {1, 2};
printf( , f1.a, f1.b);
swap(f1);
printf( , f1.a, f1.b);
return 0;
}
void swap(struct foo input)
{
int tmp = input.a; What is the output?
input.a = input.b; Before swap: 1 2
input.b = tmp;
} After swap: 1 2
F1 is copied
int main() into input.
{
struct foo f1 = {1, 2};
printf( , f1.a, f1.b);
swap(f1);
printf( , f1.a, f1.b);
return 0;
}
typedef struct foo {
int a, b;
} foo;

void swap(foo input) void swap(foo *input)


{ {
int tmp = input.a; int tmp = input->a;
input.a = input.b; input->a = input->b;
input.b = tmp; input->b = tmp;
} }

If input is a pointer to a struct, we use the


arrow operator (->) instead of the dot operator.
void swap(foo *input)
{
int tmp = input->a; What is the output?
input->a = input->b;
input->b = tmp; Before swap: 1 2
} After swap: 2 1
int main()
{
foo f1 = {1, 2};
printf( \ , f1.a, f1.b);
swap(&f1);
printf( , f1.a, f1.b);
return 0;
}
We can also dereference!
void printElements(basketball *b)
{
printf( \ , b->style);
printf( lf\ , b->radius);
printf( lf\ , b->weight);
}
Is the same as:
void printElements(basketball *b)
{
printf( \ , (*b).style); Must use parentheses
printf( lf\ , (*b).radius); (*b) otherwise the dot
printf( lf\ , (*b).weight); operator is applied first
}
An ordered set of data elements, each
containing a link to its successor.
(and in some cases, its predecessor)
These data elements can be structs in C

NULL pointer, there


is no 4th element

Address of 3rd data element


typedef struct monkey
{
char name[10];
double weight;
struct monkey *next;
} monkey;

Pointer to struct monkey as a member


variable of struct monkey
/* The start variable pointer to
a monkey node */
monkey *start;

/* The nodes 3 monkey structs */


monkey m1, m2, m3;

m1 m2 m3
monkey *start;
monkey m1, m2, m3;
strcpy(m1.name, );
strcpy(m2.name, );
strcpy(m3.name, );

m1 m2 m3
monkey *start;
monkey m1, m2, m3;
m1.weight = 300;
m2.weight = 150;
m3.weight = 120;

Is the linked list complete?

m1 m2 m3
300 150 120
monkey *start;
monkey m1, m2, m3;
strcpy(m1.name, );
strcpy(m2.name, );
strcpy(m3.name, );
m1.weight = 300;
m2.weight = 150; start = &m1;
m3.weight = 120;
m1.next = &m2;
m2.next = &m3;
m3.next = NULL;

m1 m2 m3
300 150 120
Linked List Traversal
Starting at the first node, visit every subsequent
node until the final node is reached.
Linked List Traversal
monkey *p;
int count = 0; /* count monkeys */
element
Madness equal to first

for (p = start; p != NULL; p = p->next)


{
instance of
pointer
not
is a ,
a

the struct .

count = count + 1;
printf( \ , count, p->name);
}

m1 m2 m3
300 150 120
monkey *p;
int count = 0; /* count monkeys */
for (p = start; p != NULL; p = p->next)
{
count = count + 1;
printf( \ , count, p->name);
}
Console
Monkey 1 is Donkey.

m1 m2 m3
300 150 120
monkey *p;
int count = 0; /* count monkeys */
for (p = start; p != NULL; p = p->next)
{
count = count + 1;
printf( \ , count, p->name);
}
Console
Monkey 1 is Donkey.

m1 m2 m3
300 150 120
monkey *p;
int count = 0; /* count monkeys */
for (p = start; p != NULL; p = p->next)
{
count = count + 1;
printf( \ , count, p->name);
}
Console
Monkey 1 is Donkey.
Monkey 2 is Diddy.

m1 m2 m3
300 150 120
monkey *p;
int count = 0; /* count monkeys */
for (p = start; p != NULL; p = p->next)
{
count = count + 1;
printf( \ , count, p->name);
}
Console
Monkey 1 is Donkey.
Monkey 2 is Diddy.
Monkey 3 is Dixie.

m1 m2 m3
300 150 120
monkey *p;
int count = 0; /* count monkeys */
for (p = start; p != NULL; p = p->next)
{
count = count + 1;
printf( \ , count, p->name);
}
Console
Monkey 1 is Donkey.
p
Monkey 2 is Diddy.
done traversing! Monkey 3 is Dixie.

m1 m2 m3
300 150 120
Linked Lists & Functions
Pass a linked list into a function as an argument.
Implement traversal as a function and return the
number of nodes that were traversed.
Traverse function:

int traverse (monkey *first)


{
monkey *p;
int count = 0; /* count monkeys */ indigo
for (p = first; p != NULL; p = p->next)
{ me
count = count + 1;
printf( \ , count, p->name);
}
return count;
}
Main function:

int main ()
{
strcpy(m1.name, );
monkey *start; strcpy(m2.name, );
monkey m1, m2, m3; strcpy(m3.name, );
m1.weight = 300;
int num; m2.weight = 150;
m3.weight = 120;
num = traverse(start); start = &m1;
m1.next = &m2;
printf( , num); m2.next = &m3;
m3.next = NULL;
return 0;
}
More Examples
typedef struct element {
int num;
struct element *next;
} element;
int main ()
{
element e1, e2, e3, e4, *current;
e1.num = 1; e2.num = 2; e3.num = 3; e4.num = 4;
e1.next = NULL; e2.next = &e3; e3.next = &e4; e4.next = &e1;
current = &e2;
while (current != NULL) {
printf( , current->num);
current = current->next;
}
return 0;
}
element e1, e2, e3, e4, *current;
e1.num = 1; e2.num = 2; e3.num = 3; e4.num = 4;
e1.next = NULL; e2.next = &e3; e3.next = &e4; e4.next = &e1;
current = &e2;
element e1, e2, e3, e4, *current;
e1.num = 1; e2.num = 2; e3.num = 3; e4.num = 4;
e1.next = NULL; e2.next = &e3; e3.next = &e4; e4.next = &e1;
current = &e2;
element e1, e2, e3, e4, *current;
e1.num = 1; e2.num = 2; e3.num = 3; e4.num = 4;
e1.next = NULL; e2.next = &e3; e3.next = &e4; e4.next = &e1;
current = &e2;
current = &e2;
while (current != NULL) {
printf( , current->num);
current = current->next;
}

Console
2 3 4 1
Dynamic
Linked list allocation
Recall dynamic array allocation for primitives (int, double, char, etc.)

int size;
char *array; /* 1. Pointer to character array */
printf( );
scanf( , &size);
/* 2. Allocate array dynamically using calloc */
array = (char*) calloc(size, sizeof(char));
/* 3. Use array normally */

free(array); /* 4. Free array */


Write code to do the following:
Dynamically allocate a linked list of monkey nodes. Prompt the user
for name and weight.
The code will create (dynamically!) at least one node. Prompt the user
after each node to see if they would like to add another. If yes, allocate
the new node and prompt for name and weight. If no, the program
ends.
monkey *first, *current;
int addAnother;

/* Create first node */


first = (monkey*) calloc(1, sizeof(monkey));
current = first;

Notice!
Our node has no identifier.
We access it using a pointer.
monkey *first, *current;
int addAnother;
first = (monkey*) calloc(1, sizeof(monkey));
current = first;

printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);

We now have one dynamically allocated node


with values for name and weight.

280
So far so good?
monkey *first, *current;
int addAnother;
first = (monkey*) calloc(1, sizeof(monkey));
current = first;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);

printf( );
scanf( , &addAnother);

If the user keeps entering 1, we


keep adding monkeys.

280 This calls for a loop!


printf( );
scanf( , &addAnother);

while (addAnother)
{
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;

We created a new node, and


updated our current pointer.

first always points to the first node.

280
while (addAnother) {
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
Fill node as usual
printf( );
scanf( lf , &current->weight);

280 450
while (addAnother) {
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);

printf( );
scanf( , &addAnother);
}

280 450
while (addAnother)
{
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);
printf( );
scanf( , &addAnother);
}

280 450
while (addAnother)
{
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);
printf( );
scanf( , &addAnother);
}

280 450
while (addAnother)
{
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);
printf( );
scanf( , &addAnother);
}

280 450 Koba 310


while (addAnother) {
/* Loop code in here */
}

current->next = NULL;

280 450 Koba 310


monkey *first, *current;
int addAnother;
first = (monkey*) calloc(1, sizeof(monkey));
current = first;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight);
printf( );
scanf( , &addAnother);
while (addAnother)
{
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( );
scanf( , current->name);
printf( );
scanf( lf , &current->weight); The complete code
printf(
scanf( , &addAnother);
); ^
mostly
}
current->next = NULL;
monkey *first, *current;
int addAnother;
first = (monkey*) calloc(1, sizeof(monkey));
current = first;
int traverse (monkey *first)
printf( );
{
scanf( , current->name);
printf( ); monkey *p;
scanf( lf , &current->weight); int count = 0; /* count monkeys */
printf( ); for (p = first; p != NULL; p = p->next)
scanf( , &addAnother); {
while (addAnother) count = count + 1;
{ printf( \ , count, p->name);
}
current->next = (monkey*) calloc(1, sizeof(monkey));
current = current->next;
printf( ); return count;
scanf( , current->name); }
printf( );
scanf( lf , &current->weight);
printf( );
scanf( , &addAnother);
}
current->next = NULL;
printf( \ , traverse(first));
Summary

Structured Data in C
2D arrays (static VS dynamic)
Arrays of strings
Structs, Linked Lists

© Alex Ufkes, 2022 125


© Alex Ufkes, 2022 126

You might also like