0% found this document useful (0 votes)
12 views47 pages

02A-II Stack Arrays Strings

Uploaded by

partouchetikva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views47 pages

02A-II Stack Arrays Strings

Uploaded by

partouchetikva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 47

Introduction to C

Programming Workshop in C/C++ (67312)


Lecture 3
Expected Learning Outcomes
0 What is the stack memory segment?
Understand

0 How are local variables stored/removed from the stack?


0 What are static (fixed-length) arrays?
0 How are 1D and 2D static arrays stored in the stack?
0 How are C strings represented using null-terminated arrays

0 Declare, read, write & iterate over 1D & 2D static arrays


0 Determine array length using sizeof(arr)/sizeof(*arr)
Apply

0 Declare, read and write C strings


0 Compute the length of C strings
0 Process strings from the command-line interface (CLI)

2
Stack Memory Segment

3
The stack memory: last-in, first-out (LIFO)

❑Stack: local variables Address 0xffffff

Stack
Born when a scope begins,
die when it ends. Free space
❑ Heap: dynamic memory
Born with malloc(),
Heap
die with free() or with the program.

Data (Global/Static)
❑ Data: global variables (often read-only)
Born and die with the program.
Code (text)
❑ Code: functions (often read-only)
Born and die with the program. Address 0x000000

4
The stack memory segment

Maintains memory during function calls:


● Arguments of the function
● Local variables
● Call frame

●Variables on the stack have a limited


lifetime and their size is defined during

5
compilation
Local variables are typically stored in the
stack in descending memory addresses
int main ()
{
char c = 'd';
int i = 0, j = 0; // assume sizeof(int) = 4
double x = 0; // assume sizeof(double) = 8
}
descending memory addresses

c i j x
'd' 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0x9F 0x9E 0x9A 0x96

6
Stack and scopes - Example
>call<
int foo( int a, double f )
a
{ f
int b;
...
{
int c;
...
}
...
}

7
Stack and scopes - Example
>call<
int foo( int a, double f )
a
{ f
int b; b
...
{
int c;
...
}
...
}

8
Stack and scopes - Example
>call<
int foo( int a, double f )
a
{ f
int b; b
... c
{
int c;
...
}
...
}

9
Stack and scopes - Example
>call<
int foo( int a, double f )
a
{ f
int b; b
... c
{
int c;
...
}
...
}

10
Stack and scopes - Example
>call<
int foo( int a, double f )
a
{ f
int b; b
... c
{
int c;
...
}
...
}

11
Stack and scopes - Example Return
address
ret
int foo( int a, double f )
{
int b;
...
{
int c;
...
}
...
}

12
The dark side of the stack
void foo( int num )
{
int a;
if( num>1 )
{
foo(num);
}
}

Will it run forever?


13
The dark side of the stack
void foo( int num )
{
int a;
if( num>1 )
{
foo(num);
}
}

Will result in an out of stack space run-time error,


(the infamous stack overflow) https://stackoverflow.com/

14
Memory and Arrays

For now, we will only discuss static arrays


(dynamic arrays – next time)

15
The array data type

In C, the array data type denotes a static (fixed-length)


array. Declaring an array of n elements of type type:

<type> array_name[n] = {<v1>,<v2>, …,


<vn>};

<type> array_name[n] = {<value>};

<type> array_name[n]; // uninitialized

<type> array_name[] = {<v1>,<v2>, …, <vn>};


Local array variables – memory storage
A local array of length n is stored in the stack as a block of n
consecutive cells with (typically) ascending memory addresses

{
int i = 0;
int a[3] = {1, 2, 3}; // sizeof(a) = 3 *
sizeof(int)

}
a[0] a[1] a[2] i
1 0 0 0 2 0 0 0 3 0 0 0 0 0 0 0
0x9C 0xA0 0xA4 0xA8
ascending memory addresses
Array Initialization (1D)
➢ int arr[3] = {3, 4, 5}; // explicit length = 3

➢ int arr[] = {3, 4, 5}; // implicit length = 3


(equivalent)

➢ int arr[3] = {0}; // Init all three items to 0 (zero


only!)

➢ char arr[] = {'h', 'i'}; // length = 2

➢ char arr[] = "hi"; // length = 3 (huh? strings -


later…)

➢ int arr[2] = {3, 4, 5}; // Error: incompatible length


➢ int arr[3]; // uninitialized
18➢ arr = {2,5,7}; // Error: array assignment only at
Array Initialization (2D)
2D static arrays are stored consecutively in
the stack memory, row-by-row (“row-major”)
➢ int arr[2][3] = {{2,5,7},{4,6,7}}; // 2 rows, 3
columns

➢ int arr[2][3] = {2,5,7,4,6,7}; // Equivalent

➢ rowint
columnarr[3][2] = {{2,5,7},{4,6,7}}; // Err:
arr[0] arr[0] arr[0] arr[1] ...
incompatible
[0] [1] [2] [0]

0x08 0x0C 0x10 0x14 0x18

19
2D Array Memory Map
int a[2][3] = {{2,5,7},{4,6,7}};

Conceptually, we think of 2D arrays as


int a[ROWS][COLS];

a[0] 2 5 7
a[1] 4 6 7

20
2D Array Memory Map
int a[2][3] = {{2,5,7},{4,6,7}};

In the memory, it is actually like this:

a[0] a[1]

2 5 7 4 6 7

21
The subscript [] operator –
read/write access to array elements
int arr[] = {3, 4, 5};
arr[1] = 40; // write access  {3, 40, 5}
printf("%d\n", arr[2]); // read access  5
arr = {30, 40, 50}; // compile error – cannot
assign

int arr[2][3] = {{2,5,7},{4,6,7}};

arr[1][0] = 40; // {{2,5,7},{40,6,7}}

arr[0][1] = 50; // {{2,50,7},{40,6,7}}

arr = {{20,50,70},{40,60,70}}; // compile error


22
Array access – memory addressing (1D)
The i’th array element is stored i x sizeof(arr[i])
bytes from the first array element
int arr[5] = { 1, 5, 2, 1 ,3 };

1 5 2 1 3

32 36 40 44 48 52 decimal
hexadecimal
0x20 0x24 0x28 0x2C 0x30 0x34

Address Computation Examples:


1. arr[0] 32+0*sizeof(int) = 32 // arr[0] accesses memory address
32

2. arr[3] 32+3*sizeof(int) = 44 // arr[3] accesses memory address


44

3. arr[i] 32+i*sizeof(int) = 32 + 4 * i
4. arr[-1] 32+(-1)*sizeof(int) = 28 // Danger: access code segment,
// other variables, etc.
23
Arrays – out-of-bounds access

C does not provide any run-time boundary checks:


int a[4];
a[-1] = 0; // no problemo
a[4] = 0; // no problemo

This will compile and run…


But can lead to unpredictable results/crash.

It is the programmer’s responsibility to check whether the


index is out of bound.
24
Q: What is the output?
(assuming the stack memory is organized from top to bottom as in the chart below)

int a[6] = {1,2,3};


int i = 9;
printf("%d", a[-1]);
A. 3
B. 9
C. Compile error A B C D 0

D. Run-time error
i a[0] a[1] a[2]
. . .
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
Note – Variable Length Array
(VLA) not allowed in course
C99 allows the array size to be determined at run time:
int m = 10;
. double vla[m]; // VLA, not OK! (in course)

Do NOT do this in this course!


(why? various dangers, potential bugs)

We will test your exercises, labs, and exam with


–Werror=vla

26
Array iteration
and sizeof()

27
Assigning, printing & comparing arrays:
The easy way is the wrong way

int a[4] = {1, 2, 3, 4};


int b[4] = {10, 20, 30, 40};

a = b; // compile error – cannot assign array

printf ("%d", a); // compile buts… prints address

if (a==b) … // compiles but… compares addresses

 C does not provide operators for iterating over all array elements

28
Array comparison – the wrong way

When comparing arrays using ==, we compare addresses

int a[2] = {0};

int b[2] = {0};

if (a==b) … // we are comparing 0x0C with 0x14


b[0 b[1] b[2] a[0]
]
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
hexadecimal
0x0C 0x10 0x14 0x18
12 16 20 24 decimal

29
Array comparison – the right way 
We always know the number of static array elements at
compile-time  we can compare them one-by-one

int a[] = {1, 2}; // 2 elements

int b[] = {1, 2}; // 2 elements

bool is_equal = true;

for (int i = 0; i < 2; i++)

if(a[i] != b[i])

30
Array iteration – a common nasty bug

What if we changed the arrays length but forgot to update the


loop?

int a[] = {1, 2, 3}; // 3 elements

int b[] = {1, 2, 30}; // 3 elements

bool is_equal = true;

for (int i = 0; i < 2; i++)

if(a[i] != b[i])

31
Number of array elements:
sizeof(<array>)/sizeof(<element>)

int a[] = {1, 2, 3};

// Three alternatives:

size_t n = sizeof(a) / sizeof(int); // n == 3

size_t n = sizeof(a) / sizeof(a[0]); // n == 3


Explanation:
sizeof(a) == size of the array in bytes
size_t n = sizeof(a) / sizeof(*a); // why *a? later…
sizeof(int) or sizeof(a[0]) or sizeof(*a) == size of a single element in bytes
 sizeof(a) / sizeof(<element>) == number of elements (evaluated at compile time!)
size_t is an integral data type that can hold even the largest memory address
32
Array iteration – less bug-prone comparison using sizeof()

int a[] = {1, 2, 3};

int b[] = {1, 2, 30};

bool is_equal = true;

assert (sizeof(a) == sizeof(b) &&

sizeof(*a) == sizeof(*b)); // extra safety when debugging the code

for (size_t i = 0; i < sizeof(a) / sizeof(*a); i++)


Printing an array:
{ Code runner L2B.Q3
33
Array iteration – less bug-prone comparison using sizeof()

A slightly more readable alternative:

int a[] = {1, 2, 3};

int b[] = {1, 2, 30};

bool is_equal = true;

size_t na = sizeof(a) / sizeof(*a);

size_t nb = sizeof(b) / sizeof(*b);

assert (na == nb); // extra safety when debugging the code

Printing an array:
for (size_t i = 0; i < na; i++)Code runner L2B.Q3

34
Note: when we pass arrays to functions, we cannot use sizeof()!

We must pass the array size explicitly to functions.


Why? Later in the course…

void print_array (int a[], size_t n)

for (size_t i = 0; i < n; i++)

{ … }

35
char[] strings

36
A char[] string is a null-terminated
array of characters
int main()
{ '\0' is a special
char str1[] = "hello"; character indicating
the end of a string
char str2[6] = "hello"; (ASCII==0).
} 5 +1

str2 str1
h e l l o 0\ h e l l o 0\ . . .
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
Equivalently…

int main()
{
char str1[] = {'h','e','l','l','o','\
0’};
char str2[6] = {'h','e','l','l','o','\
0’};
str2 str1
}
h e l l o 0\ h e l l o 0\ . . .
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
Printing a char[] string
int main()
{
char str[] = "hello";
printf("%s", str); // print till '\0'
}

str
h e l l o 0\
hexadecimal
0x0C 0x10
12 16 decimal
char [] string – don’t lose your '\0'..

int main()
{
char ch = 'a';
char str[] = {'c', 'o', 'd', 'e'};

printf("%s", str);
return 0;
}
c o d e a ?
40
str ch
Q: What is the output?

char str[] = "hi!";


printf ("%zu",
sizeof(str));
Note: %zu prints unsigned integers large enough to
hold sizeof() results

A. 3
B. 4
C. 5
D. compiler-dependent
A B C D -
vote at hujicppbr.participoll.com
41
String length - C library strlen()
Signature:size_t strlen(const char str[]);
size_t is an unsigned int that indicates size

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

int main ()
{
char str[] = "hello";
printf ("%zu\n", strlen (str)); // %zu – prints a
size_t
}
str
h e l l o 0\
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
String length – our own implementation
size_t my_strlen (const char s[])
{
size_t i = 0;
Printing a string:
while(s[i++]!='\0');
Code runner L1A.Q4
return i-1;
}

int main ()
{
char str[] = "hello";
printf("%zu\n", my_strlen (str));
return 0;
}

str
h e l l o 0\
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
String length – our own implementation
size_t my_strlen (const char s[])
{
size_t i = 0;
Printing a string:
while(s[i++]!='\0');
Code runner L2B.Q4
return i-1;
}

int main ()
{
char str[] = "hello";
printf("%zu\n", my_strlen (str));
return 0;
}

str
h e l l o 0\
0x0C 0x10 0x14 0x18 hexadecimal
12 16 20 24 decimal
Strings as command line
arguments

45
Handling command-line arguments
Command line arguments are passed to main as an array of string –
we will learn about the details later in the course

void print_string(const char s[])


{ argc – number of
}
printf ("%s\n", s);
command line
We will learn about
int main(int argc, char *argv[])
the star (”char *”)
later – don’t worry
argumnets + 1
{
for(int i = 0; i < argc; i++)
about it for now
argv – an array of
{
print_string(argv[i]);
command line
}
}
arguments
argv[i] - the i’th
command line
argument (a string)
Handling command-line arguments
Command line arguments are passed to main as an array of string –
we will learn about the details later in the course

void print_string(const char s[])


{ argc – number of
}
printf ("%s\n", s);
command line
We will learn about
int main(int argc, char *argv[])
the star (”char *”)
later – don’t worry
argumnets + 1
{
for(int i = 0; i < argc; i++)
about it for now
argv – an array of
{
print_string(argv[i]);
command line
}
}
arguments
argv[i] - the i’th
command line
argument (a string)

You might also like