[go: up one dir, main page]

0% found this document useful (0 votes)
22 views638 pages

Te Mario

1. An algorithm is a set of rules that describes how to solve a problem through a series of steps. It must be finite, definite, and effective. Algorithms can be expressed through natural language, pseudocode, flowcharts, or programming languages. 2. Common elements of algorithms include data input, calculations, selection of different action sequences, and iteration. Algorithms define input and output objects. 3. A program is a description of an algorithm using a programming language that determines the specific operations to be performed. The same problem can have multiple algorithms and programs can be written for each algorithm using different programming languages.

Uploaded by

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

Te Mario

1. An algorithm is a set of rules that describes how to solve a problem through a series of steps. It must be finite, definite, and effective. Algorithms can be expressed through natural language, pseudocode, flowcharts, or programming languages. 2. Common elements of algorithms include data input, calculations, selection of different action sequences, and iteration. Algorithms define input and output objects. 3. A program is a description of an algorithm using a programming language that determines the specific operations to be performed. The same problem can have multiple algorithms and programs can be written for each algorithm using different programming languages.

Uploaded by

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

Introduction to Programming - Lectures

1. Algorithm, program, programming

© ZPR-FER-UNIZG Introduction to Programming 1


Algorithm
▪ An algorithm is a set of rules that describes how to solve a
problem. It has the following properties:
▪ finite: must finish after the final number of steps
▪ definite (completely determined): each step must be precise and
straightforward
▪ effective: all operations are elemental to the extent that they can
be performed accurately and in finite time
▪ algorithm defines a set of input object (can be empty)
▪ algorithm produces a set of output objects
▪ The algorithm can be described in:
▪ natural language
▪ pseudo-code
▪ flowchart
▪ programming language
© ZPR-FER-UNIZG Introduction to Programming 2
Common elements of algorithms
▪ data input
▪ read input values from an external source (e.g., keyboard)
▪ calculation
▪ performing arithmetic and logic operations, comparisons, ...
▪ selection
▪ choosing between two or more action sequences, based on inputs,
calculated results, etc.
▪ iteration
▪ successive repetition of a set of operations, with predetermined
number of times, or until a logical condition is satisfied (or until it is
satisfied)
▪ delivering results
▪ informing users of the results, such as printing on screen or typing in
a file
© ZPR-FER-UNIZG Introduction to Programming 3
Example
Pickled cucumbers
▪ Initial objects: 5 kg of cucumbers, 1 l of vinegar (9%), 30 dag of
sugar, 10 dag of salt, dill, pepper
▪ wash the cucumbers and dill, put in clean jars
▪ add vinegar, sugar, salt and pepper to 2 l of water
▪ cook while stirring
▪ pour the hot solution into jars
▪ close jars with cellophane
▪ stack the jars in a wide pot filled with water up to the throat of the jars
▪ if thermometer is available
▪ heat the water to 80 degrees C
▪ otherwise
▪ heat until air bubbles rise from the bottom
▪ leave for 24 hours
▪ Finishing objects: pickles á la FER
© ZPR-FER-UNIZG Introduction to Programming 4
Programming language, programming,
programming
▪ Programming language - A dictionary and a set of grammatic
rules that describe how a computer does a job
▪ Programming - the process of describing an algorithm in some of
the programming languages
▪ Program - A description of an algorithm in a programming
language that uniquely determines which operations to perform

© ZPR-FER-UNIZG Introduction to Programming 5


Problem, algorithm, program
▪ as a rule, it is possible to define several different algorithms for
each problem, and to write different programs for each
algorithm, using the same or different programming language

Problem

Algorithm Algorithm Algorithm


1 2 ... n

Program Program Program


1 2
... m

© ZPR-FER-UNIZG Introduction to Programming 6


Computer and computer system
▪ a computer is a device that can perform arithmetic and logic
operations based on the instructions defined in the computer
program
▪ computer system includes hardware and software that make up a
functional unit capable of data input, data processing, data
storage and data output

© ZPR-FER-UNIZG Introduction to Programming 7


Hardware
▪ The physical components of a computer
▪ Processor (Central Processing Unit)
▪ manages the execution of machine instructions and performs
arithmetic and logic operations
▪ Memory
▪ primary memory: faster, more expensive, of less capacity (typically
RAM). Temporary storage of programs and data - programs and data
must be loaded from the secondary memory into the primary memory
(program load) before execution and processing.
▪ secondary memory: slower, cheaper, higher capacity (typically HDD,
SSD). Permanent storage of data and programs.
▪ Input / output units
▪ keyboard, screen, mouse, network card, etc.

© ZPR-FER-UNIZG Introduction to Programming 8


Von Neumann's architecture (194x)

© ZPR-FER-UNIZG Introduction to Programming 9


Analitical engine – Babbage (c. 1837)

© ZPR-FER-UNIZG Introduction to Programming 10


Software - executable code
▪ software is a set of data and computer instructions that defines a
series of operations that a computer must perform
▪ executable code: a set of data and instructions in machine
language (machine code) that the computer actually performs
▪ binary code
▪ instructions are specific to a particular processor type (executable
code is non-portable)

© ZPR-FER-UNIZG Introduction to Programming 11


Software - Symbolic Machine Language
▪ assembly language describe machine language instructions using
symbols understandable to humans
▪ translated by assembler into machine language instructions
▪ programming is slow, hard, the probability of error is high
▪ programs are non-transferable - a new program needs to be written
for each processor type
▪ compared to higher programming languages, results in more
efficient machine code an example of a symbolic machine code
...
movl% esp,% ebp
.cfi_def_cfa_register 5
andl $ -16,% esp
subl $ 32,% esp
call ___main
leal 24 (% esp),% eax
movl% eax, 4 (% esp)
...
© ZPR-FER-UNIZG Introduction to Programming 12
Software – High-level Programming Languages
▪ programs are most commonly written in high-level programming
languages
▪ C, C ++, C #, Java, Python, PHP, Javascript, Fortran, Pascal, ...
▪ instructions (commands) are expressed mainly in English words and
understandable additional symbols - programming is much easier
than programming in symbolic machine language
▪ the code is (mostly) portable (after recompilation)
▪ a program written in a high-level programming language (but also in
a symbolic machine language) is called a source program
▪ source code
▪ source code must be translated into machine code by a specialized
program
▪ in advance, as a whole (compiler, compiler) or
▪ at runtime, command-by-command (interpreter)

© ZPR-FER-UNIZG Introduction to Programming 13


Software - classification by purpose
▪ The software is classified by purpose into the following
categories:
▪ System software
▪ interfaces the hardware providing basic computer system functionality
(e.g. read data from a file)
▪ operating systems (handling startup of application programs, file
system, operating system shell, memory allocation, ...)
▪ drivers (control of specific device type)
▪ utilities for configuring, optimizing, and maintaining your
computer system
▪ Application software
▪ performing functions specific to a purpose
▪ editors, word processors, spreadsheets
▪ compilers, interpreters
▪ integrated development tools
▪ games ...
© ZPR-FER-UNIZG Introduction to Programming 14
Computer system

APPLICATION
SOFTWARE compilers
text interpreters
editors spreadsheet
computer
calculators
games
SYSTEM operation
SOFTWARE system
utility
programs driver
driver driver

memory HARDWARE
bus disk
graphic network
processor
card card

© ZPR-FER-UNIZG Introduction to Programming 15


Example: from algorithm to program
▪ Programming assignment
▪ input an integer from the keyboard, then calculate the absolute
value of the input, then print the input and its absolute value on the
screen

© ZPR-FER-UNIZG Introduction to Programming 16


Example: algorithm
▪ An algorithm expressed in natural language
▪ input an integer number. If the number is less than zero, the
absolute value is calculated by changing the sign of the input,
otherwise, the absolute value is equal to the input. Print the number
and the calculated absolute value on the screen

© ZPR-FER-UNIZG Introduction to Programming 17


Pseudo-code
▪ the algorithm described in natural language is generally too broad,
without a clearly recognizable structure, and inherently ambiguous
▪ pseudo-code uses conventions about common programming
structures of programming languages, but at the same time avoids
specific details of programming languages
▪ contributes to removing the ambiguity of natural language
▪ in relation to a particular programming language, it is more
understandable to people who do not know the details of that
programming language
▪ natural language or mathematical notation are permitted in
appropriate places in the pseudo code
▪ Although some pseudo-code elements may roughly resemble the
usual elements of a particular programming language, there is no
generally accepted pseudo-code syntax
© ZPR-FER-UNIZG Introduction to Programming 18
Example: pseudo-code
▪ Pseudo-code - with less details, more like natural language
input integer
calculate the absolute value of the input
print the input and calculated value

▪ Pseudo-code - with more detail, using additional, pre-arranged


symbols
input (n)
{ calculate absolute value }
if n < 0 then
result: = - n
otherwise
result: = n
print (n, result)

© ZPR-FER-UNIZG Introduction to Programming 19


Flowchart
▪ Flowchart - A graphical description of an algorithm or, in general,
functional diagram of a system
▪ unambiguously describes the algorithm
▪ relatively standardized
▪ cumbersome if changes are required
▪ The most commonly used symbols are:

Start, End Input

Process Output

Decision Continuation

© ZPR-FER-UNIZG Introduction to Programming 20


Example: flowchart
▪ The algorithm described by the
flowchart
Start

input n

Yes No
n<0

result = - n result = n

output n, result

End

© ZPR-FER-UNIZG Introduction to Programming 21


Example: program code
▪ An algorithm implemented in C programming language
▪ source code written in a text editor (eg Notepad, vi) is stored in a
file with the extension .c (by convention)
#include <stdio.h> file prog1.c
int main(void) {
int n, result;
scanf("%d", &n);
// calculate absolute value
if (n < 0) {
result = -1 * n;
} else {
result = n;
}
printf("Input: %d Result %d", n, result);
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 22


Example: program code
▪ As a rule, it is possible to write different programs for each
algorithm (even using the same programming language). In most
cases, there is no single correct solution or the best solution by all
criteria.

#include <stdio.h> file prog1.c


#include <stdlib.h>
int main(void) {
int n;
scanf("%d", &n);
// calculate and output
printf("Input: %d Result: %d", n, abs(n));
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 23


Example: program code
▪ The algorithm described in the Python programming language
▪ source code in a .py file (by convention)

n = int(input()); file prog1.py


# calculate absolute value
if (n < 0):
result = -1 * n
else:
result = n
print("Input:", n, "Result:", result)

© ZPR-FER-UNIZG Introduction to Programming 24


Example: program code
▪ The algorithm described in the Java programming language
▪ source code in the .java file
import java.util.Scanner; file Prog1.java
public class Prog1 {
public static void main(String argv[]) {
int n, result;
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
// calculate absolute value
if (n < 0)
result = -1 * n;
else
result = n;
System.out.println("Input: " + n + " Result: " + result);
scanner.close();
}
}

© ZPR-FER-UNIZG Introduction to Programming 25


Compile or interpret programs
▪ The processor can only execute machine (binary) code.
Instructions written in a higher programming language must
therefore:
▪ be translated in advance into machine code, into a standalone
executable program that requires an operating system to run on the
computer
or
▪ be interpreted one command at the time of executing the program,
which, in addition to the operating system, requires a special
program - interpreter
or
▪ be translated in advance into a special form of program code
(bytecode) that can be very effectively interpreted or translated into
machine code at the time of executing the program. In addition to
the operating system, a special program is required for
interpretation and/or translation
© ZPR-FER-UNIZG Introduction to Programming 26
C program translation
▪ The C program is translated into several stages:
▪ Preprocessor: modifies the source code, eliminates comments, etc.
E.g. the directive #include <stdio.h> replaces the directive with
content of stdio.h file.
▪ C compiler: translates the code obtained from the previous step
into a symbolic machine code (assembly code)
▪ Assembler (assembler): translates symbolic machine code into
object code
▪ object code is machine code that is not yet ready to execute because,
among other things, it is not linked to the machine code of pre-
programmed libraries
▪ Linker: links object code to machine code from software libraries
(e.g., machine code to print to screen) and to other possibly already
translated modules creating executable code

© ZPR-FER-UNIZG Introduction to Programming 27


Example: preprocessor source code
#include <stdio.h>

writing source code, e.g. int main(void) {


int n, result;
Notepad scanf("%d", &n);
file prog1.c
notepad prog1.c // calculate absolute value
if (n < 0) {
result = -1 * n;
} else {
result = n;
}
preprocessor call printf(“Input: %d Result: %d", n, result);
return 0;
}

cpp prog1.c prog1.i


preprocessed source code
or
# 1 "prog1.c"
gcc -E prog1.c > prog1.i # 1 "<built-in>"
...
# 62 "c:\\mingw\\include\\sys/types.h" 3
typedef long __off32_t;
typedef __off32_t _off_t;...
# 3 "prog1.c"
...
int main(void) {
int n, result;
file prog1.i scanf("%d", &n);

if (n < 0) {
result = -1 * n;
} else {
...

© ZPR-FER-UNIZG Introduction to Programming 28


Example: compiler preprocessed source code
# 1 "prog1.c"
# 1 "<built-in>"
...
file prog1.i # 62 "c:\\mingw\\include\\sys/types.h" 3
typedef long __off32_t;
typedef __off32_t _off_t;...
# 3 "prog1.c"
...
int main(void) {
compiler call int n, result;
scanf("%d", &n);

if (n < 0) {
gcc -S prog1.i result = -1 * n;
} else {
...

symbolic machine code


...
_main:
LFB10:
file prog1.s .cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call ___main
leal 24(%esp), %eax
...

© ZPR-FER-UNIZG Introduction to Programming 29


Example: assembler
symbolic machine code
...
file prog1.s _main:
LFB10:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
assembler call .cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
gcc -c prog1.s call ___main
leal 24(%esp), %eax
movl %eax, 4(%esp)
movl $LC0, (%esp)
...

object code: machine code and references to machine


code from software libraries and other modules
...
file prog1.o 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000 01110000 01110010 01101111 01100111 00110001
00101110 01100011 00000000 01101101 01100001 01101001
01101110 00000000 01011111 01011111 01101001 01110011
01101111 01100011 00111001 00111001 01011111 01110011
01100011 01100001 01101110 01100110 00000000 01110000
...

© ZPR-FER-UNIZG Introduction to Programming 30


Example: linker
object code
...
file prog1.o 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000
00000000
... 00000000 00000000 00000000 00000000 00000000
00000000 01110000
00000000 01110010
00000000 01101111
00000000 01100111
00000000 00110001
00000000 00000000
00101110 01100011 00000000 01101101 01100001 01101001
program file prog2.o 00000000 00000000 00000000 00000000 00000000 00000000
... 00000000 01011111 01011111 01101001 01110011
01101110
00000000 00000000
00000000 00000000
00000000 00000000
00000000 00000000
00000000 00000000
00000000 00000000
libraries 01101111 01100011
00000000
00000000
00111001
01110000 00111001
01110010
00000000
01011111
01101111
00000000
01110011
01100111
00000000 00110001
00000000 00000000
01100011 01100001
00101110 01101110
01100011 01100110
00000000 00000000
01101101 01110000
01100001 01101001
00000000 00000000 00000000 00000000 00000000 00000000
...01101110 00000000 01011111 01011111 01101001 01110011
file prog3.o 00000000 01110000 01110010 01101111 01100111 00110001
01101111 01100011
00101110 00111001
01100011 00111001
00000000 01011111
01101101 01110011
01100001 01101001
01100011 01100001 01101110 01100110 00000000
01101110 00000000 01011111 01011111 01101001 01110000
01110011
...01101111 01100011 00111001 00111001 01011111 01110011
linker call 01100011 01100001 01101110 01100110 00000000 01110000
...
gcc prog1.o prog2.o ... -o prog.exe
executable code
...
00000000 01011111 01011111 01100100 01100001 01110100
01100001 01011111 01110011 01110100 01100001 01110010
01110100 00000000 01011111 01011111 01100100 01110011
01101111 01011111 01101000 01100001 01101110 01100100
file prog.exe 01101100 01100101 00000000 01011111 01011111 01000100
01010100 01001111 01010010 01011111 01000101 01001110
01000100 01011111 01011111 00000000 01011111 01011111
01101100 01101001 01100010 01100011 01011111 01100011
01110011 01110101 01011111 01101001 01101110 01101001
01110100 00000000 01011111 01011111 01100010 01110011
01110011 01011111 01110011 01110100 01100001 01110010
01110100 00000000 01011111 01011111 01101001 01110011
01101111 01100011 00111001 00111001 01011111 01110011
...

© ZPR-FER-UNIZG Introduction to Programming 31


Example: compile (and the rest) with one
command
writing source code, e.g.
Notepad
file prog1.c
notepad prog1.c

preprocessing, compile,
linking
gcc -o prog1.exe prog1.c

▪ files prog1.i, prog1.s, prog1.o are


prog1.i
automatically deleted
prog1.s ▪ to keep tis files, add gcc option -save-temps

prog1.o
▪ a very detailed description of all the
translation steps will be obtained by adding
the --verbose option

file
prog1.exe

© ZPR-FER-UNIZG Introduction to Programming 32


Example: C, compiling and execution
windows x64
executable code Linux x64 executable code
execution execution
prog1.exe prog1

C compiler for C compiler for


Windows x64 Linux x64

Operating system Operating system


Windows x64 Linux x64

prog1.c
source code

© ZPR-FER-UNIZG Introduction to Programming 33


Example: Java, compiling and execution
byte code (portable code, p-code)
Prog1.class

execution execution

JVM: Java Virtual Machine


Java compiler for JVM for JVM za
Windows x64 Windows x64 Linux x64

Operating system Operating system


Windows x64 Linux x64

The translation could also be done on a


Linux operating system, using a Java
Prog1.java compiler for Linux. The same byte code
source code would be obtained.
© ZPR-FER-UNIZG Introduction to Programming 34
Example: Python, execution
source code
prog1.py

execution execution

Python for Python for


Windows x64 Linux x64

Operating system Operating system


Windows x64 Linux x64

© ZPR-FER-UNIZG Introduction to Programming 35


Introduction to Programming - Lectures

2. The C Programming Language

© ZPR-FER-UNIZG Introduction to Programming 1


Basic elements of language C

Structure of a C program

© ZPR-FER-UNIZG Introduction to Programming 2


Structure of a C program
▪ C program consists of declarations and definitions of functions
(named blocks), declarations and definitions of variables and
directives to the preprocessor
▪ the difference between the terms declaration and definition will be
explained later. For now, only the term definition will be used.
▪ a complex statement or block (named or unnamed) can include
variable declarations and definitions, other statements and
unnamed blocks
▪ each statement must end with character ;
▪ ; is a terminator: an indication that the statement ends at this point
(and can start typing next if necessary)
▪ the block does NOT end with a character ; (it is not placed behind
the } character)

© ZPR-FER-UNIZG Introduction to Programming 3


Example
#include <stdio.h> directive to the preprocessor

int main(void) { named block (function)


int n, result; definition of variables
scanf("%d", &n); statement

// calculate the absolute value


if (n < 0) { start of unnamed block
result = -1 * n;
} end of unnamed block
else { start of unnamed block
result = n;
} end of unnamed block

printf("Input: %d Result: %d", n, result);


return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 4


C is a free-format language
▪ the standard does not prescribe the writing style
▪ the place of the beginning of the statement in the line is arbitrary,
the inserted gaps have no special meaning
▪ it is allowed to write more than one statement in the same line or
one statement in several lines
...
int n, result; scanf("%d", &n);
...
printf("Input: %d Result: %d"
, n
, result
);
...

▪ however, it is desirable to write neatly, or to insert blanks and


blank lines in appropriate places
© ZPR-FER-UNIZG Introduction to Programming 5
Example
▪ What's wrong with this program?
#include <stdio.h>
int main(

void
) { int n
, result
; scanf(
"%d", &n); // calculate the absolute value
if ( n < 0 )
{result = -1 * n
;}
else {result =
n; }printf("Input: %d Result: %d", n
, result); return 0;}

© ZPR-FER-UNIZG Introduction to Programming 6


Basic elements of C language

Keywords
Capitalization

© ZPR-FER-UNIZG Introduction to Programming 7


Keywords
▪ the key words are predefined identifiers that have special
meaning for the compiler. ISO/IEC 9899:2011 (C11) prescribes the
following 44 keywords:
auto extern short while
break float signed _Alignas
case for sizeof _Alignof
char goto static _Atomic
const if struct _Bool
continue inline switch _Complex
default int typedef _Generic
do long union _Imaginary
double register unsigned _Noreturn
else restrict void _Static_assert
enum return volatile _Thread_local

© ZPR-FER-UNIZG Introduction to Programming 8


Capitalization
▪ The C compiler is case sensitive
▪ variable names, keywords, and other identifiers must use the
uppercase / lowercase format

#Include <STDIO.h>
INT Main(Void) {
Return 0;
}

▪ every word in the previous program was spelled incorrectly. In


this program, the compiler will not be able to recognize :
▪ the preprocessor directive include
▪ file stdio.h
▪ keywords int, void, return
▪ function main
© ZPR-FER-UNIZG Introduction to Programming 9
Basic elements of C language

Comments

© ZPR-FER-UNIZG Introduction to Programming 10


Comments
▪ comments have no effect on program execution. They can be
installed in two ways, anywhere in the source code:
▪ a comment beginning with // extends to the end of the line
// student information
int yearOfBirth; // year of birth .

int yearOfEnrollment; // year of enrolling FER .

▪ a comment that begins with /* and ends with */ can span multiple
rows
▪ comments of this form should not be nested
/* the function calculates the largest common divisor for
positive integers m and n
*/
int maxCommonDivisor(int m, int n) {
...

© ZPR-FER-UNIZG Introduction to Programming 11


Basic elements of C language

Function main

© ZPR-FER-UNIZG Introduction to Programming 12


The main function (main)
int main(void) {
...
return 0;
}

▪ a C program starts executing with the main


▪ each program must contain exactly one function main
▪ int in front of main means that the function returns an integer to
the calling program (in this case the operating system). The
associated return actually returns an integer to the calling
program
▪ for now: always return an zero integer to the operating system, as
shown in the example
▪ void means that the function main receives no arguments
▪ the beginning and end of the statement block, representing the
body of the function, are indicated by curly brackets { and }
© ZPR-FER-UNIZG Introduction to Programming 13
Basic elements of C language

Variables and constants

© ZPR-FER-UNIZG Introduction to Programming 14


Variable
▪ in general: variable data (lat. variabilis - variable)
▪ in programming: space in the memory of a computer, predefined
and invariable in size, given a name and type in a definition,
contents of which can be modified, e.g. by assignment or by input
from a keyboard.
...
int main(void) {
int m, n; contents of the variables of this moment are uncertain
variables contain „garbage value”
... variables are uninitialized
n = 128; content of variable n is set by assignment
scanf("%d", &m) content of variable m is set by input from keyboard
...
m = 1000; contents of the variables may change again
scanf("%d", &n);
...
© ZPR-FER-UNIZG Introduction to Programming 15
Variable definition
int n, result;

▪ the previous statement defined two integer variables that can


only store integers. We say: variables are of type int
float x, y, z;
float v;

▪ previous statements have defined real variables x, y, z i v in which


only real numbers can be stored. We say: variables are of type
float (name derived from the term floating point)
▪ for now, only types int i float will be used. Other supported
data types will be explained later.
▪ a variable can be defined anywhere in the block, but the
definition must exist before the variable first used

© ZPR-FER-UNIZG Introduction to Programming 16


Variable definition with initialization
int k, m, n; k, m, n contain "garbage"
m = 3; m now contains 3
n = 3; n now contains 3
k still contains "garbage"

▪ A variable definition may contain an initializer that defines the


initial value of a variable
▪ the initial value must be specified individually for each variable to be
initialized

...
int main(void) {
int k, m = 3, n = 5; m contains 3; n contains 5
... k contains "garbage"

© ZPR-FER-UNIZG Introduction to Programming 17


Variable names
▪ variable names (and other identifiers, e.g. function names) are
composed of letters, numbers, and underscores _
▪ name must not begin with:
▪ digit
▪ two underscores
▪ underscore and a capital
▪ the name must not be equal to any keyword
▪ According to the convention, lowercase letters are used primarily to
form variable names, with the addition of few uppercase letters
(camelCase, explained later)
▪ examples of incorrect variable names
new+date x1/1 x$ Result!
float int return void
__sum _Product 1.sum 1product

© ZPR-FER-UNIZG Introduction to Programming 18


Variable names
▪ the length of a name is arbitrary, but the following should be
taken into account:
▪ some compilers may have restrictions on the number of significant
characters. The standard only requires that at least 31 of the first
characters of the name be significant. Therefore, some compilers
may not be able to distinguish between the following variable
names:
▪ average_grade_earned_in_class_ipro_year_2018
▪ average_grade_earned_in_class_ipro_year_2019
▪ names that are too long or too short reduce readability or make it
difficult to write programs. Using a name that reflects the meaning
of a variable significantly improves the clarity of the program
▪ instead of too long (above) or too short names (e.g. p1, p2) it is better:
ipro_avg_2018, ipro_avg_2019 (snake_case form) or
iproAvg2018, iproAvg2019 (camelCase oblik)
© ZPR-FER-UNIZG Introduction to Programming 19
Constants
▪ similar to variables, constants also have their types. The type of a
constant depends on the form in which it is written
float x, y;
int m, n;
x = 1.f; the value of a real constant is assigned to a real variable
y = 2; the value of an integer constant is assigned to a real variable
(a conversion is performed before the assignment)
m = 3; the value of an integer constant is assigned to an integer variable
n = 3.5f; the value of a real constant is assigned to an integer variable
(a conversion is performed before the assignment)

▪ the reason why letter f is added to real constants will be


explained in lectures on data types

© ZPR-FER-UNIZG Introduction to Programming 20


Basic elements of C language

Preprocessor directives

© ZPR-FER-UNIZG Introduction to Programming 21


Preprocessor directives - #include
#include <stdio.h>

▪ preprocessor directive: before translation, include the contents of


the file <stdio.h> in the program
▪ <stdio.h> contains the declarations and definitions that are
required for the program to properly use, among other things, the
printf and scanf functions (functions for output and input)
▪ conclusion: at the beginning of every program that uses the scanf
or printf functions, there must be directive
#include <stdio.h>

© ZPR-FER-UNIZG Introduction to Programming 22


Example
▪ gcc -E prog1.c > prog1.i
source code prog1.c preprocessed source code prog1.i
#include <stdio.h> ...
__attribute__((__cdecl__))
int main(void) { __attribute__((__nothrow__))
int n, result; int printf (const char *, ...);
scanf("%d", &n); ...
__attribute__((__cdecl__))
// calculate the absolute value
__attribute__((__nothrow__))
if (n < 0) {
int scanf (const char *, ...);
result = -1 * n;
...
} else {
result = n; int main(void) {
} int n, result;
scanf("%d", &n);
printf("Input: %d Result: %d", n,
result); if (n < 0) {
result = -1 * n;
...
} else {
...

© ZPR-FER-UNIZG Introduction to Programming 23


Preprocessor directive - #define
#define PI 3.14159f

▪ Preprocessor directive: during the preprocessing phase, replace


each occurrence of the word PI in the source code with 3.14159f
▪ this defines a symbolic constant
▪ by convention, the names of the constants are written in capitals
letters <stdio.h>
#include
#define PI 3.14159f
int main(void) { „print a new line”, jump to a
float r; // radius of a circle new line on the screen
scanf("%f", &r);
printf("Circle area: %f\n",
r * r * PI);
printf("Circle circumference: %f", Not like this!
2 * r * PI); float pi;
return 0;
pi = 3.14159f;
}
© ZPR-FER-UNIZG Introduction to Programming 24
Example
▪ gcc -E prog2.c > prog2.i
source code prog2.c preprocessed source code prog2.i
#include <stdio.h> ...
#define PI 3.14159f __attribute__((__cdecl__))
__attribute__((__nothrow__))
int main(void) {
int printf (const char *, ...);
float r; // radius of a circle
...
scanf("%f", &r);
printf("Circle area: %f\n", int main(void) {
r * r * PI); float r;
printf("Circle circumference: %f", scanf("%f", &r);
2 * r * PI); printf("Circle area: %f\n",
r * r * 3.14159f);
return 0; printf("Circle circumference: %f",
} 2 * r * 3.14159f);
return 0;
Not like this! }
#define TWO 2
...
printf("Circle circumference : %f",
TWO * r * PI);
...
© ZPR-FER-UNIZG Introduction to Programming 25
An example of executing the previous program
5
Circle area: 78.539801
Circle circumference: 31.415920

▪ characters that the user typed on the keyboard are shown in red
▪ mark  will always be used when in instances it will be necessary to emphasize that
somewhere a jump to newline occurs or Enter (or Return) is pressed

© ZPR-FER-UNIZG Introduction to Programming 26


Basic elements of C language

Expressions

© ZPR-FER-UNIZG Introduction to Programming 27


Expressions
▪ Expression is a combination of operators, operands (constants,
variables, function calls, expressions, ...) and parentheses
▪ Types of expressions:
▪ assignment expression
▪ arithmetic expression
▪ relational expression
▪ logical expression
▪ Expressions can be embedded in other, more complex
expressions, used as function arguments, or parts of statements

© ZPR-FER-UNIZG Introduction to Programming 28


Expressions
▪ Examples of expressions (assuming a and b are integer variables):
256 arithmetic expression
a arithmetic expression
a + 11 arithmetic expression
(a + 1) * (b - 1) arithmetic expression
a = 20 assignment expression
b = a + 3 arithmetic expression within an assignment expression
a <= 10 relational expression
(a <= 10) && (b == 0) two relational expressions within a logical expression

▪ Examples of using an expression as a function argument and part


of the statement (in this case, the statement return)
printf("%d", (a + 1) * (b - 1));
return a - b;

© ZPR-FER-UNIZG Introduction to Programming 29


Assignment operator and assignment expression
▪ Assignment operator assigns a value to a variable
▪ symbol in the pseudo-code :=
▪ symbol in C =
▪ Examples: constant 5 stored at some
memory location
5
▪ int k; =
k = 5; memory location used to
? 5 store variable k
k

constant 1 stored at some


memory location
▪ k = k + 1; 1
=
5+1

k 5 6

© ZPR-FER-UNIZG Introduction to Programming 30


Locator value, lvalue
▪ Locator value (Lvalue, L-value, lvalue) is an expresson that
designates an object stored in memory at a specific address
▪ e.g., variable names k and p are lvalue because they represent
objects (in this case an integer variable and an integer array) whose
values are stored at specific addresses in memory

address in memory
... that contains
... k 5 integer variable k
int k = 5; ...
int p[3] = {7, 9, 11}; p 7 address in memory
...
9 that contains integer
array p
11
...

© ZPR-FER-UNIZG Introduction to Programming 31


Modifiable lvalue, non-modifiable lvalue
▪ lvalue which represents an object whose value can be changed is
called modifiable lvalue
▪ variable name is modifiable lvalue
...
int k = 5;
...
k = 10; the value of the object can be changed using lvalue k

▪ array name is non-modifiable lvalue. The contents of the array


cannot be changed by using (only) the array name p1
...
int p1[3] = {7, 9, 11}, p2[3] = {6, 8, 10};
...
p1 = p2; incorrect: p1 is non-modifiable lvalue

© ZPR-FER-UNIZG Introduction to Programming 32


The left side of the assignment expression
▪ The left side (left operand) of the assignment expression must be
a modifiable locator value (modifiable lvalue).
int m, n, k;
int p[3] = {7, 9, 11};
n = 15 + 3; n is modifiable lvalue
m = m + n + 1; m is modifiable lvalue
k + 1 = m + 1; incorrect: k + 1 is not lvalue
7 = m; incorrect: constant 7 is not lvalue
p = 10; incorrect: p is not modifiable lvalue

According to (now obsolete) interpretation of Kernighan and Ritchie: The C


Programming Language, term Lvalue (left-value) refers to the type of expression that
can be used on the left side of the assignment expression.
© ZPR-FER-UNIZG Introduction to Programming 33
The right side of the assignment expression
▪ The right side of the assignment expression can contain any
expression (it may, but need not be lvalue). E.g. variable,
constant, arithmetic expression, function call, etc.
▪ the value of right side expression is calculated (evaluated) and then
set as the new value of the object designated by lvalue on the left
side of the assignment expression
int m, n;
n = 15 * 3 - 100;
m = abs(n) / 2;

According to the now outdated, but often used interpretation in the literature, the
term Rvalue (right-value) refers to the type of expression that can be used on the right
side of the assignment expression.
© ZPR-FER-UNIZG Introduction to Programming 34
The result of the assignment expression
▪ the assignment expression is primarily used to assign values, but
like any other expression, it produces a result.
▪ this result is not commonly used, as in the following example: the
arithmetic expression results in 30, the assignment expression
assigns the value of 30 to the variable m, and the final result of the
assignment expression is again the value of 30 (the value just
assigned). The value of the assignment expression remained unused.
int m;
m = 15 * 2;

▪ in the following example, the result of the assignment expression will


be used. The constant 5 is assigned to the variable m, the final result
of the expression is 5, which is sent to the output.
int m;
printf("%d", m = 5);

© ZPR-FER-UNIZG Introduction to Programming 35


Multiple assignment
▪ the fact that the assignment expression produces a result can be
exploited in a multiple association
int a, b, c;
...
c = 3;
...
a = b = c * 5; Order of execution: a = (b = (c * 5));

▪ the value of c * 5 (15) was calculated and assigned to variable b.


▪ the result of the assignment expression (15) is assigned to variable a
▪ the result of the assignment expression (15) is not used and is discarded

▪ Is the following multiple assignment expression correct?


a = b + 2 = c; Incorrect because b + 2 is not a lvalue

© ZPR-FER-UNIZG Introduction to Programming 36


Operator priority and associativity
▪ The order of operations in expressions depends on
▪ operator priority, if the operators are of different priority
a + b * c (a + b) * c ili a + (b * c)
operator priority determines that operation b * c is performed first
▪ operator associativity, if the operators are of equal priority
a / b * c (a / b) * c ili a / (b * c)
operator associativity determines that operation a / b is performed first
← Lower Higher →

Operator
Operator
associativity
Priority

* / L→R
Binary + - L→R
= R→L

© ZPR-FER-UNIZG Introduction to Programming 37


Example
▪ While evaluating
a = b = c * 5
several operations need to be performed. In what order the
operations will be performed?
▪ The multiplication operator has a higher priority than the
assignment operator
▪ the multiplication operation will be performed first
a = b = (c * 5)
▪ Assignment operators have equal priority. The order of
performance is determined by the associativity of the operator.
▪ operator associativity R→L means that the operations are
performed from right to left, therefore
(a = (b = c * 5)) operation c * 5 was performed previously.

© ZPR-FER-UNIZG Introduction to Programming 38


Example
▪ Initialize integer variables a and b to values 14 and -9. The
program should print their values, mutually exchange the values
in the variables, and re-print the values of the variables on the
screen. The output should look like this: a=14, b=-9
a=-9, b=14

#include <stdio.h>
int main(void) { a b aux
int a = 14, b = -9, aux; 14 -9 ?
printf("a=%d, b=%d\n", a, b); 14 -9 ?
aux = a; 14 -9 14
a = b; -9 -9 14
b = aux; -9 14 14
printf("a=%d, b=%d", a, b); -9 14 14
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 39


Arithmetic operators and expressions
▪ Only the basic arithmetic operators are listed here
Operator Meaning Operands
+ addition int, float
- subtraction int, float
* multiplication int, float
/ division int, float
remainder of integer division
% int
(modulus)

▪ the arithmetic operator and associated operands form the


arithmetic expression
▪ operands can be variables, constants, and more complex arithmetic
expressions
© ZPR-FER-UNIZG Introduction to Programming 40
Result of expression with integer operands
▪ note: if both operands are integer
▪ the result is an integer
▪ the operation is performed in an integer domain (especially
important for a division operation)

int a = 11, b = 2;
arithmetic expression result
a + b 13
a - b 9
a * b 22
a / b 5
a % b 1

© ZPR-FER-UNIZG Introduction to Programming 41


Result of expression with floating point operands
▪ notice: if there is at least one floating point operand
▪ the result is of floating point type
▪ the operation is performed in the floating point domain (especially
important for a division operation)
▪ the modulus operator % must not be used
int a = 11;
float b = 2.f;
arithmetic expression the result
a + b 13.0
a - b 9.0
a * b 22.0
a / b 5.5
a % b compiler error

© ZPR-FER-UNIZG Introduction to Programming 42


Arithmetic operators priority
▪ multiplication, division, and modulus operators have equal
priority, but higher than addition and subtraction operators
a + b * c ≡ a + (b * c)
b * c + a ≡ (b * c) + a
▪ if arithmetic operators have equal priority (e.g. multiplication,
division and modulus) then operations are performed from left to
right
a / b * c ≡ (a / b) * c
x / a + b * c + d * e ≡ ((x / a) + (b * c)) + (d * e)
▪ if the assumed order of operations needs to be changed, use
round brackets, e.g.
(a + b) * c
x / ((a + b) * (c + d) * e)

© ZPR-FER-UNIZG Introduction to Programming 43


Example
▪ Determine the value and type of results of the following
arithmetic expressions
int m = 11;
float x = 2.f;
m / x 5.5, float
m / 2 5, int
m / 2 * x 10.0, float
x * m / 2 11.0, float
x * (m / 2) 10.0, float
m + 1 / x 11.5, float
(m + 1) / x 6.0, float

© ZPR-FER-UNIZG Introduction to Programming 44


Relational operators and expressions
▪ relational operators are comparing the operands
▪ the relational operator and associated operands form a relational
expression
▪ operands in relational expressions can be both real and integer (also
of other types). Operands can be variables, constants, and more
complex arithmetic expressions
▪ relational expression is a simple logical expression which is
evaluated as true or false. E.g.
...
if (n < 0)
...

▪ a relational expression n < 0 will be evaluated as true if the value


of variable n is less than zero, otherwise, the expression is
evaluated as false
© ZPR-FER-UNIZG Introduction to Programming 45
Relational operators
▪ all relational operators are listed
Operator Meaning
> greater than
< less than
>= greater or equal
<= less or equal
== equal
!= not equal

▪ pay particular attention to the following: operators = and == have


a completely different meaning. The compiler will not be able to
detect usage of an incorrect operator: the program will be
compiled and will run, but incorrectly.
© ZPR-FER-UNIZG Introduction to Programming 46
Logical operators and expressions
▪ logical operators build complex expressions
▪ the logical operator and associated operands form a logical
expression
▪ relational expressions and complex logical expressions can be
operands in logical expressions. E.g.
...
if (n >= 10 && n <= 20)
...

▪ logical expression n >= 10 && n <= 20 will be evaluated as true if


and only if the result of relational expression n >= 10 is true and
the result of relational expression n <= 20 is true

© ZPR-FER-UNIZG Introduction to Programming 47


Logical operators
▪ all logical operators are listed
Operator Meaning
! logical NOT
&& logical AND
|| logical OR

© ZPR-FER-UNIZG Introduction to Programming 48


Operator priority
▪ pay attention to the priority of arithmetic, relational, logical, and
assignment operators. Use parentheses where necessary.
Operator priority
!
* / %
+ -
< <= > >=
== !=
&&
||
▪ Example: =

▪ !x > 20 will be evaluated as (!x) > 20


▪ correct expression: !(x > 20)

© ZPR-FER-UNIZG Introduction to Programming 49


Examples of logical expressions
▪ The result of a logical expression is true
▪ if the value of a floating point variable x is in interval [3, 5] or in
interval [7, 9]
(x >= 3.f && x <= 5.f) || (x >= 7.f && x <= 9.f)

▪ if the value of a floating point variable x is in interval [3, 5] and the


value of a floating point variable y is not in interval [7, 9]
x >= 3.f && x <= 5.f && !(y >= 7.f && y <= 9.f) or
x >= 3.f && x <= 5.f && (y < 7.f || y > 9.f)
Transformation of the first into the second term and vice versa: De Morgan laws

▪ if the value of a floating point variable x is positive or at least by 10


greater than both y and z
x > 0.f || x >= y + 10.f && x >= z + 10.f
▪ for exercise: check for missing brackets or remove any surplus
brackets
© ZPR-FER-UNIZG Introduction to Programming 50
Basic elements of C language

Control flow statements


Simple selection

© ZPR-FER-UNIZG Introduction to Programming 51


Simple selection
▪ a simple control flow statement
if (n < 0) {
res = -1 * n;
} else {
res = n;
}
the execution of the program continues here, regardless of the result of the
logical expression
▪ if the logical expression (in parentheses behind the keyword if ) is
calculated as true, statements within the first pair of curly brackets
are executed
▪ otherwise, statements within the second pair of curly brackets are
executed (behind the else keyword)
▪ the part of the statement that starts with the keyword else need
not always exist

© ZPR-FER-UNIZG Introduction to Programming 52


Basic elements of C language

Functions for reading from standard input and


writing to standard output

© ZPR-FER-UNIZG Introduction to Programming 53


Reading values from standard input
scanf("%d", &n);

▪ a function call to read values from the keyboard


▪ the first argument is format - a string of characters within double
quotation marks containing one or more conversion specifications
▪ "%d" is format that allows one integer value to be read
▪ "%f" is a format that allows one floating point value to be read
▪ "%d %d %f %d" is a format that allows reading (in sequence) two
integers, floating point and another integer value
▪ one or more of the following arguments represent the addresses of
the variables into which the function should write the values read
from the keyboard. The address of the variable is obtained by
placing the operator & in front of the variable name. Variable types
must match the conversion specifications specified in the format by
number and type.

© ZPR-FER-UNIZG Introduction to Programming 54


Example
int i, j, k;
float x;
scanf("%d %d %f %d", &i, &j, &x, &k);

▪ for input: 37 5 3.14 2


▪ after execution of the function scanf, variables i, j, x, k will
contain values 37, 5, 3.14 i 2, respectfully

mark  emphasizes that a „jump to the new line” was sent to the output or that the
Enter key or the Return key was pressed while typing

© ZPR-FER-UNIZG Introduction to Programming 55


Print values to standard output
printf("Input: %d Result: %d", n, res);

▪ a function call to print values to the screen


▪ the first argument is format - a string of characters within double
quotation marks containing a combination of characters to be printed
and / or containing conversion specifications
▪ %d is a conversion specification for printing an integer value
▪ %f is a conversion specification for printing a floating point value
▪ %e is a conversion specification for printing a floating point value in
scientific notation
▪ further arguments (if specified) represent values that will be printed in
places where the conversion specifications are specified in the format
▪ this values can be variables, constants, but also more complex
expressions
▪ the values must match the conversion specifications specified in format
by number and type.
© ZPR-FER-UNIZG Introduction to Programming 56
Adjusting the print width of an integer value
▪ the print width can be adjusted by the conversion specification
▪ if the width is not specified or the specified width is less than the
required number of digits in printed value, only digits in value will be
printed
▪ If the specified width is greater than the number of digits in value,
the blanks will be printed in front of the digits to fill the specified
width
printf("%d,%5d,%2d", 128, -12, 256);

128, -12,256

© ZPR-FER-UNIZG Introduction to Programming 57


Adjusting the width and precision of printing of a
floatig point value
▪ when printing a real number, it is possible to adjust the total print
width and the number of digits printed behind the decimal point
(precision)
printf("%f,%f,%f\n", 4.5f, 1280.0f, -3.4555555f);
4.500000,1280.000000,-3.455556

%f total width as needed, 6 the digits behind the decimal point, rounded if needed

printf("%5.2f,%12.4f,%.4f", 5.128f, -256.128f, 12.4555555f);


5.13, -256.1280,12.4556

%5.2f min. total width 5 characters, 2 digits behind decimal point, rounded if needed
%12.4f min. total width 12 characters, 4 digits behind decimal point, rounded if needed
%.4f 4 digits behind decimal point, as many as needed in front of decimal point

© ZPR-FER-UNIZG Introduction to Programming 58


Print a floating point number in scientific notation
▪ specification %e is similar to the specification %f. The only
difference is that the number is printed in the form that contains
the exponent of the number 10
printf("%e,%e,%e\n", 4.5f, 1280.0f, -3.4555555f);

4.500000e+000,1.280000e+003,-3.455556e+000
%e width as needed, 6 digits behind the decimal point, rounded as needed

printf("%12.2e,%15.4e,%.4e", 5.128f, -256.128f, 12.4555555f);


5.13e+000, -2.5613e+002,1.2456e+001

%12.2e min. total width 12 characters, 2 digits behind the decimal point, rounded as needed
%15.4e min. total width 15 characters, 4 digits behind the decimal point, rounded as needed
%.4e 4 digits behind the decimal point, as many as needed in front

© ZPR-FER-UNIZG Introduction to Programming 59


Range and precision

Integer and floating point type

© ZPR-FER-UNIZG Introduction to Programming 60


The range of integer variables and constants
▪ Due to the way integers are stored on your computer, only a
limited set of integers can be stored
▪ storage of integers will be discussed in more detail later, for now
it is sufficient to know the following:
▪ integer data type (int variable and constant) can be represent
integers in the interval [-2 147 483 648, 2 147 483 647]. Attempt to
use integers outside of this interval can lead to unexpected results,
e.g.
int min = -2147483648, max = 2147483647, rez1, rez2;
rez1 = min - 1;
rez2 = max + 1;
printf("-2147483648 - 1 > %d\n", rez1);
printf("2147483647 + 1 > %d", rez2);

-2147483648 - 1 > 2147483647


2147483647 + 1 > -2147483648
© ZPR-FER-UNIZG Introduction to Programming 61
The range of real variables and constants
▪ Due to the way floating point numbers are stored on your
computer, only the following floating point numbers can be
stored
▪ numbers from the interval [-3.402823ˑ1038, -1.401298ˑ10-45] or
▪ numbers from the interval [1.401298ˑ10-45, 3.402823ˑ1038] or
▪ 0.0
▪ storage of floating point numbers will be discussed in more detail
later
▪ attempting to use floating point numbers beyond that interval may
lead to unexpected results
float x = 3.4e38f * 1.1f;
float y = 1.401298e-45f / 2.f;
printf("%f\n%e\n", x, y);

inf
0.000000e+000
© ZPR-FER-UNIZG Introduction to Programming 62
Precision of floating point variables and constants
▪ Due to the way floating point numbers are stored, it is not
possible to completely accurately store all real numbers from the
intervals specified above
▪ in fact, infinite numbers from these intervals cannot be shown
exactly
▪ the accuracy of storing floating point numbers will be discussed in
more detail later
float x = 0.0625f;
float y = 0.0624f;
printf("%20.18f\n%20.18f", x, y);

0.062500000000000000
0.062399998307228088

© ZPR-FER-UNIZG Introduction to Programming 63


Precision of floating point variables and constants
▪ sometimes just because of the rounding on the printout (if a
sufficiently small number of digits to be printed after the decimal
point is given) the number appears to be stored exactly
float x = 0.01f;
printf("%f\n", x);
printf("actually stored:\n", x);
printf("%20.18f", x);

0.010000
actually stored:
0.009999999776482582

© ZPR-FER-UNIZG Introduction to Programming 64


Useful mathematical functions

© ZPR-FER-UNIZG Introduction to Programming 65


Useful mathematical functions
▪ these functions can be used as operands in an arithmetic or
relational expression
▪ the arguments of these functions can be variables, constants, or
arithmetic expressions
Function Meaning
▪ the arguments and results of the
sqrt(x) 𝑥
following functions are numbers
of double precision, however for pow(x, y) xy
the time being this can be sin(x) sine (rad)
ignored.
cos(x) cosine (rad)
tan(x) tangent (rad)
log(x) ln x
log10(x) log10 x

© ZPR-FER-UNIZG Introduction to Programming 66


Example
#include <stdio.h>
#include <math.h> // Note this include!
int main(void) {
printf("sqrt(20.25) = %f\n", sqrt(20.25f));
printf("pow(6.25, -0.5) = %f\n", pow(6.25f, -0.5f));
printf("sin(3.1415926/2) = %f\n", sin(3.1415926f/2));
printf("ln(2.7182818) = %f\n", log(2.7182818f));
printf("log(1000.0) = %f\n", log10(1000.f));
return 0;
}

sqrt(20.25) = 4.500000
pow(6.25, -0.5) = 0.400000
sin(3.1415926/2) = 1.000000
ln(2.7182818) = 1.000000
log(1000.0) = 3.000000

© ZPR-FER-UNIZG Introduction to Programming 67


Example
#include <stdio.h>
#include <math.h>
int main(void) {
float a, b, c;
printf("Enter the sides > ");
scanf("%f %f", &a, &b);
c = sqrt(pow(a, 2.f) + pow(b, 2.f));
printf("Hypotenuse = %f\n", c);
return 0;
}

Enter the sides > 6 8


Hypotenuse = 10.000000

© ZPR-FER-UNIZG Introduction to Programming 68


Programming, compiler, types of errors

© ZPR-FER-UNIZG Introduction to Programming 69


Procedures for making smaller programs
1. Algorithm development (e.g. using pseudo code)
2. Implementation of algorithm in programming language
(coding)
3. Translating the program into object code (compilation)
- The compiler reports formal errors
4. Correcting formal errors
5. Linking object code (linking)
- linker reports linking errors
6. Correcting linking errors
7. Execute programs using test data
- runtime and semantic errors are detected
8. Correcting runtime and semantic errors
© ZPR-FER-UNIZG Introduction to Programming 70
Procedures for making smaller programs

syntax errors

Text editor source object


compiler
code code

test data program


library
run-time errors linker errors)

execution executable linker


code

semantic errors
results

© ZPR-FER-UNIZG Introduction to Programming 71


Procedures for making smaller programs
▪ Implementation of the algorithm in programming language
(coding)
▪ is done by typing the source code into a file using a text editor. E.g.
notepad, vi, ...
▪ or using a text editor built into the integrated developer
environment (IDE), e.g. VSCode, Eclipse, MS Visual Studio, ...

▪ Translating source code into object program


▪ done by a compiler
▪ compiler (and preprocessor) detect and report syntax (spelling, formal)
errors
▪ the developer corrects the source code and restarts the compilation
▪ the process is repeated as long as the compiler reports formal errors

© ZPR-FER-UNIZG Introduction to Programming 72


Procedures for making smaller programs
▪ Linking compiled object code into executable code
▪ done by a linker
▪ the object code from one or more compiled modules is linked with the
code from the program libraries
▪ the linker detects and reports linker errors
▪ the developer corrects the source code and restarts compilation and
linking
▪ the process is repeated as long as the linker reports linker errors

© ZPR-FER-UNIZG Introduction to Programming 73


Procedures for making smaller programs
▪ Program testing
▪ it is done by preparing the input data sets and the expected results,
and then executing the program, for example by running a program
from an operating system shell
▪ it reveals
▪ run-time errors
and
▪ incorrect results suggesting semantic errors
▪ the developer corrects the source code and restarts compilation,
linking, and testing
▪ it is repeated as long as abnormal program interruptions occur or
incorrect results are obtained during program execution

© ZPR-FER-UNIZG Introduction to Programming 74


Example - developing a small program
#inklude <stdio.h>
int main(void) {
int n; result;
scan("%d", -n);
// calculate the absolute value
if (n < 0) {
result = --n;
} else {
result = n;
}
print("Input: %d Result: %d", n, result);
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 75


Example - formal errors
C:\ipro>gcc -std=c11 -Wno-all -o prog1.exe prog1.c
prog1.c:1:2: error: invalid preprocessing directive #inklude
#inklude <stdio.h>
^~~~~~~~
prog1.c: In function 'main':
prog1.c:4:11: error: ‘result' undeclared (first use in this function)
int n; result;
^~~
prog1.c:4:11: note: each undeclared identifier is reported only once for
each function it appears in

▪ correct errors in source code and repeat compilation


#inklude <stdio.h>
int main(void) {
int n; result;
scan("%d", -n);
...

© ZPR-FER-UNIZG Introduction to Programming 76


Example - linker errors
C:\ipro>gcc -std=c11 -Wno-all -o prog1.exe prog1.c
C:\Users\user\AppData\Local\Temp\cc6jyeMA.o:prog1.c:(.text+0x20):
undefined reference to `scan'
C:\Users\user\AppData\Local\Temp\cc6jyeMA.o:prog1.c:(.text+0x41):
undefined reference to `print'
collect2.exe: error: ld returned 1 exit status

▪ correct source code errors, recompile and relink

...
int n = 0, result;
scan("%d", -n);
...
print("Input: %d Result: %d", n, result);
...

© ZPR-FER-UNIZG Introduction to Programming 77


Example - runtime errors
C:\ipro>gcc -std=c11 -Wno-all -o prog1.exe prog1.c
C:\ipro>prog1.exe
-11

C:\ipro>

▪ how to detect errors that the compiler and linker failed to


identify?

© ZPR-FER-UNIZG Introduction to Programming 78


Debugging
▪ Options for searching for runtime errors and semantic errors
▪ read the program and think
▪ add auxiliary prints to strategic places in the program

#include <stdio.h>
int main(void) {
int n, result;
scanf("%d", -n);
printf("Read n=%d\n", n);

// calculate the absolute value


if (n < 0) {
printf("n is less than zero");
result = --n;
printf("result=%d", result);
} else {
printf("n is greater than zero");
rez = n;
}
printf("Input: %d Result: %d", n, result);
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 79


Debugging
▪ Better way: use specialized bug-finding programs – (debuggers)
▪ in the command line (operating system shell)
▪ integrated in the programming environment(VSCode, Eclipse, ...)
▪ only a small set of options of debugger gdb when used in
combination with the compiler gcc is shown below

© ZPR-FER-UNIZG Introduction to Programming 80


Debugger - finding where the program breaks
C:\ipro>gcc -std=c11 -ggdb -o prog1.exe prog1.c
C:\ipro>gdb prog1.exe
(gdb) start
Temporary breakpoint 1 at 0x401497: file prog1.c, line 5.
Starting program: C:\ipro/prog1.exe
Temporary breakpoint 1, main () at prog1.c:5
5 scanf("%d", -n);
(gdb) frame which statement will be executed as next?
#0 main () at prog1.c:5
5 scanf("%d", -n);
(gdb) next execute the next statement
-11 input n
Program received signal SIGSEGV, Segmentation fault.
0x7593ff0b in ungetwc () from C:\WINDOWS\SysWOW64\msvcrt.dll

▪ apparently, the program was terminated after the scanf function


was called, now it is no longer difficult to spot the error. Correct and
retest. scanf("%d", -n); → scanf("%d", &n);

© ZPR-FER-UNIZG Introduction to Programming 81


Debugger - searching for semantic errors
C:\ipro>gcc -std=c11 -ggdb -o prog1.exe prog1.c
C:\ipro>prog1.exe
-11
Input: -11 Result: 4194432

▪ The program was not interrupted, but the result is incorrect.


Where might the semantic error occur?
scanf("%d", &n); is the value of variable n is now read correctly?
// calculate the absolute value
if (n < 0) { was this relational expression properly evaluated? how can we know?
result = --n; does variable result now contain a correct value?
} else {
result = n;
}

© ZPR-FER-UNIZG Introduction to Programming 82


Debugger - searching for semantic errors
C:\ipro>gcc -std=c11 -ggdb -o prog1.exe prog1.c
C:\ipro>gdb prog1.exe
(gdb) start start the program and stop at the first statement
...
(gdb) watch result watch varijable result - whenever it changes, stop the program
Hardware watchpoint 2: rez
(gdb) continue continue executing
Continuing.
-11 input n
Hardware watchpoint 2: result result changed. Where and how is reported:
Old value = 4194432
New value = -12
0x004014c6 in main () at prog1.c:9
9 result = --n; Here you are! Something is wrong in result = --n;

© ZPR-FER-UNIZG Introduction to Programming 83


What follows is: testing, testing, testing, ...
▪ Correct the error, recompile, relink and test with different input
data
C:\ipro>gcc -std=c11 -Wall -pedantic-errors -o prog1.exe prog1.c
C:\ipro>prog1.exe
-11
Input: -11 Result: 11
C:\ipro>prog1.exe
11
Input: 11 Result: 11
C:\ipro>prog1.exe
0
Input: 0 Result: 0

© ZPR-FER-UNIZG Introduction to Programming 84


Introduction to Programming - Lectures

3. Control flow

© ZPR-FER-UNIZG Intoduction to Programming 1


Control flow, control structures
▪ one of the most important aspects of programming is the ability
to control the order in which statements are executed (control
flow): prescribing which statements to execute in the next step of
executing the program. For this purpose programming control
structures are used
▪ selection (conditional statement)
▪ if ... then ...
▪ if ... then ... else ...
▪ switch (case ... then ..., case ... then ..., case ... then ..., ...)
▪ loop
▪ repeating statements until the condition is satisfied (condition-
controlled)
▪ repeating statements a certain number of times (count-controlled)

© ZPR-FER-UNIZG Intoduction to Programming 2


Sequence of statements
▪ a series of statements that are executed exactly one after the
other, in the order they are written
Pseudocode Flowchart
...
input a, b, x
input (a, b, x)
y := ax + b
output (y) y = ax + b
...
output y

C program
...
scanf("%f %f %f", &a, &b, &x);
y = a * x + b;
printf("%f", y);
...
© ZPR-FER-UNIZG Intoduction to Programming 3
Simple selection

if..then

© ZPR-FER-UNIZG Intoduction to Programming 4


Simple selection - if
Pseudocode C program
... if (logical_expression)
if logical_expression then statement; single statement!
statement_1
statement_2
...
C program - example
...
...
Flowchart if (grade > 1)
logical No printf("The exam is passed!");
expr. ...
Yes
statement_1

statement_2 What if more than one statement is to be


... executed when the grade is passing?
Solution: Use a compound statement

© ZPR-FER-UNIZG Intoduction to Programming 5


Compound statement
▪ problem: only one statement is allowed to be executed when the
result of the logical expression is true. What to do if more than
one statement is required?
▪ solution: compound statement (block statement)
▪ one or more statements delimited by curly brackets
▪ can be used in places where only one statement is allowed
according to syntax (if, while, ...)
▪ compound statement is never teminated with ;
Sintax of compound statement Example of compound statement
{ ...
statement_1; if (grade > 1) {
statement_2; printf(" The exam is passed.");
... countPassed = countPassed + 1;
} }
...
© ZPR-FER-UNIZG Intoduction to Programming 6
Example
▪ Enter a floating point number from the keyboard into variable x.
If the reciprocal for x is defined, output x and its reciprocal
▪ Pseudocode and flowchart

input(x) input x
if x ≠ 0 then No
output(x, 1/x) x≠0
Yes
output x, 1/x

© ZPR-FER-UNIZG Intoduction to Programming 7


Example: C program
#include <stdio.h> #include <stdio.h>
int main(void) { int main(void) {
float x; float x;
scanf("%f", &x); scanf("%f", &x);
if (x != 0) if (x != 0) {
printf("%f %f", x, 1/x); printf("%f %f", x, 1/x);
return 0; }
} return 0;
}
▪ both variants are correct, however
▪ although there is only one statement that must be performed when
the condition is satisfied, it is recommended to use the form of a
compound statement, i.e., to enclose the statement in curly brackets
▪ it reduces the possibility of a logical error that may occur by possible
modification of the program, as shown in the following example

© ZPR-FER-UNIZG Intoduction to Programming 8


Example
▪ Similar example:
▪ Enter a floating point number from the keyboard into variable x. If
the reciprocal for x is defined, print x, after that calculate, and after
that print the reciprocal
▪ Pseudocode and flowchart
input x
input(x)
No
if x ≠ 0 then x≠0
output(x) Yes
recip := 1 / x
output x
output(recip)
recip = 1 / x
▪ Two new program variants will be written
by reworking the previous example output recip

© ZPR-FER-UNIZG Intoduction to Programming 9


Example: C program
#include <stdio.h> #include <stdio.h>
int main(void) { int main(void) {
float x, recip; float x, recip;
scanf("%f", &x); scanf("%f", &x);
if (x != 0) if (x != 0) {
printf("%f", x); printf("%f", x);
recip = 1 / x; recip = 1 / x;
printf(" %f", recip); printf(" %f", recip);
}
return 0; return 0;
} }

▪ the program on the left is faulty! By reworking the left-hand


version of the program from the previous example, the
programmer overlooked the need to add curly brackets and thus
made a hard-to-see logical mistake
© ZPR-FER-UNIZG Intoduction to Programming 10
Examples
▪ In some cases, for the sake of compactness and readability of the
program, it is appropriate not to use curly brackets. E.g.

// set the variable a to its absolute value


if (a < 0) a = -1 * a;

▪ Caution!
if (a < 0); a = -1 * a;

▪ The C compiler considers this (syntactically) correct. "Nothing"


terminated by character ; is called a null-statement. Quite
expected, null-statement takes no action
▪ analyze the consequences of this logical error
© ZPR-FER-UNIZG Intoduction to Programming 11
Example
▪ Enter a floating point number from the keyboard into variable x.
If the reciprocal for x is defined, output x and its reciprocal,
otherwise print "Undefined"
▪ Bad pseudocode and bad flowchart
input x

No
x≠0
input(x) Yes
if x ≠ 0 then
output x, 1/x
output(x, 1/x)
if x = 0 then
No
output("Undefined") x=0
Yes
output "Undefined"

© ZPR-FER-UNIZG Intoduction to Programming 12


Selection

if…then…else

© ZPR-FER-UNIZG Intoduction to Programming 13


if – then- else
Pseudocode
Flowchart
...
if logical_expression then Yes logical No
statement_1 expr
statement_2 statement_1 statement_3
...
else statement_2 statement_4
statement_3 ... ...
statement_4
...
...

C program C program - primjer


if (logical_expression) if (grade > 1)
statement_1; single statement! printf("The exam is passed!");
else else
statement_2; single statement! printf("The exam is not passed!");

© ZPR-FER-UNIZG Intoduction to Programming 14


Example
▪ Correction of poor solution for calculating reciprocal value
Bad Good
input x input x

No Yes No
x≠0 x≠0
Yes
output x, 1/x output "Undefined"
output x, 1/x

No
x=0
Yes if (x != 0)
output "Undefined"
printf("%f %f", x, 1/x);
else
printf("Undefined");

© ZPR-FER-UNIZG Intoduction to Programming 15


Example
▪ Print the message Enter an integer >
▪ Enter an integer from keyboard
▪ Calculate the absolute value of the entered number and print the
number and its absolute value
▪ An example of executing a program

Enter an integer> -47


Absolute value of -47 is 47

© ZPR-FER-UNIZG Intoduction to Programming 16


Solution (bad!)
#include <stdio.h>
int main(void) {
int n, absN;
printf("Enter an integer >");
scanf("%d", &n);
if (n < 0) {
absN = -1 * n; // absN = -n;
printf("Absolute value of %d is %d\n", n, absN);
} else {
absN = n;
printf("Absolute value of %d is %d\n", n, absN);
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 17


Solution (good!)
#include <stdio.h>
int main(void) {
int n, absN; // not abs, because there exist a function abs()
printf("Enter an integer > ");
scanf("%d", &n);
if (n < 0) {
absN = -1 * n; // absN = -n;
} else {
absN = n;
}
printf("Absolute value of %d is %d\n", n, absN);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 18


Solution (also good!)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("Enter an integer > ");
scanf("%d", &n);
printf("Absolute value of %d is %d\n", n, abs(n));
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 19


Example
▪ Print message Enter an integer >
▪ Enter an integer from the keyboard and, depending on the value,
print one, both, or none of the following messages:
▪ The number is positive
▪ The number is even
▪ Examples of program execution

Enter an integer > 12 Enter an integer > -12


The number is positive The number is even
The number is even

Enter an integer > 0


Enter an integer > 13 The number is even
The number is positive
Enter an integer > -47

© ZPR-FER-UNIZG Intoduction to Programming 20


Solution
#include <stdio.h>
int main(void) {
int n;
printf("Enter an integer > ");
scanf("%d", &n);
if (n > 0) {
printf("The number is positive\n");
}
if (n % 2 == 0) {
printf("The number is even\n");
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 21


Example
▪ Enter two integers from the keyboard. Depending on the values,
print either the message "numbers are equal" or the message
"numbers are not equal".

input a, b input a, b

Yes No Yes No
a=b a≠b

output output output output


"numbers are equal" "numbers are not equal" "numbers are not equal" "numbers are equal"

▪ note: solutions are equally correct


▪ for exercise: write C programs for both diagrams

© ZPR-FER-UNIZG Intoduction to Programming 22


Primjer
▪ Enter three different integers from the keyboard (no need to
check that the numbers are entered correctly)
▪ print the largest value on screen
▪ an example of executing the program
Enter three different integers > 1 17 -2
The largest value is 17

© ZPR-FER-UNIZG Intoduction to Programming 23


Solution (variant 1)
#include <stdio.h>

int main(void) {
int x, y, z, result;
printf("Enter three different integers > ");
scanf("%d %d %d", &x, &y, &z);
if (x > y) {
if (x > z) {
result = x;
} else {
result = z;
}
} else {
if (y > z) {
result = y;
} else {
result = z;
}
}
printf("The largest value is %d\n", result);
return 0;
}
© ZPR-FER-UNIZG Intoduction to Programming 24
Solution (variant 2)
#include <stdio.h>

int main(void) {
int x, y, z, result;
printf("Enter three different integers > ");
scanf("%d %d %d", &x, &y, &z);
result = x;
if (y > result)
result = y;
if (z > result)
result = z;
printf(" The largest value is %d\n", result);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 25


Selection

Cascading selection

© ZPR-FER-UNIZG Intoduction to Programming 26


Example
▪ Enter an integer. Depending on the value entered, print one of
the messages "Number is greater than 0", "Number is equal to 0"
or "Number is less than 0"
Enter an integer > -47
Number is less than 0
input a

Yes No ▪ cascading selection:


a>0
performing a series of
tests that stops when
output Yes No
"Number is greater than 0" a<0 first of the conditions is
satisfied
output output
"Number is less than 0" "Number is equal to 0"

© ZPR-FER-UNIZG Intoduction to Programming 27


Solution
#include <stdio.h>
int main(void) {
int a;
printf("Enter an integer > ");
scanf("%d", &a);
if (a > 0) {
printf("Number is greater than 0\n");
} else {
if (a < 0) {
printf("Number is less than 0\n");
} else {
printf("Number is equal to 0\n");
}
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 28


Program writing style

An important digression

© ZPR-FER-UNIZG Intoduction to Programming 29


Program writing style
▪ blanks, tabs, or newlines in the C program have no special
meaning
▪ e.g. the following program will compile correctly:
#include <stdio.h>
int main(void){int a;scanf("%d",&a);if(a%2==0)printf(
"Even");else printf("Odd");return 0;}

▪ programs written in this way will be very difficult for a person to


understand. So it's a good idea to choose and stick to some of the
code-writing conventions when writing a program

Thus, programs must be written for people to read, and only incidentally for
machines to execute.
H. Abelson, J. Sussman: Structure and Interpretation of Computer Programs; MIT Press, 1984.

© ZPR-FER-UNIZG Intoduction to Programming 30


Program writing style
▪ stylishly correct program
▪ is easier to understand - therefore more likely to be correct
▪ it is easier to maintain - so it is more likely to remain correct
▪ there are many different styles of writing C programs
▪ there is no "best" style. Which style you use can depend on different
factors
▪ company rules, personal preferences, ...
▪ examples of different writing styles of if
if (x > y) { if (x > y) if (x > y) if (x > y)
result = x; { { {
} result = x; result = x; result = x;
} } }

▪ The most important thing is to choose one style and apply it


consistently at least within the same project

© ZPR-FER-UNIZG Intoduction to Programming 31


Program writing style
▪ within the course Introduction to Programming, it is compulsory
to adhere to the recommendations presented in these lectures
▪ the recommendations presented here are based on the code writing
standards of the LLVM project
▪ LLVM Coding Standards
▪ https://llvm.org/docs/CodingStandards.html

▪ some other famous C/C++ writing styles:


▪ Google
▪ WebKit
▪ Microsoft Windows

© ZPR-FER-UNIZG Intoduction to Programming 32


Program writing styles - recommendations
▪ each statement should be started in a new line. The line should
be no longer than 80 characters
▪ a statement block that is logically subordinate should be indented
by a specified number of places. This procedure is called
indentation
▪ on IPRO course: 3 or 4 blank characters
▪ put block start mark { at the end of a line, and mark the end of
the block } exactly below the first character of the first line
if (x > y) {
result = x;
if (result == 0) {
z = 10;
}
printf("%d", z);
}

© ZPR-FER-UNIZG Intoduction to Programming 33


Program writing styles - recommendations
▪ the else keyword should be in the same line as the character }
which closed the block behind if. The same applies to the while
keyword in the do-while loop (explained later)
if (x > y) {
result = x;
} else {
result = y;
}

do {
...
} while (counter < 100);

© ZPR-FER-UNIZG Intoduction to Programming 34


Program writing styles - recommendations
▪ place empty lines to separate logical units of the program
▪ directives to the preprocessor
▪ variable definitions
▪ other key functional units (reading, calculation, ...)
#include <stdio.h>
. .

int main(void) {
int a;
float x, y;
. .

printf("Enter an integer > ");


scanf("%d", &a);
. .

if (a > 0) {
printf("Nuber is greater than 0\n");
...

© ZPR-FER-UNIZG Intoduction to Programming 35


Program writing styles - recommendations
▪ insert a blank before the character { which starts the block
int main(void) {
printf("%d", r);

▪ insert a blank after the comma, but not before the comma
scanf("%d %d", &m, &n);
▪ insert a blank behind the keyword that controls the program flow
(if, switch, while, for)
if (x > y) {

© ZPR-FER-UNIZG Intoduction to Programming 36


Program writing styles - recommendations
▪ insert a space between operators and operands, operators and
parentheses, but not between parentheses and operands
if (m > n) {
r = (m + n) * 10;

▪ the exception to the rule are unary operators and following


binary operators
▪ . ->
▪ the meaning of these operators will be explained later

year = p_student->birt_year;
s_student.avg_grade = 4.5f;
year++;
a = -a;

© ZPR-FER-UNIZG Intoduction to Programming 37


Program writing styles - recommendations
▪ do not place blanks between function name and open
parenthesis, after open parenthesis, before closed parenthesis, or
between closed parenthesis and character ;
scanf("%d %d", &m, &n);

▪ logically break complex expressions into multiple lines and align


vertically
if (month == 1 && day == 1 || month == 5 && day == 1 || month == 6 &&
day == 22 || month == 6 && day == 25 || month == 8 && day == 10) {
printf("State holiday");

if (month == 1 && day == 1 ||


month == 5 && day == 1 ||
month == 6 && day == 22 ||
month == 6 && day == 25 ||
month == 8 && day == 5) {
printf(" State holiday ");
}

© ZPR-FER-UNIZG Intoduction to Programming 38


Example
▪ Enter an integer representing a numeric grade. Depending on the
value, print one of the messages on the screen:
▪ excellent
▪ very good
▪ good
▪ sufficient
▪ insufficient
▪ incorrect grade

© ZPR-FER-UNIZG Intoduction to Programming 39


Solution (program section)
if (grade == 5) { ▪ the program is styled correctly
printf("excellent");
▪ yet, because of the large number of selections in
} else {
the cascade, it becomes difficult to write and
if (grade == 4) {
printf("very good");
read. It is easy to make a mistake in the number
} else { of brackets and the indentation that consumes
if (grade == 3) { too much space
printf("good"); ▪ also note that the curly brackets behind else
} else { (except the last one) are unnecessary since there
if (grade == 2) { is always only one statement behind else
printf("sufficient");
} else {
if (grade == 1) {
printf("insufficient");
} else {
printf("incorrect grade");
}
}
▪ let's write the program a little differently: remove
}
unnecessary curly brackets and redundant
}
}
indentation

© ZPR-FER-UNIZG Intoduction to Programming 40


Solution (program section)
if (grade == 5) { additionally: this particular example needs no curly brackets
printf("excellent");
} else if (grade == 4) {
printf("very good");
} else if (grade == 3) {
printf("good");
} else if (grade == 2) {
printf("sufficient");
} else if (grade == 1) {
printf("insufficient");
} else {
printf("incorrect grade");
}

▪ To note:
▪ it simplifies writing and increases code readability
▪ it will be easy for developers to see that this is nothing more than a
series of testing conditions that exclude one another
© ZPR-FER-UNIZG Intoduction to Programming 41
A better solution to one of the previous examples
#include <stdio.h>
int main(void) {
int a;
printf("Enter an integer > ");
scanf("%d", &a);
if (a > 0) {
printf("Number is larger than 0\n");
} else if (a < 0) {
printf("Number is smaller than 0\n");
} else {
printf("Number is equal to 0\n");
}

return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 42


Explanation
▪ In some programming languages, there is a special form of
statement for cascading selection. Eg. in Python:
if grade == 5:
print "excellent"
elif grade == 4:
print "very good"
elif grade == 3:
print "good"
elif grade == 2:
print "sufficient"
elif grade == 1:
print "insufficient"
else:
print "incorrect grade"

© ZPR-FER-UNIZG Intoduction to Programming 43


Explanation
▪ In programming language C there is no specific statement for
cascading selection
▪ a number of nested selections are used, which are written in a
characteristic way for readability only. Practically, it's a writing style,
not a special statement for cascading selection

if (logical_expression_1) ▪ if necessary, compund statements


statement_1; can be used instead of of individual
else if (logical_expression_2) statements (statement_1,
statement_2; statement_2, ...)
else if (logical_expression_3)
statement_3;
▪ if required, the last else and the
... associated statement can be omitted
else
statement_n;

© ZPR-FER-UNIZG Intoduction to Programming 44


Example
▪ Enter a floating point number T representing the measured body
temperature. Depending on the value, print one of the warnings
on the screen:
▪ The temperature is slightly elevated for 37.0 ≤ T < 38.0
▪ The temperature is significantly elevated for 38.0 ≤ T < 39.0
▪ The temperature is dangerously high for T ≥ 39

▪ Example of program execution


Enter the temperature > 39
The temperature is dangerously high

© ZPR-FER-UNIZG Intoduction to Programming 45


Rješenje
#include <stdio.h>
int main(void) {
float temp; // this example requires no curly brackets

printf("Enter the temperature > ");


scanf("%f", &temp);
if (temp >= 37.0f && temp < 38.0f) {
printf("The temperature is slightly elevated\n");
} else if (temp >= 38.0f && temp < 39.0f) {
printf("The temperature is significantly elevated\n");
} else if (temp >= 39.0f) {
printf("The temperature is dangerously high\n");
} // last "else" not required

return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 46


Possible dilemmas regarding else
▪ An important rule: else part of the selection statement "belongs"
to the nearest if statement (which does not already have "its"
else part)
▪ A carelessly nested selection statement can lead to a logical error
which is difficult to detect
▪ Example: if the integer b is non-zero, check that the integer value a
is divisible by b, and if so, print the message "a is divisible by
b". Otherwise (if b is zero), print "b is zero"
Wrong! Indentation does not help! Correctly
if (b != 0) if (b != 0) {
if (a % b == 0) if (a % b == 0)
printf("a is divisible by b"); printf("a is divisible by b");
else } else
printf("b is zero"); printf("b is zero");

© ZPR-FER-UNIZG Intoduction to Programming 47


Selection

switch

© ZPR-FER-UNIZG Intoduction to Programming 48


switch
▪ In cases where cascading selection is based on relational
expressions in which equality of integer values is tested, it is
appropriate to use the switch statement
▪ this means that the switch statement is only applicable in one of the
following cases of cascade selection. Which one?
if (grade == 5) { if (temp >= 37.0f && temp < 38.0f)
printf("excellent"); printf("The temperature is slightly elevated");
} else if (grade == 4) { else if (temp >= 38.0f && temp < 39.0f)
printf("very good"); printf("The temperature is significantly elevated");
} else if (grade == 3) { else if (temp >= 39.0f)
printf("good"); printf("The temperature is dangerously high");
} else if (grade == 2) {
printf("sufficient");
} else if (grade == 1) {
printf("insufficient");
} else {
printf("incorrect grade");
}

© ZPR-FER-UNIZG Intoduction to Programming 49


switch
C program - sintax
switch (integer_expression) {
case constant_integer_expression_1:
statements_1
case constant_integer_expression_2:
statements_2
case constant_integer_expression_n:
statements_n
default:
statements_d
}

▪ integer_expression: an expression that results in an integer value


(integer constants, variables, operators)
▪ constant_integer_expression: an integer expression that does not
contain variables

© ZPR-FER-UNIZG Intoduction to Programming 50


Labeled statement
▪ A label gives the ability to direct execution of the program to the
labeled statement. E.g. switch statement can direct further
execution of the program to statements marked with one of two
* forms of the label:
▪ case constant_integer_expression:
▪ default:
▪ the order of the labels in the switch statement is not specified
(e.g. label default: may be placed first), but the order of the
labels may affect the overall behavior of the statement
▪ specifying the label default: is optional

*Later, another form of label will be described which is used in combination with the
goto statement
© ZPR-FER-UNIZG Intoduction to Programming 51
switch - principle of action
▪ the value of the integer expression S (the expression in
parentheses behind the keyword switch)
▪ if exists label L with a value equal to S, the execution of the program
is continued with the statement labeled L (and continues over
following labels!).
▪ colloquial: "fallthrough down the labels" continues
▪ otherwise, if there is no such label L, execution of the program is
continued with the statement labeled default: if such a label in
the statement exists, otherwise switch statement immediately
ends

▪ let's try to print the name of the grade using the switch
statement instead of the cascading selection

© ZPR-FER-UNIZG Intoduction to Programming 52


Example: incorrect solution
switch (grade) { ▪ why is the solution incorrect?
case 5:
▪ if the variable grade contains a
printf("excellent");
case 4:
value of 3
goodsufficientinsufficientincorrect grade
printf("very good");
case 3: will be printed
printf("good"); ▪ switch statement should be
case 2:
printf("sufficient");
changed so that its execution is
case 1: interrupted after the instructions
printf("insufficient"); behind the appropriate label have
default:
been completed
printf("incorrect grade");
} ▪ introduce break statement

© ZPR-FER-UNIZG Intoduction to Programming 53


Example: correct solution
switch (grade) { ▪ break statement interrupts
case 5:
printf("excellent");
further execution of switch
break; ▪ (later, the same statement
case 4: will also be used to interrupt
printf("very good");
break;
the loop)
case 3: ▪ it is not necessary to write the
printf("good");
break;
last break, but it is
case 2: recommended to avoid
printf("sufficient"); subsequent logical errors
break;
case 1: ▪ in this example, the order of
printf("insufficient"); the labels is irrelevant
break;
default:
printf("incorrect grade");
break;
}

© ZPR-FER-UNIZG Intoduction to Programming 54


Deliberately omitting the break statement
▪ absence of break statement is a common logical mistake.
However, there are instances where the desired functionality is
achieved precisely by omitting the break
switch (grade) {
▪ example: if the grade case 2: /*FALLTHROUGH*/
belongs to the set { 2, 3, 4, case 3: /*FALLTHROUGH*/
5 } print exam passed, if case 4: /*FALLTHROUGH*/
case 5:
grade equals 1 print exam
printf("exam passed");
not passed, otherwise break;
print incorrect grade case 1:
▪ in this example, the order printf("exam not passed");
break;
of the labels is important. default:
What would happen if printf("incorrect grade");
label case 4: moves to break;
last place? }

© ZPR-FER-UNIZG Intoduction to Programming 55


Cascade selection or switch?
▪ every switch statement can be written in the form of a cascade
selection (the opposite is not true)
▪ the previous example can also be solved by cascading selection:
if (grade == 5 || grade == 4 ||
grade == 3 || grade == 2) {
printf("exam passed");
} else if (grade == 1) {
printf("exam not passed");
} else {
printf("incorrect grade");
}

© ZPR-FER-UNIZG Intoduction to Programming 56


Cascade selection or switch?
▪ why then does switch statement exist at all?
▪ the program is more understandable because it is immediately
apparent that it is a selection based on the comparison of individual
integer values
▪ executing the switch statement is (usually) faster than executing
an equivalent statement written in the form of cascading selection
▪ in cascade selection, logical expressions are succesively evaluated, until
they reach a logical expression that is evaluated as true
▪ switch statement jumps directly (machine instruction JUMP) to the
first statement after the appropriate label. This is precisely why the
expression in the label must be a constant integer expression: this way
the compiler can pre-specify the address of the machine instruction to
which it should "jump" directly, depending on the value of the
expression specified behind the keyword switch

© ZPR-FER-UNIZG Intoduction to Programming 57


Loops

© ZPR-FER-UNIZG Intoduction to Programming 58


Loops
▪ are intended to perform a particular program section (one or
more statements that make up the loop body) multiple times
▪ There are three types of loops used in C
▪ entry controlled loops, program loops with condition testing at the
beginning
▪ depending on the initial conditions, the loop body may not execute at
all
▪ exit controlled loops, program loops with condition testing at the
end
▪ the loop body will execute at least once
▪ count controlled loops, program loops with known number of
repetitions
▪ the number of repetitions can be calculated in advance and (in
principle) does not depend on the execution of the loop body

© ZPR-FER-UNIZG Intoduction to Programming 59


Entry controlled loop

© ZPR-FER-UNIZG Intoduction to Programming 60


Programming loops - motivation
▪ Example:
▪ print the first 20 natural numbers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

#include <stdio.h> ▪ (almost) the same job is repeated many


times, while the burden of repeating the
int main(void) { same job falls on the developer
printf("%d ", 1);
printf("%d ", 2);
▪ We cannot be satisfied with this solution -
printf("%d ", 3);
we want the computer to repeat the
printf("%d ", 4);
statements that a programmer otherwise
...
must write many times
printf("%d ", 19); ▪ the problem is that this solution does not
printf("%d ", 20); repeat exactly the same job because a
return 0; new constant is printed each time
}

© ZPR-FER-UNIZG Intoduction to Programming 61


Programming loops - motivation
▪ modify the previous program. Use a variable instead of a constant.
Now, the same set of statements will be executed many times
#include <stdio.h> ▪ we are not satisfied yet. Here again the
int main(void) {
programmer repeated exactly the
int n = 1;
same statements (as long as the value
of variable n was less than or equal to
printf("%d ", n); 20)
n = n + 1;
▪ a control program structure is required
printf("%d ", n); to allow the computer to repeat the
n = n + 1; same statements. Something like:
...
printf("%d ", n); int n = 1;
n = n + 1; repeat while n ≤ 20
return 0; printf("%d ", n);
} n = n + 1;

© ZPR-FER-UNIZG Intoduction to Programming 62


Entry controlled loop

Flowchart Pseudocode
...
while logical_expression

tijelo petlje
logical Yes statement_1
expr. statement_2
No statement_1 ...

loop body
...
statement_2

...

© ZPR-FER-UNIZG Intoduction to Programming 63


Entry controlled loop

C program - sintax
while (logical_expression)
statement; single statement!

What if the loop body contains more than one


statement?
Solution: Use a compound statement.

C program - example
...
n = 1;
while (n <= 20) {
printf("%d ", n);
n = n + 1;
}
...

© ZPR-FER-UNIZG Intoduction to Programming 64


Example
▪ Enter a nonnegative integer n. It is not necessary to check the
correctness of the number entered. Print the remainder of
consecutive divisions of the entered number by 2, and interrupt
the process when the result reaches 0
▪ the entered number may be 0. It may not be possible to print any
remainder of the split, or that the loop body will not print
▪ Examples of program execution
Enter a nonnegative integer > 11
You entered 11
Remainder = 1
Remainder = 1
Remainder = 0
Remainder = 1

Enter a nonnegative integer > 0


You entered 0

© ZPR-FER-UNIZG Intoduction to Programming 65


Solution
#include <stdio.h>
int main(void) {
int n, remainder;
printf("Enter a nonnegative integer > ");
scanf("%d", &n);
printf("You entered %d\n", n);
while (n != 0) {
remainder = n % 2;
printf("Remainder = %d\n", remainder);
n = n / 2;
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 66


Example
▪ Enter and sum integers until 0 is entered. Print the sum of the
entered numbers

#include <stdio.h>
int main(void) {
int n, sum = 0;
printf("Enter n > ");
scanf("%d", &n);
while (n != 0) {
sum = sum + n;
▪ the number should be entered at
printf("Enter n > ");
least once and then again in each
scanf("%d", &n);
step of the loop
}
▪ the condition-testing loop at the
printf("Sum = %d\n", sum);
beginning is not particularly suited to
return 0;
accomplish this task.
}

© ZPR-FER-UNIZG Intoduction to Programming 67


Example
▪ The repetition of part of the program code can be avoided by a
trick that will ensure at least one entry into the loop body

#include <stdio.h>
int main(void) {
int n = 1, sum = 0;
while (n != 0) {
printf("Enter n > ");
scanf("%d", &n);
sum = sum + n;
}
printf("Sum = %d\n", sum);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 68


Example
▪ ... or by using an auxiliary variable, a flag
#include <stdio.h>
int main(void) {
int n, sum = 0, firstPass = 1;
while (n != 0 || firstPass == 1) {
if (firstPass == 1) firstPass = 0;
printf("Enter n > ");
scanf("%d", &n);
sum = sum + n;
}
printf("Sum = %d\n", sum);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 69


Exit controlled loop

© ZPR-FER-UNIZG Intoduction to Programming 70


Exit controlled loop

Flowchart Pseudocode
...
repeat

loop body
statement_1 statement_1
loop body
statement_2
statement_2 ...
... while logical_expression
...
Yes
logical
expr.
No

© ZPR-FER-UNIZG Intoduction to Programming 71


Exit controlled loop

C program - sintax
do
statement; single statement!
while (logical_expression);

What if the loop body contains more than one statement?


Solution: use a compound statement

C program - example
...
n = 1;
do {
printf("%d ", n);
n = n + 1;
} while (n <= 20);
...

© ZPR-FER-UNIZG Intoduction to Programming 72


Example
▪ Enter and sum integers until 0 is entered. Print the sum of the
numbers entered.

#include <stdio.h>
int main(void) {
int n, sum = 0;
do {
printf("Enter n > ");
scanf("%d", &n);
sum = sum + n;
} while (n != 0);
printf("Sum = %d\n", sum);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 73


Example
▪ Enter a positive integer that specifies the upper limit of the sum
of numbers (no need to check the correctness of the entered
number). Then enter and sum the integers until their sum
exceeds the given upper limit of the sum. Then calculate and print
the arithmetic mean of the numbers entered.
▪ An example of executing a program

Enter the upper limit > 11


2
4
1
8
15 4 3.750000

© ZPR-FER-UNIZG Intoduction to Programming 74


Solution
#include <stdio.h>
int main(void) {
int counter = 0, sum = 0, n, gg;
float as;
printf("Enter the upper limit > ");
scanf("%d", &gg);
do {
scanf("%d", &n);
sum = sum + n; the loop body will execute at least once
counter = counter + 1; because this loop tests the repetition
} while (sum <= gg); condition at the end

as = 1.f * sum / counter; Multiplication by 1.f required for floating point result
printf("%d %d %f\n", sum, counter, as);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 75


Solution
#include <stdio.h>
int main(void) {
int counter = 0, sum = 0, n, gg;
float as;
printf("Enter the upper limit > ");
scanf("%d", &gg);
while (sum <= gg) { the loop body will be executed at least
scanf("%d", &n); once because in this case the condition for
sum = sum + n; performing the loop body is initially
counter = counter + 1; satisfied
}
as = 1.f * sum / counter; Multiplication by 1.f required for floating point result
printf("%d %d %f\n", sum, counter, as);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 76


Example
▪ Enter integers from interval [-100, 100]. Interrupt input if a
number not belonging to [-100, 100] is entered. Print the number
of entered positive values, the number of entered negative values
and the number of entered zeroes. Only consider numbers from
intervals [-50, 50].

© ZPR-FER-UNIZG Intoduction to Programming 77


Solution
#include <stdio.h>
int main(void) {
int n;
int countPositive = 0, countNegative = 0, countZeros = 0;
printf("Enter number > ");
do {
scanf("%d", &n);
if (n >= -50 && n <= 50) {
if (n == 0) countZeros = countZeros + 1;
else if (n > 0) countPositive = countPositive + 1;
else countNegative = countNegative + 1;
}
} while (n >= -100 && n <= 100);

printf("Positive %d, negative %d, zeros %d\n"


, countPositive, countNegative, countZeros);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 78


Example
▪ Enter 10 integers from the keyboard, determine and print the
largest number.
▪ An example of executing a program
Enter 10 integers >
3 -15 8 45 0 72 -99 72 0 11
The largest number is 72

© ZPR-FER-UNIZG Intoduction to Programming 79


Algorithm design
▪ When searching for the highest (or lowest) in some set of values,
the following algorithm is used:
▪ declare the first value as the largest (or the lowest) and store it in an
auxiliary variable that represents the current maximum (minimum)
▪ successively examine remaining values one at a time, and whenever
a value greater (lower) than the current maximum (minimum) is
found, update the current maximum (minimum) to that value
▪ after all values are examined, the highest (lowest) value will remain
in the auxiliary variable
▪ Example: 3 -15 8 45 0 72 -99 72 0 11
number 3 -15 8 45 0 72 -99 72 0 11
-15>3? 8>3? 45>8? 0>45? 72>45? -99>72? 72>72? 0>72? 11>72?

max 3 3 8 45 45 72 72 72 72 72

© ZPR-FER-UNIZG Intoduction to Programming 80


Solution (variant 1)
#include <stdio.h>
#define TOTAL_NUMBERS 10 at least 1
int main(void) {
int n, max;
printf("Enter %d integers >\n", TOTAL_NUMBERS);
scanf("%d", &n); first number
max = n;
while (step < TOTAL_NUMBERS) { remaining numbers
scanf("%d", &n);
if (n > max)
max = n;
}
printf("The largest number is %d", max);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 81


Solution (variant 2)
#include <stdio.h>
#define TOTAL_NUMBERS 10 at least 1
int main(void) {
int step = 0, n, max;
printf("Enter %d integers >\n", TOTAL_NUMBERS);
do {
step = step + 1;
scanf("%d", &n);
if (step == 1) first number
max = n;
else remaining numbers
if (n > max)
max = n;
} while (step < TOTAL_NUMBERS);
printf("The largest number is %d", max);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 82


Count controlled loop

© ZPR-FER-UNIZG Intoduction to Programming 83


Count controlled loop

C program - sintax
for (expression_1; expression _2; expression _3)
statement; single statement!

What if the loop body contains more than one


statement?
Solution: use compound statement

C program - example Print odd numbers from interval [1, 10]


... in this example, 9 is
int counter; fine too
for (counter = 1; counter <= 10; counter = counter
+ 2)
printf("%d\n", counter);
...

© ZPR-FER-UNIZG Intoduction to Programming 84


Count controlled loop

Flowchart C program - sintax


for (expression_1; expression_2; expression_3)
initialization statement;
expression_1

change of control
variable
expression_3

loop body
logical Yes
statement
expression_2

No

Obviously, if control variable can be changed in the loop body (which


is possible in C in contrast to some other languages), this is not
strictly a count controlled loop

© ZPR-FER-UNIZG Intoduction to Programming 85


Meaning of expressions
for (expression_1; expression_2; expression_3)
statement;

▪ expression_1 is an expression that will be executed only once,


before entering the first iteration of the loop. It is most commonly
used to initialize the counter.
▪ expression_2 is a logical expression. The loop body executes if
expression_2 is satisfied (true). If not, the loop breaks (continues
with the first statement behind the loop).
▪ expression_3 is performed after each iteration through the loop
body. It is most commonly used to increase / decrease the value of a
control variable / counter. After performing expression_3, the
condition in expression_2 is tested again
▪ Each of the expressions (expression_1, expression_2, expression_3)
can be omitted. If expression_2 is omitted, the result of
expression_2 is always considered true.
© ZPR-FER-UNIZG Intoduction to Programming 86
Count controlled loop

▪ each count controlled loop can be implemented as an entry


controlled loop. The main reasons for using a count controlled
loop are:
▪ hint to other developers that this is a loop for which the number of
times the loop body will be executed is known in advance
▪ more compact code
for (expression_1; expression_2; expression_3)
statement;

expression_1;
while (expression_2) {
statement;
expression_3;
}

© ZPR-FER-UNIZG Intoduction to Programming 87


Example
▪ Enter a positive integer n (no need to check for the correctness).
Then enter n integers, calculate and print their arithmetic mean
on the screen.
▪ What type of loop is best suited to accomplish this task?
▪ Example of program execution:

How many numbers do you want to enter? > 5


Enter 1. number > 3
Enter 2. number > -15
Enter 3. number > 8
Enter 4. number > 45
Enter 5. number > 7
Aritmetic mean is 9.600

© ZPR-FER-UNIZG Intoduction to Programming 88


Solution
#include <stdio.h>
int main(void) {
int n, counter, number, sum = 0;
float mean;
printf("How many numbers do you want to enter? > ");
scanf("%d", &n);
for (counter = 1; counter <= n; counter = counter + 1) {
printf("Enter %d. number > ", counter);
scanf("%d", &number);
sum = sum + number;
}
mean = 1.f * sum / n; for floating point division
printf("Arithmetic mean is %.3f\n", mean);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 89


Example
▪ Enter a positive integer n (no need to check for the correctness).
Then, print out all natural numbers divisible by 7, 13 or 19, which
are smaller than n, in order from larger to smaller
▪ What type of loop is best suited to accomplish this task?
▪ Example of program execution:

Enter n > 30


28
26
21
19
14
13
7

© ZPR-FER-UNIZG Intoduction to Programming 90


Solution
#include <stdio.h>
int main(void) {
int i, n;
printf("Enter n > ");
scanf("%d", &n);
for (i = n - 1; i > 0; i = i - 1) { here all curly brackets could be
if ((i % 7 == 0) || omitted
(i % 13 == 0) ||
(i % 19 == 0)) {
printf("%d\n", i);
}
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 91


Example
▪ Enter a nonnegative integer n (no need to check for correctness).
Print the first n members of the Fibonacci sequence.
▪ sequence definition:
a1 = a 2 = 1
ai = ai-1 + ai-2 za i ˃ 2

▪ Example of program execution:

Enter the number of members of the Fibonacci sequence > 15


1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610

© ZPR-FER-UNIZG Intoduction to Programming 92


Solution
#include <stdio.h>
int main(void) {
int n, i, a_i_minus2, a_i_minus1 = 1, a_i = 1;
printf("Enter the number of members of the Fibonacci sequence > ");
scanf("%d", &n);
for (i = 1; i <= n; i = i + 1) {
if (i > 2) {
a_i_minus2 = a_i_minus1;
a_i_minus1 = a_i;
a_i = a_i_minus1 + a_i_minus2;
}
if (i > 1) printf(", ");
printf("%d", a_i);
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 93


Example
▪ Print multiplication table up to 100, in 10 rows and 10 columns.
▪ Example of program execution:

1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100

© ZPR-FER-UNIZG Intoduction to Programming 94


Solution
#include <stdio.h>
int main(void) {
int row, col;
for (row = 1; row <= 10; row = row + 1) {
for (col = 1; col <= 10; col = col + 1) {
printf("%4d", row * col);
}
printf("\n");
}
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 95


Implementation of the same algorithm with different loops (1)

▪ The program section shown in the flowchart is to be implemented


with an entry controlled loop

i = m

i = m;
i = i + n while (i < t) {
Yes k = k + 2 * i;
i < t k = k + 2 * i i = i + n;
}
No

© ZPR-FER-UNIZG Intoduction to Programming 96


Implementation of the same algorithm with different loops (2)

▪ The program section shown in the flowchart is to be implemented


with a count controlled loop

i = m

i = i + n for (i = m; i < t; i = i + n) {
k = k + 2 * i;
Yes
}
i < t k = k + 2 * i

No

The advantage of this approach is that the initial counter initialization, condition testing
and counter modification are all in together in the code.

© ZPR-FER-UNIZG Intoduction to Programming 97


Implementation of the same algorithm with different loops (3)

▪ The program section shown in the flowchart is to be implemented


with an exit controlled loop

i = m
i = m;
if (i < t) {
i = i + n do {
Yes k = k + 2 * i;
i < t k = k + 2 * i i = i + n;
} while (i < t)
No }

The disadvantage of this loop is that additional checking is necessary before the first pass
through the loop body.

© ZPR-FER-UNIZG Intoduction to Programming 98


Example: selecting a loop type
▪ Enter a nonnegative integer n (no need to check for correctness).
Calculate and print n factorials
▪ Solve the task with
▪ entry controlled loop
▪ exit controlled loop
▪ count controlled loop
▪ Assess which type of loop is most appropriate
▪ Examples of program execution:

Enter n > 12


12! = 479001600
Enter n > 0
0! = 0

© ZPR-FER-UNIZG Intoduction to Programming 99


Solution (1)
▪ entry controlled loop

#include <stdio.h>
int main(void) {
int n, i, fact;
scanf("%d", &n);
fact = 1;
i = 2;
while (i <= n) {
fact = fact * i;
i = i + 1;
}
printf("%d! = %d", n, fact);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 100


Solution (2)
▪ exit controlled loop

#include <stdio.h>
int main(void) {
int n, i, fact;
scanf("%d", &n);
fact = 1;
i = 1; must not start with 2 because of the first pass
do {
fact = fact * i;
i = i + 1;
} while (i <= n);
printf("%d! = %d", n, fact);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 101


Solution (3)
▪ count controlled loop

#include <stdio.h>
int main(void) {
int n, i, fact;
scanf("%d", &n);
fact = 1;
for (i = 2; i <= n; i = i + 1) {
fact = fact * i;
}
printf("%d! = %d", n, fact);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 102


Unconditional jump statement
▪ Statements that unconditionally transfer control flow (further
execution of the program) to a specific place in the program
▪ break;
▪ momentarily interrupt switch statement (as seen before) or loop and
continue executing the first statement following the loop
▪ continue;
▪ momentarily interrupt the current loop iteration and continue
executing the program with the next loop iteration
▪ goto label;
▪ continue executing the program with the statement labeled with label
(labeled statement)
▪ return;
▪ statement to return flow control (and result, if applicable) to the calling
function
▪ it will be discussed in detail in the chapter about functions
© ZPR-FER-UNIZG Intoduction to Programming 103
break statement in a loop

▪ interrupts the execution of the lowest-level loop in whose body it


is specified and directs the further execution of the program to
the first statement behind the interrupted loop
...
for (...) {
...;
while (...) { lowest-level loop where break statement is specified
...;
if (...) {
break;
}
do {
...
} while (...);
}
...
}
...
© ZPR-FER-UNIZG Intoduction to Programming 104
Example
Enter two natural numbers a i b three times in a row and print their
sum. If either of the two numbers you entered is not natural, end
the program.

© ZPR-FER-UNIZG Intoduction to Programming 105


Example (solution with break)
#include <stdio.h>
int main(void) {
int i, a, b;
for (i = 1; i <= 3; i = i + 1) {
printf("%d. sumation\n", i);
printf(" Enter the first natural number > ");
scanf("%d", &a);
if (a <= 0) break;
printf(" Enter the second natural number > ");
scanf("%d", &b);
if (b <= 0) break;
printf("%d + %d = %d\n", a, b, a + b);
}
printf("End.\n");
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 106


Example (solution without break)
#include <stdio.h>
int main(void) {
int a, b, i = 0;
do {
i = i + 1;
printf("%d. sumation\n", i);
printf(" Enter the first natural number > ");
scanf("%d", &a);
if (a > 0) {
printf(" Enter the second natural number > ");
scanf("%d", &b);
if (b > 0) {
printf("%d + %d = %d\n", a, b, a + b);
}
}
} while (i < 3 && a > 0 && b > 0);
printf("End.\n");
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 107


Example (very similar to previous)
Enter two natural numbers a i b three times in a row and print their
sum. If either of the two numbers you entered is not natural, enter
the next pair.

© ZPR-FER-UNIZG Intoduction to Programming 108


statement continue
▪ continue (in contrast to break) is used only in loops
▪ similar to break, refers to the lowest level loop in whose body it
is specified
▪ inside while or do-while
▪ directs program execution to test the condition. If the condition is
satisfied, the next iteration is performed, otherwise the loop breaks
▪ inside for
▪ directs the execution of the program to change the value of the control
variable ("expression_3") and then to test the condition
("expression_2"). If the condition is satisfied, the next iteration is
performed, otherwise the loop breaks

© ZPR-FER-UNIZG Intoduction to Programming 109


Example (solution with continue)
#include <stdio.h>
int main(void) {
int i, a, b;
for (i = 1; i <= 3; i = i + 1) {
printf("%d. sumation\n", i);
printf(" Enter the first natural number > ");
scanf("%d", &a);
if (a <= 0) continue;
printf(" Enter the second natural number > ");
scanf("%d", &b);
if (b <= 0) continue;
printf("%d + %d = %d\n", a, b, a + b);
}
printf("End.\n");
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 110


Example (solution without continue)
#include <stdio.h>
int main(void) {
int i, a, b;
for (i = 1; i <= 3; i = i + 1) {
printf("%d. sumation\n", i);
printf(" Enter the first natural number > ");
scanf("%d", &a);
if (a > 0) {
printf(" Enter the second natural number > ");
scanf("%d", &b);
if (b > 0) {
printf("%d + %d = %d\n", a, b, a + b);
}
}
}
printf("End.\n");
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 111


Example: unnecessary use of break i continue
▪ write a program that will enter integers from the keyboard and
proceed as follows
▪ if the entered number is less than zero, print the message "Invalid
number" and stop entering the numbers
▪ if the entered number is zero, print the entered number and stop
entering the numbers
▪ if the entered number is greater than 100, it should be ignored,
print the message "Neglecting the number" and continue entering
▪ otherwise (if none of the preceding conditions are satisfied) print
the entered number and continue entering

© ZPR-FER-UNIZG Intoduction to Programming 112


Solution (bad) with break and continue
#include <stdio.h>
int main(void) {
int n;
do {
printf("Enter a number > ");
scanf("%d", &n);
if (n < 0) {
printf("Invalid number\n");
break;
}
if (n > 100) {
printf("Neglecting the number\n");
continue;
}
printf("Entered number is : %d\n", n);
} while (n != 0);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 113


Solution (good) with break and continue
#include <stdio.h>
int main(void) {
int n;
do {
printf("Enter a number > ");
scanf("%d", &n);
if (n > 100)
printf("Neglecting the number\n");
else if (n >= 0)
printf("Entered number is: %d\n", n);
else
printf("Invalid number\n");
} while (n > 0);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 114


goto statement
C program - sintax
goto label;
...
label: statement;
...

▪ labeled statement can be anywhere within the function


▪ statement goto label; directs the program control flow to the
statement labeled label
▪ goto statement and the associated labeled statement must reside
in the same function
▪ the same label can be targeted by multiple goto statements
▪ the labeled statement can be located before or beyond the goto
statement

© ZPR-FER-UNIZG Intoduction to Programming 115


goto statement

▪ a program code that uses (almost always unnecessarily)


goto statement is considered difficult to follow (derogatory:
spaghetti code) and therefore difficult to maintain
for (i = 1; i <= 10; i = i + 1) { i = 1;
scanf("%d", &a); repeat:
if (a < 0) if (i > 10) goto end;
printf("less than 0\n"); i = i + 1;
else if (a == 0) scanf("%d", &a);
printf("equal to 0\n"); if (a < 0) goto printLess;
else if (a == 0) goto printEqual;
printf("greater than 0\n"); printf("greater than 0\n");
} goto repeat;
printLess:
printf("less than 0\n");
In exams and exercise within this course,
goto repeat;
goto statement is forbidden. Any solution
printEqual:
that contains a goto statement will be printf("equal to 0\n");
considered completely faulty. goto repeat;
end:;

© ZPR-FER-UNIZG Intoduction to Programming 116


goto statement
▪ a rare case of justified use of a goto statement
▪ e.g., for some reason (condition4 here) it is necessary to terminate
the deeply nested loop and continue executing statements after the
outer loop
for (...; condition1; ...) {
while (condition2) {
do {
...
if (condition4) exit all loops;
...
} while (condition3);
continuation3;
}
continuation2;
}
continuation1;

© ZPR-FER-UNIZG Intoduction to Programming 117


Rješenje s naredbom goto
for (...; condition1; ...) {
while (condition2) {
do {
...
if (condition4) goto out;
...
} while (condition3);
continuation3;
}
continuation2;
}
out:
continuation1;

© ZPR-FER-UNIZG Intoduction to Programming 118


Solution without a goto statement
▪ it can be solved without a goto, but the solution is less elegant and less
efficient due to the introduction of a flag and additional tests
int finished = 0;
for (...; condition1; ...) {
while (condition2) {
do {
...
if (condition4) {
gotovo = 1;
break;
}
...
} while (condition3);
if (finished == 1) break;
continuation3;
}
if (finished == 1) break;
continuation2;
}
continuation1;
© ZPR-FER-UNIZG Intoduction to Programming 119
Structured programming
▪ a programming paradigm in which the following elements are
allowed to control flow:
▪ selection
▪ iteration (loops)
▪ subroutine call (functions)
▪ avoid:
▪ statements to break or continue loops (break, continue)
▪ using more than one return statement in a single function
▪ not allowed:
▪ using the goto statement

© ZPR-FER-UNIZG Intoduction to Programming 120


Structured programming
▪ disciplined programming
▪ programs that are not written according to structured
programming rules are the result of the ignorance or laziness of
the programmer (except in the aforementioned exceptional
cases)

Any fool can write code that a computer can understand. Good programmers
write code that humans can understand.
M. Fowler, K. Beck, J. Brant, W. Opdyke, D. Roberts: Refactoring: Improving the Design of Existing
Code. Addison-Wesley, 1999.

© ZPR-FER-UNIZG Intoduction to Programming 121


Example
... structured ... nonstructured
for (i = 1; i <= 10; i = i + 1) i = 1;
if (i % 2 == 0) { repeat:
printf("%d is even\n", i); if (i % 2 == 0)
else goto printEven;
printf("%d is odd\n", i); printf("%d is odd\n", i);
... i = i + 1;
goto repeat;
printEven :
printf("%d is even\n", i);
i = i + 1;
goto repeat;
...

© ZPR-FER-UNIZG Intoduction to Programming 122


Example
▪ Enter a natural number (no need to check for correctness). Print
whether the entered number is a prime number.
▪ Examples of program execution

Enter a natural number > 12


12 is not a prime number

Enter a natural number > 13


13 is a prime number

Enter a natural number > 1


1 is not a prime number

© ZPR-FER-UNIZG Intoduction to Programming 123


Solution using break
#include <stdio.h>
int main(void) {
int i, n, divisible = 0; // hypothesis: not divisible
printf("Enter a natural number > ");
scanf("%d", &n);
for (i = 2; i <= n - 1; i = i + 1) {
if (n % i == 0) {
divisible = 1; // hypothesis was wrong
break; // no further testing is required
}
}
if (divisible == 1 || n == 1) // number 1 is a special case
printf("%d is not a prime number\n", n);
else
printf("%d is a prime number\n", n);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 124


Alternative solution using break
#include <stdio.h>
int main(void) {
int i, n;
printf(" Enter a natural number > ");
scanf("%d", &n);
for (i = 2; i <= n - 1; i = i + 1) {
if (n % i == 0) {
break; // no further testing is required
}
}
if (i < n || n == 1) // break occured
printf("%d is not a prime number\n", n);
else // all loop steps finished
printf("%d is a prime number\n", n);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 125


Solution without break
#include <stdio.h>
int main(void) {
int i, n, divisible = 0; // hypothesis: not divisible
printf(" Enter a natural number > ");
scanf("%d", &n);
i = 2;
while (i <= n - 1 && divisible == 0) {
if (n % i == 0) {
divisible = 1; // hypothesis was wrong
}
i = i + 1;
}
if (divisible == 1 || n == 1) // number 1 is a special case
printf("%d is not a prime number \n", n);
else
printf("%d is a prime number \n", n);
return 0;
}

© ZPR-FER-UNIZG Intoduction to Programming 126


Infinite loop
▪ a series of statements that will be repeated infinitely, until an
externally imposed program interruption (e.g., a signal from the
operating system or shutting down the computer)
▪ most often it is the result of a logical error
▪ except in special cases, in which the infinite loop is deliberately used
because of the nature of the problem to be solved
▪ Example: a very simplified pseudo-code of a program that controls the
room temperature
repeat
read the temperature
if lower than minimum
turn on the heater
if higher than maximum
turn off the heater

© ZPR-FER-UNIZG Intoduction to Programming 127


Infinite loop
▪ examples of infinite loops resulting from a logical error
for (i = 1; i <= 10; i == i + 1) {
printf("%d\n", i);
}

i = 1;
while (i <= 10) {
printf("%d\n", i);
}

i = 1;
while (i <= 10); {
printf("%d\n", i);
i = i + 1;
}

© ZPR-FER-UNIZG Intoduction to Programming 128


Pseudo-infinite loop with break statement
▪ infinite by at first glance (repeat condition is always true), but
with break(s) under certain condition(s)
do {
scanf("%d", &n);
if (n > 0)
counter = counter + 1;
} while (n > 0);

while (1 == 1) { // while (1) for (;;) {


scanf("%d", &n); scanf("%d", &n);
if (n > 0) if (n > 0)
counter = counter + 1; counter = counter + 1;
else else
break; break;
} }

© ZPR-FER-UNIZG Intoduction to Programming 129


Example: Collatz conjecture
▪ Programmatically illustrate Collatz's conjecture: for every positive
integer n, after a finite number of subsequent operations
▪ if n is even, n = n / 2
▪ if n is odd, n = n * 3 + 1
the sequence will always reach n = 1
▪ Enter integers, and for every entered value, print intermediate
values and number of steps required to obtain 1. Finish when n is
not positive, e.g.
Enter a positive integer, 0 to finish > 15
46 23 70 35 106 53 160 80 40 20 10 5 16 8 4 2 1
Steps: 17
Enter a positive integer, 0 to finish > 6
3 10 5 16 8 4 2 1
Steps: 8
Enter a positive integer, 0 to finish > 0

▪ https://en.wikipedia.org/wiki/Collatz_conjecture
© ZPR-FER-UNIZG Intoduction to Programming 130
Solution
#include <stdio.h>
int main(void) {
int n, steps;
while (1) {
printf(" Enter a positive integer, 0 to finish > ");
scanf("%d", &n);
if (n <= 0) break;
steps = 0;
while (n > 1) {
steps = steps + 1;
if (n % 2 == 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
printf("%d ", n);
}
printf("\nSteps: %d\n", steps);
}
}
© ZPR-FER-UNIZG Intoduction to Programming 131
Introduction to Programming - Lectures

4. Aggregate data types

© ZPR-FER-UNIZG Introduction to Programming 1


Arrays - motivation
▪ enter 10 integers from the keyboard, print their arithmetic mean
and and all values greater than the arithmetic mean
▪ an example of executing a program

5 15 1 2 3 -4 25 6 8 7
mean = 6.800000
15
25
8
7

▪ obviously, all 10 values will need to be stored in variables. Calculate


the average, and then print the values of the variables that satisfy
the condition

© ZPR-FER-UNIZG Introduction to Programming 2


Solution (bad)
#include <stdio.h>
int main(void) { 10 x almost the same code
int b1, b2, b3, b4, b5, b6, b7, b8, b9, b10;
float mean;
scanf("%d %d %d %d %d %d %d %d %d %d"
, &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &b9, &b10);
sredina = (b1 + b2 + b3 + b4 + b5 + b6 + b7 + b8 + b9 + b10) / 10.f;
printf("mean = %f\n", mean);
if (b1 > mean) printf("%d\n", b1);
if (b2 > mean) printf("%d\n", b2);
...
if (b9 > mean) printf("%d\n", b9);
if (b10 > mean) printf("%d\n", b10);
return 0;
}

▪ Imagine now the same task, but with (only) 1000 values
© ZPR-FER-UNIZG Introduction to Programming 3
Matematical sequence
▪ A series of numbers that share a common name and whose
members are identified by an index: a0, a1, a2, ...
▪ If such a sequence could be used in a program, the previous task
would be much simpler:
sum := 0
for i = 1 to 10
input(bi)
sum := sum + bi
mean := sum / 10
for i = 1 to 10
if bi > mean
output(bi)

© ZPR-FER-UNIZG Introduction to Programming 4


Matematical sequence
▪ Much larger problems could be solved without difficulty, which
would be extremely tedious to solve without using a sequence:
for example, loading n numbers and printing those numbers
larger than their arithmetic mean
input(n)
sum := 0
for i = 1 to n
input (bi)
sum := sum + bi
mean := sum / n
for i = 1 to n
if bi > mean
output(bi)

© ZPR-FER-UNIZG Introduction to Programming 5


Aggregate data types

Arrays
Structures

© ZPR-FER-UNIZG Introduction to Programming 6


Aggregate data types
▪ So far only primitive data types have been used: int and float
▪ only a single data item can be stored in a variable of primitive type
▪ Single variable ↔ Single value
▪ scalar data type, scalar variable, scalar data
▪ data aggregate includes multiple scalar data and / or multiple
aggregate data, combined under the same name
▪ array
▪ structure, record
▪ benefits of using aggregate data
▪ simpler procedures over data sets
▪ the logical connection of data is emphasized

© ZPR-FER-UNIZG Introduction to Programming 7


Arrays

One-dimensional arrays

© ZPR-FER-UNIZG Introduction to Programming 8


Array
▪ Primitive data types
▪ single variable ↔ single value float x;
x = 3.14f;
▪ the value of the variable is accessed by
printf("%f", x);
specifying the variable name
▪ a varijable of primitive type is modifiable x 3.14
lvalue
▪ Array is a composite data type that
contains multiple members of the same float y[4];
type y[1] = 2.71f;
▪ single variable ↔ multiple values printf("%f", y[1]);
▪ individual values (members) are
accessed using the name and index y ? 2.71 ? ?
▪ variable name is non-modifiable lvalue y[0] y[1] y[2] y[3]

▪ name plus index is, however, a


modifiable lvalue
© ZPR-FER-UNIZG Introduction to Programming 9
Array definition
▪ When defining an array, it is necessary to specify
▪ variable name: is defined in the same way as a variable name for
simple data types
▪ data type for array members (int, float, ...)
▪ the size of the array expressed in the number of array members
▪ array of known constant dimensions
▪ the dimension of the field is known at compile time
▪ in square brackets, a constant integer expression is given
▪ variable-length array, VLA
▪ the size of the field is determined at the time when the array
definition statement is executed (but does not change thereafter)
▪ in square brackets, an integer expression is given (may contain
variables) whose result must be greater than zero

© ZPR-FER-UNIZG Introduction to Programming 10


Example
#define VECTOR_SIZE 50
#define MEMBER_COUNT (5 * 10)
...
// definitions of arrays of known constant dimensions
//float vector[50];
float vector[VECTOR_SIZE]; // better than 50

//int numbers[5 * 10];


int numbers[MEMBER_COUNT]; // better than 5 * 10

// definitions of variable length arrays


int n;
scanf("%d", &n); // ensure n > 0 !
float temperatures[n];
int pressures[2 * n];

© ZPR-FER-UNIZG Introduction to Programming 11


Accessing array members
▪ The members (elements) of the array are accessed using an index
▪ index can be an integer expression (composed of constants,
variables, operators, functions) whose result must be a nonnegative
integer from the interval
[0, numberOfArrayElements - 1] (index of first element is 0)
▪ The C compiler can only detect the wrong use of the index data type
(eg float instead of int)
▪ compliance with the rules on the permissible index limits is the sole
responsibility of the developer
▪ the result of using incorrect indexes is undefined: an incorrect value
(logical error) will be retrieved or set. Additionally, a run-time error and
program interruption can occur.

© ZPR-FER-UNIZG Introduction to Programming 12


Example
int i = 2, m, numbers[10];
float x = 5.0f;
numbers[0] = 0;
numbers[1] = 10;
...
numbers[i * 4] = 80;
numbers[i * 4 + 1] = 90;

numbers[x] = 1; compiler error


...
m = numbers[10]; undefined result (garbage value). Logical error.
numbers[-1] = 15; 15 is stored to a wrong memory location,
which can cause a logical or runtime error

© ZPR-FER-UNIZG Introduction to Programming 13


Example
▪ Enter 10 integers from the keyboard, print their arithmetic mean
and numbers greater than the arithmetic mean
#include <stdio.h>
#define DIMENSION 10
int main(void) {
int numbers[DIMENSION], sum = 0, i;
float mean;
for (i = 0; i < DIMENSION; i = i + 1) {
scanf("%d", &numbers[i]);
sum = sum + numbers[i];
}
mean = 1.f * sum / DIMENSION;
printf("mean = %f\n", sredina);
for (i = 0; i < DIMENSION; i = i + 1) {
if (numbers[i] > mean) {
printf("%d\n", numbers[i]);
}
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 14


Example of VLA
▪ Enter n, then n integers from the keyboard, print their arithmetic
mean and numbers greater than the arithmetic mean
...
int n, sum = 0, i;
float mean;
scanf("%d", &n);
int numbers[n];
for (i = 0; i < n; i = i + 1) {
scanf("%d", &numbers[i]);
sum = sum + numbers[i];
}
mean = 1.f * sum / n;
printf("mean = %f\n", mean);
for (i = 0; i < n; i = i + 1) {
if (numbers[i] > mean) {
printf("%d\n", numbers[i]);
}
}
...

© ZPR-FER-UNIZG Introduction to Programming 15


Definition of array with initialization
▪ Array members can be initialized at the time of definition
▪ not applicable for VLA arrays!
▪ without initialization, array members contain undefined values
int array[5]; array ? ? ? ? ?

▪ initial values can be listed in the initializer


int array[5] = {1, 3, 5, 7, 9}; array 1 3 5 7 9

▪ if too few values are listed, the other members are set to 0
int array[5] = {1, 3, 5}; array 1 3 5 0 0

▪ … which can be used to initialize all members to zero


int array[5] = {0}; array 0 0 0 0 0

© ZPR-FER-UNIZG Introduction to Programming 16


Definition of array with initialization
▪ specific members can be initialized using designated initializer
int array[] = {1, [4] = 2}; array 1 0 0 0 2

▪ automatic array size determination based on initializer


int array[] = {1, 3, 5, 7, 9}; array 1 3 5 7 9

▪ the initializer must have at least one value


int array[5] = {}; Compiler error

▪ initializer must not contain too many values


int array[5] = {1, 3, 5, 7, 9, 11}; Compiler error

© ZPR-FER-UNIZG Introduction to Programming 17


Initialization is not assignment!

▪ an array type variable must not be on the left side of the


assignment expression because the array is not a modifiable lvalue
▪ incorrect way to copy contents of array source to array target:
int source[4] = {1, 2, 3, 4}; initialization of source. O.K.
int target[4];
target = source; compile error!

▪ correct way to copy contents of array source to array target:


int source[4] = {1, 2, 3, 4}; initialization of source. O.K.
int target[4];
int i;
for (i = 0; i < 4; i = i + 1) {
target[i] = source[i];
}
© ZPR-FER-UNIZG Introduction to Programming 18
Example
▪ Enter integer n from the keyboard representing the number of
array members. Repeat entering n until the number of array
members is correct. Then enter n floating point array members
and print them in reverse order

▪ an example of executing a program


Enter number of array members > 0
Enter number of array members > -2
Enter number of array members > 4
Enter 1. member > 9.1
Enter 2. member > 101.55
Enter 3. member > -476.3333
Enter 4. member > 5
5.0, -476.3, 101.6, 9.1

© ZPR-FER-UNIZG Introduction to Programming 19


Solution (Part 1)
#include <stdio.h>
int main(void) {
int n; // array size
int i; // loop control variable
/* repeat entering the array size until it is correct */
do {
printf("Enter number of array members > ");
scanf("%d", &n);
} while (n < 1);
/* definition of VLA array */
float array[n];

© ZPR-FER-UNIZG Introduction to Programming 20


Solution (Part 2)
/* entering of the array members */
for (i = 0; i < n; i = i + 1) {
printf("Enter %d. member > ", i + 1);
scanf("%f", &array[i]);
}
/* printing the members in reverse order */
for (i = n - 1; i >= 0; i = i - 1) {
if (i < n - 1) { // print a comma before each but the first
printf(", ");
}
printf("%.1f", array[i]);
}
printf("\n");
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 21


Example
▪ Enter integers from interval [0, 9]. Interrupt input when a number
outside the default interval is entered. Then print how many
times each number this interval has been entered, printing only
those numbers that have been entered at least once.

Enter number from interval [0, 9] > 1


Enter number from interval [0, 9] > 5
Enter number from interval [0, 9] > 7
Enter number from interval [0, 9] > 5
Enter number from interval [0, 9] > 0
Enter number from interval [0, 9] > 5
Enter number from interval [0, 9] > 7
Enter number from interval [0, 9] > 10

Number 0 occurred 1 times
Number 1 occurred 1 times
Number 5 occurred 3 times
Number 7 occurred 2 times

© ZPR-FER-UNIZG Introduction to Programming 22


Example
▪ Determining the frequency of occurrence of numbers
▪ one counter is required for each number
▪ initially all the counters are set to zero
▪ whenever a number is entered, the corresponding counter is
increased by 1
cnt 0 0 0 0 0 0 0 0 0 0
cnt[0] cnt[1] cnt[2] cnt[3] cnt[4] cnt[5] cnt[6] cnt[7] cnt[8] cnt[9]

Enter number from interval [0, 9] > 1 → cnt[1] = cnt[1] + 1


Enter number from interval [0, 9] > 5 → cnt[5] = cnt[5] + 1
Enter number from interval [0, 9] > 7 → cnt[7] = cnt[7] + 1
Enter number from interval [0, 9] > 5 → cnt[5] = cnt[5] + 1
Enter number from interval [0, 9] > 0 → cnt[0] = cnt[0] + 1
Enter number from interval [0, 9] > 5 → cnt[5] = cnt[5] + 1
Enter number from interval [0, 9] > 7 → cnt[7] = cnt[7] + 1

cnt 1 1 0 0 0 3 0 2 0 0
cnt[0] cnt[1] cnt[2] cnt[3] cnt[4] cnt[5] cnt[6] cnt[7] cnt[8] cnt[9]

© ZPR-FER-UNIZG Introduction to Programming 23


Solution (Part 1)
#include <stdio.h>
#define L_BOUND 0 // interval lower bound
#define U_BOUND 9 // interval upper bound
int main(void) {
int number;
int cnt[U_BOUND - L_BOUND + 1] = { 0 }; // initialization to 0
/* enter numbers and increment corresponding counters */
do {
printf("Enter number from interval [%d, %d] > ", L_BOUND, U_BOUND);
scanf("%d", &number);
if (number >= L_BOUND && number <= U_BOUND) {
cnt[number] = cnt[number] + 1;
}
} while (number >= L_BOUND && number <= U_BOUND);

© ZPR-FER-UNIZG Introduction to Programming 24


Solution (Part 2)
printf("\n");
/* print counters larger than zero */
int i;
for (i = L_BOUND; i <= U_BOUND; i = i + 1) {
if (cnt[i] > 0) {
printf("Number %d occurred %d times\n", i, cnt[i]);
}
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 25


Example – a variant with different interval
▪ Enter integers from interval [1000005, 1000014]. Interrupt input
when a number outside the specified interval is entered. Then print
how many times each number from a given interval has been
entered, printing only those numbers that have been entered at
least once.

Enter number from interval [1000005, 1000014] > 1000008


Enter number from interval [1000005, 1000014] > 1000012
Enter number from interval [1000005, 1000014] > 1000012
Enter number from interval [1000005, 1000014] > 1000008
Enter number from interval [1000005, 1000014] > 1000012
Enter number from interval [1000005, 1000014] > 1000014
Enter number from interval [1000005, 1000014] > 1000000

Number 1000008 occurred 2 times
Number 1000012 occurred 3 times
Number 1000014 occurred 1 times

© ZPR-FER-UNIZG Introduction to Programming 26


Solution (Part 1)
#include <stdio.h>
#define L_BOUND 1000005 // interval lower bound
#define U_BOUND 1000014 // interval upper bound
int main(void) {
int number;
int cnt[U_BOUND - L_BOUND + 1] = { 0 }; // initalization to 0
/* entering the numbers and incrementing the corresponding counters */
do {
printf("Enter number from interval [%d, %d] > ", L_BOUND, U_BOUND);
scanf("%d", &number);
if (number >= L_BOUND && number <= U_BOUND) {
cnt[number - L_BOUND] = cnt[number - L_BOUND] + 1;
}
} while (number >= L_BOUND && number <= U_BOUND);

© ZPR-FER-UNIZG Introduction to Programming 27


Solution (Part 2)
printf("\n");
/* print counters larger than zero */
int i;
for (i = L_BOUND; i <= U_BOUND; i = i + 1) {
if (cnt[i - L_BOUND] > 0) {
printf("Number %d occurred %d times\n", i, cnt[i - L_BOUND]);
}
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 28


Example
▪ Enter n, the size of an array (no need to control the correctness)
and Enter n members of the integer array. Print the position
(index) and value of the smallest member of the array. If more
than one array member has the same lowest value, print the
position of the first such member.
Enter array size > 5
Enter array members > 7 5 4 6 4

Value 4 at position 2

© ZPR-FER-UNIZG Introduction to Programming 29


Solution
#include <stdio.h>
int main(void) {
int n, i; // array size, loop control variable
printf("Enter array size > ");
scanf("%d", &n);
int array[n];
printf("Enter array members > ");
for (i = 0; i < n; i = i + 1) {
scanf("%d", &array[i]);
}
int min_ind = 0; // assumption: first member is, so far, the smallest
for (i = 1; i < n; i = i + 1) {
if (array[i] < array[min_ind]) min_ind = i; // change the assumption
}
printf("\nValue %d at position %d\n", array[min_ind], min_ind);
return 0;
}
© ZPR-FER-UNIZG Introduction to Programming 30
Example
▪ Enter n, the size of an array (no need to control the correctness) and
then enter n members of the integer array. Sort array members
from smaller to larger. Print the contents of the sorted field.

Enter array size > 5


Enter array members > 9 4 7 2 5

2 4 5 7 9

© ZPR-FER-UNIZG Introduction to Programming 31


Solution
▪ Array sorting
▪ Here, one of the simplest and least efficient sorting algorithms will
be used: selection sort
▪ for each i, 0 ≤ i ≤ n-2
▪ find index ind_min of the smallest array[j], i < j ≤ n-1
▪ if array[ind_min] < array[i], swap array[i] and array[ind_min]

i =0 array 9 4 7 2 6 5 ind_min = 3, array[ind_min] < array[i] → swap

i =1 array 2 4 7 9 6 5 ind_min = 5, array[ind_min] ≥ array[i]

i =2 array 2 4 7 9 6 5 ind_min = 5, array[ind_min] < array[i] → swap

i =3 array 2 4 5 9 6 7 ind_min = 4, array[ind_min] < array[i] → swap

i =4 array 2 4 5 6 9 7 ind_min = 5, array[ind_min] < array[i] → swap

end array 2 4 5 6 7 9

© ZPR-FER-UNIZG Introduction to Programming 32


Array
/* the usual loading code to enter dana is omitted */
for (i = 0; i < n - 1; i = i + 1) {
/* find the indeks of the smallest from array[i+1] ... array[n-1] */
ind_min = i + 1;
for (j = i + 2; j < n; j = j + 1) {
if (array[j] < array[ind_min]) ind_min = j;
}
/* ind_min contains index of the smallest member */
if (array[ind_min] < array[i]) {
/* swap array[i] and array[ind_min] */
aux = array[i];
array[i] = array[ind_min];
array[ind_min] = aux;
}
}
/* the usual code to print is omitted */

© ZPR-FER-UNIZG Introduction to Programming 33


Arrays

Multidimensional arrays

© ZPR-FER-UNIZG Introduction to Programming 34


▪ one-dimensional array (vector)
int a[4]; a a[0] a[1] a[2] a[3]

▪ An array can have multiple dimensions


▪ two dimensions (matrix, table)
▪ e.g. matrix with 3 rows i 5 columns

int b[3][5]; b b[0][0] b[0][1] b[0][2] b[0][3] b[0][4]


b[1][0] b[1][1] b[1][2] b[1][3] b[1][4]
b[2][0] b[2][1] b[2][2] b[2][3] b[2][4]

© ZPR-FER-UNIZG Introduction to Programming 35


Multidimensional array
▪ Array can have multpile dimensions
▪ three dimensions int c[4][3][5];

c[3][0][0] c[3][0][1] c[3][0][2] c[3][0][3] c[3][0][4]


c[2][0][0] c[2][0][1]
c[3][1][0] c[2][0][2]
c[3][1][1] c[2][0][3]
c[3][1][2] c[2][0][4]
c[3][1][3] c[3][1][4]
c[1][0][0] c[1][0][1]
c[2][1][0] c[1][0][2]
c[2][1][1]
c[3][2][0] c[1][0][3]
c[2][1][2]
c[3][2][1] c[1][0][4]
c[2][1][3]
c[3][2][2] c[2][1][4]
c[3][2][3] c[3][2][4]
c c[0][0][0] c[0][0][1]
c[1][1][0] c[0][0][2]
c[1][1][1]
c[2][2][0] c[0][0][3]
c[1][1][2]
c[2][2][1] c[0][0][4]
c[1][1][3]
c[2][2][2] c[1][1][4]
c[2][2][3] c[2][2][4]
c[0][1][0] c[0][1][1]
c[1][2][0] c[0][1][2]
c[1][2][1] c[0][1][3]
c[1][2][2] c[0][1][4]
c[1][2][3] c[1][2][4]
c[0][2][0] c[0][2][1] c[0][2][2] c[0][2][3] c[0][2][4]

▪ number of dimensions is not limited, e.g.


int d[4][4][4][4][4][4][4][4][4][4][4][4][4][4];

▪ caution: this array has 414 memers. Memory usage?


© ZPR-FER-UNIZG Introduction to Programming 36
Definition of array with initialization
▪ Array members can be initialized in definition
▪ not applicable for VLA!
▪ without initialization, array members contain undefined values
int array[3][4]; array ? ? ? ?
? ? ? ?
? ? ? ?

▪ initial values can be listed in the initializer


int array[3][4] = {1, 2, 3, 4, 5, 6, array 1 2 3 4
7, 8, 9, 10, 11, 12}; 5 6 7 8
9 10 11 12

© ZPR-FER-UNIZG Introduction to Programming 37


Definition of array with initialization
▪ Rows will be identified more easily if the following initializer format
is used
int array[3][4] = {{1, 2, 3, 4}, array 1 2 3 4
{5, 6, 7, 8}, 5 6 7 8
{9, 10, 11, 12}};
9 10 11 12
▪ if too few values are listed, the other members are set to zero
int array[3][4] = {{1, 2}, array 1 2 0 0
{5, 6, 7}}; 5 6 7 0
0 0 0 0
▪ specific members can be initialized using designated initializer
▪ array[3][4]
int postaviti = {{1, 2}, array 1 2 0 0
{[2] = 7}, 0 0 7 0
[2][1] = 11};
0 11 0 0
© ZPR-FER-UNIZG Introduction to Programming 38
Definition of array with initialization
▪ automatic determination of the size is only possible for the first
dimension (all others must be specified)
int array[][4] = {{1, 2, 3, 4}, array 1 2 3 4
{5, 6, 7}, 5 6 7 0
{9, 10}};
9 10 0 0
▪ otherwise, the compiler reports an error
int array[][] = {{1, 2, 3, 4}, Compiler error
{5, 6, 7, 8},
{9, 10, 11, 12}};

▪ the initializer must not list too many values


int array[2][3] = {{1, 2, 3, 4}, Compiler error
{5, 6, 7, 8},
{9, 10, 11, 12}};

© ZPR-FER-UNIZG Introduction to Programming 39


Example
▪ Enter the members of a 2-dimensional floating point array of 4 rows
and 5 columns (colloquially: 4 x 5 dimension), row by row. Print the
contents of the array in a table format

Enter array members >


-43.1 15 122.21 0.15 11
19.7 0.9761 54 33.7888 1
0 0 4.45 4.4 -45
28.1 28 6.721 -1 2

-43.10 15.00 122.21 0.15 11.00
19.70 0.98 54.00 33.79 1.00
0.00 0.00 4.45 4.40 -45.00
28.10 28.00 6.72 -1.00 2.00

© ZPR-FER-UNIZG Introduction to Programming 40


Solution (Part 1)
#include <stdio.h>
#define ROWS 4 // number of rows
#define COLS 5 // number of columns
int main(void) {
int row, col;
float array[ROWS][COLS];
/* Enter array members*/
printf("Enter array members >\n");
for (row = 0; row < ROWS; row = row + 1) {
for (col = 0; col < COLS; col = col + 1) {
scanf("%f", &array[row][col]);
}
}
/* printing a blank line after input */
printf("\n");

© ZPR-FER-UNIZG Introduction to Programming 41


Solution (Part 2)
/* prints a table-shaped array */
for (row = 0; row < ROWS; row = row + 1) {
for (col = 0; col < COLS; col = col + 1) {
printf("%8.2f", array[row][col]);
}
/* jump to a new row after printing one row of a table */
printf("\n");
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 42


Example
▪ Enter number of rows m (must not be greater than 10) and
number of columns n (must not be greater than 20). Repeat until
both m and n are correct
▪ Enter the members of a two-dimensional integer array of m rows
and n columns.
▪ Find the largest member in each row of the array and print its
position and value

© ZPR-FER-UNIZG Introduction to Programming 43


Example
▪ example of program execution
Enter number of rows > -2
Enter number of rows > 11
Enter number of rows > 3
Enter number of columns > 40
Enter number of columns > 4
Enter 3 x 4 integers >
1 2 4 -8
-8 -7 -5 -2
9 4 9 1
Largest members by rows:
array(0, 2) = 4
array(1, 3) = -2
array(2, 0) = 9

© ZPR-FER-UNIZG Introduction to Programming 44


Solution (Part 1)
#include <stdio.h>
#define MAX_ROWS 10
#define MAX_COLS 20
int main(void) {
int i, j; // control variables for loops
int m, n; // the actual number of rows and of columns
/* Entering m until correct */
do {
printf("Enter number of rows > ");
scanf("%d", &m);
} while (m < 1 || m > MAX_ROWS);
/* Entering n until correct */
do {
printf("Enter number of columns > ");
scanf("%d", &n);
} while (n < 1 || n > MAX_COLS);

© ZPR-FER-UNIZG Introduction to Programming 45


Solution (2. dio)
/* definition of VLA */
int array[m][n];
/* entering members */
printf("Enter %d x %d integers >\n", m, n);
for (i = 0; i < m; i = i + 1) {
for (j = 0; j < n; j = j + 1) {
scanf("%d", &array[i][j]);
}
}

© ZPR-FER-UNIZG Introduction to Programming 46


Solution (3. dio)
/* find and print the largest member in each row */
int colMax;
printf("Largest members by rows:\n");
for (i = 0; i < m; i = i + 1) {
/* find the indeks of the largest member in the row i */
colMax = 0; // assumption: the first element is largest
for (j = 1; j < n; j = j + 1) {
if (array[i][j] > array[i][colMax]) {
colMax = j; // change the assumption
}
}
printf("array(%d, %d) = %d\n",
i, colMax, array[i][colMax]);
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 47


Example
▪ Enter floating point values of a 8x8 square matrix
▪ a square matrix is a table that has an equal number of rows and of
columns
▪ Print the smallest value on the main diagonal and the smallest
value on the antidiagonal
▪ the main diagonal and the antidiagonal of a square matrix
main diagonal antidiagonal
array

© ZPR-FER-UNIZG Introduction to Programming 48


Solution
▪ The main diagonal 0, 0 0, 7

▪ assumption: array[0][0] is the smallest 1, 1 1, 6

▪ check the others on the main diagonal 2, 2 2, 5

min_md = array[0][0]; 3, 3 3, 4
for (i = 1; i < 8; i = i + 1) 4, 3 4, 4
if (array[i][i] < min_md)
5, 2 5, 5
change the assumption
6, 1 6, 6
▪ Antidiagonal 7, 0 7, 7
▪ assumption: array[0][7] is the smallest
▪ check the others on the antidiagonal
min_ad = array[0][7];
for (i = 1; i < 8; i = i + 1)
if (array[i][8 - 1 - i] < min_ad)
change the assumption
© ZPR-FER-UNIZG Introduction to Programming 49
Solution (Part 1)
#include <stdio.h>
#define ORDER 8
int main(void) {
int i, j;
float array[ORDER][ORDER], min_md, min_ad;
/* the usual code for input is omitted */
/* assumption: the first member of the main diagonal is the smallest */
min_ad = array[0][0];
/* check the other members of the main diagonal */
for (i = 1; i < ORDER; i = i + 1) {
if (array[i][i] < min_ad) {
/* change the assumption */
min_ad = array[i][i];
}
}

© ZPR-FER-UNIZG Introduction to Programming 50


Solution (Part 2)
/* assumption: the first member of the antidiagonal is the smallest */
min_ad = array[0][ORDER - 1];
/* check other member of the antidiagonal */
for (i = 1; i < ORDER; i = i + 1) {
if (array[i][ORDER - 1 - i] < min_ad) {
/* change the assumption */
min_ad = array[i][ORDER - 1 - i];
}
}

/* the usual code for printing results is omitted */

return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 51


Example
▪ Enter number of rows m and number of columns n of a matrix
mat. It is not necessary to check that the correctness.
▪ Enter matrix members and print them out in a table form.
▪ Define a new matrix matT to store the transpose of mat
▪ transposition is done by replacing rows with columns: the element
at position [i] [j] of the matrix mat becomes the element at position
[j] [i] of matrix matT
▪ the transposed will have n rows and m columns
▪ print the resulting matrix matT as a table

© ZPR-FER-UNIZG Introduction to Programming 52


Example
▪ an example of executing a program
Enter number of rows and number of columns > 3 5
Enter 3 x 5 integers >
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

1 6 11
2 7 12
3 8 13
4 9 14
5 10 15

© ZPR-FER-UNIZG Introduction to Programming 53


Solution
n
mat
1 2 3 4 5
m 6 7 8 9 10
for (i = 0; i < m; i = i + 1)
11 12 13 14 15 for (j = 0; j < n; j = j + 1)
matT[j][i] = mat[i][j];

m m
matT ? ? ? matT 1 6 11
mat[0][0] → matT[0][0]
? ? ? mat[0][1] → matT[1][0] 2 7 12
mat[0][2] → matT[2][0] n
n ? ? ? 3 8 13
...
? ? ? mat[2][2] → matT[2][2] 4 9 14
? ? ? mat[2][3] → matT[3][2] 5 10 15
mat[2][4] → matT[4][2]

© ZPR-FER-UNIZG Introduction to Programming 54


Solution (Part 1)
#include <stdio.h>
int main(void) {
int m, n, i, j;
printf("Enter number of rows and number of columns > ");
scanf("%d %d", &m, &n);
int mat[m][n], matT[n][m];
/* enter the matrix mat m x n */
printf("Enter %d x %d integers >\n", m, n);
for (i = 0; i < m; i = i + 1) {
for (j = 0; j < n; j = j + 1) {
scanf("%d", &mat[i][j]);
}
}
printf("\n");

© ZPR-FER-UNIZG Introduction to Programming 55


Solution (Part 2)
/* print the matrix mat m x n */
for (i = 0; i < m; i = i + 1) {
for (j = 0; j < n; j = j + 1) {
printf("%4d", mat[i][j]);
}
printf("\n");
}
printf("\n");
/* copy values from mat to corresponding positions in matT */
for (i = 0; i < m; i = i + 1) {
for (j = 0; j < n; j = j + 1) {
matT[j][i] = mat[i][j];
}
}

© ZPR-FER-UNIZG Introduction to Programming 56


Solution (Part 3)
/* print the matrix matT n x m */
for (i = 0; i < n; i = i + 1) {
for (j = 0; j < m; j = j + 1) {
printf("%4d", matT[i][j]);
}
printf("\n");
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 57


Example
▪ Enter n, the order of a matrix. It is not necessary to check for
correctness.
▪ Enter members of a square matrix of order n. Print the matrix in a
table form.
▪ Transpose the matrix by replacing members within the matrix
(without defining a new matrix and without using auxiliary array)
▪ Print the modified matrix in a table form

© ZPR-FER-UNIZG Introduction to Programming 58


Solution
n n
mat mat
1 2 3 4 5 1 6 11 16 21
6 7 8 9 10 2 7 12 17 22
n 11 12 13 14 15 n 3 8 13 18 23
16 17 18 19 20 4 9 14 19 24
21 22 23 24 25 5 10 15 20 25

for (i = 0; i < n - 1; i = i + 1) mat[0][1] ↔ mat[1][0]


for (j = i + 1; j < n; j = j + 1) mat[0][2] ↔ mat[2][0]
mat[i][j] ↔ mat[j][i]; mat[0][3] ↔ mat[3][0]
mat[0][4] ↔ mat[4][0]
mat[1][2] ↔ mat[2][1]
...
mat[3][4] ↔ mat[4][3]

© ZPR-FER-UNIZG Introduction to Programming 59


Solution
#include <stdio.h>
int main(void) {
int n, i, j, aux;
printf("Enter order of a matrix > ");
scanf("%d", &n);
int mat[n][n];
/* the usual code for input is omitted */
/* the usual code for output is omitted */
for (i = 0; i < n - 1; i = i + 1) {
for (j = i + 1; j < n; j = j + 1) {
aux = mat[i][j];
mat[i][j] = mat[j][i];
mat[j][i] = aux;
}
}
/* the usual code for output is omitted */
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 60


Aggregate data types

Structures

© ZPR-FER-UNIZG Introduction to Programming 61


Structure
▪ Structure or record is an aggregate data type that includes
multiple members that do not need to be of the same type
▪ single variable ↔ multiple values
▪ one name combines multiple logically related data
▪ e.g., instead of separate variables
int id; // student id
float midterm; // number of points at midterm exam
float final; // number of points at final exam
float lab[8]; // number of points at lab

▪ a single variable is defined containing members id, midterm, final


and lab
▪ individual values are accessed using a variable name and member
name

© ZPR-FER-UNIZG Introduction to Programming 62


Structure declaration
▪ The structure must be described first
▪ structure declaration, structure blueprint, structure tag
▪ the name of the structure
▪ names and types of structure members

struct structure_name {
type_of_element_1 name_of_element_1;
type_of_element_2 name_of_element_2;
...
type_of_element_n name_of_element_n;
};

▪ The structure declaration can then be used


▪ to define variables of structure type (can be arrays)
▪ for the declaration of other structures that will contain members of
the structure type
© ZPR-FER-UNIZG Introduction to Programming 63
Example
structure declaration points_s
struct points_s { according to the convention, a suffix _s is added to the name
int id;
float midterm;
float final;
float lab[8];
};
variable definition points
struct points_s points; variable points is of type structure points_s
... structure member access operator: . (point)
points.id = 1234; structure member access: variable_name.member_name
points.midterm = 23.5f;
points.lab[0] = 1.5f; points
points.lab[1] = 1.2f; id 1234
midterm 23.5
final ?
lab 1.5 1.2 ? ? ? ? ? ?

© ZPR-FER-UNIZG Introduction to Programming 64


Structure declaration - variants
▪ Variables can be defined at the same time with the structure
declaration. Structure name can later be used to define
additional variables
struct date_s {
int day;
int month;
int year;
} frenchRev, americanRev;
...
frenchRev.day = 5; frenchRev.month = 5; frenchRev.year = 1789;
americanRev.day = 19; americanRev.month = 4; americanRev.year = 1775;
...
struct date_s peasantRevolt;
peasantRevolt.day = 28; peasantRevolt.month = 1;
peasantRevolt.year = 1573;

© ZPR-FER-UNIZG Introduction to Programming 65


Structure declaration - variants
▪ The structure name can be dropped from the declaration if the
declaration will not be required to define additional variables
struct {
float latitude;
float longitude;
} geoPosEiffel, geoPosFER;
...
geoPosEiffel.latitude = 48.85822f;
geoPosEiffel.longitude = 2.2945f;
geoPosFER.latitude = 45.80107f;
geoPosFER.longitude = 15.97083f;
...

© ZPR-FER-UNIZG Introduction to Programming 66


Definition with initialization
▪ Similar to arrays, a variable of structure type can be initialized at
the time of definition
struct points_s points1 = { 4321, 10.5f, 21.5f,
{0.5f, 1.5f, 1.8f}
id 4321
};
midterm 10.5
final 21.5
lab 0.5 1.5 1.8 0.0 0.0 0.0 0.0 0.0

struct points_s points2 = { 1243, .zi = 12.5f,


{0.5f, [5] = 2.0f}
id 1243 };
midterm 0.0
final 12.5
lab 0.5 0.0 0.0 0.0 0.0 2.0 0.0 0.0

© ZPR-FER-UNIZG Introduction to Programming 67


Complex structures
▪ It is possible to define a data structure of arbitrary complexity
because a structure member can be a structure or an array:
struct date_s {
int day;
int month;
int year;
};
struct interval_s {
struct datum_s date_from;
struct datum_s date_to;
};
struct interval_s winter_exam = {{11, 2, 2019}, {22, 2, 2019}};
printf("Winter exam: %d.%d.%d. - %d.%d.%d.",
winter_exam.date_from.day, winter_exam.date_from.month,
winter_exam.date_from.year,
winter_exam.date_to.day, winter_exam.date_to.month,
winter_exam.date_to.year);
© ZPR-FER-UNIZG Introduction to Programming 68
The structure is modifiable lvalue
▪ Unlike arrays, the structure type variable is modifiable lvalue
▪ even when a member of the structure is array!
struct points_s points1 = { 4321, 10.5f, 21.5f,
{0.5f, 1.5f, 1.8f}
};
struct points_s points2;
points2 = points1; correct

▪ The assignment operator is the only operator that can be used for
operations with two operands of structure type. E.g. it is not
possible to use relational operators
if (points1 == points2) { compiler error
...

© ZPR-FER-UNIZG Introduction to Programming 69


Compatible structures
▪ Structure variable can be assigned to another structure variable
only if their types are compatible, which means that the variables
are defined based on the same declaration
struct coordinate_s {
float latitude;
float longitude;
}; Variables defined based on declaration coordinate_s
are not compatible with the variables defined based on
struct position_s {
the declaration position_s. Having members of the
float latitude; same names and types is not enough for compatibility.
float longitude;
};
struct coordinate_s point1 = {45.80107f, 15.97083f};
struct coordinate_s point2;
point2 = point1; correct
struct position_s point3;
point3 = point1; compiler error

© ZPR-FER-UNIZG Introduction to Programming 70


Structures can be array members
▪ Although individual structure type variables may be useful,
structures are most commonly used as elements of more
complex data structures, such as arrays
struct date_s {
int day;
int month;
int year;
};
struct date_s holidays_2018[] = {
{ 1, 1, 2018}, { 6, 1, 2018}
, { 1, 4, 2018}, { 2, 4, 2018}
, { 1, 5, 2018}, {31, 5, 2018}
, {22, 6, 2018}, {25, 6, 2018}
, { 5, 8, 2018}, {15, 8, 2018}
, { 8, 10, 2018}
, { 1, 11, 2018}
, {25, 12, 2018}, {26, 12, 2018}
};

© ZPR-FER-UNIZG Introduction to Programming 71


Example
▪ Enter integer n from the keyboard, representing the number of
students who enrolled the Introduction to Programming course.
For each student, enter the id (int), the number of points on the
midterm exam (float), the number of points on the final exam
(float), and the number of points on each of the eight laboratory
exercises (float). Calculate the sum of points on all knowledge
tests for each student (total number of points).
▪ Sort students according to the total number of points, in order
from higher to lower. The order of students having the same
number of points is not important.
▪ Print the sorted data in a table format

© ZPR-FER-UNIZG Introduction to Programming 72


Example
▪ An example of executing the program
Enter the number of students > 740
Enter data > 360149290 11.6 5.8 1.9 0.6 1.7 1.4 1.0 1.9 1.5 0.2
Enter data > 553721121 15.9 10.2 0.9 0.8 0.8 1.3 1.9 0.4 0.4 1.8
Enter data > 277253502 33.3 44.2 1.4 1.8 1.6 0.8 0.9 1.6 0.0 1.4
...
Enter data > 380893153 3.4 0.4 1.1 0.2 1.5 0.1 0.4 0.6 1.3 0.7
Enter data > 711650074 28.5 9.4 1.8 0.8 1.1 1.2 1.8 0.0 0.0 0.5

Rankings
No. Id Midterm Final LAB Total
=========================================
1. 277253502 33.3 44.2 9.5 87.0
2. 378063837 33.5 44.6 8.6 86.7
3. 419558299 28.9 44.4 11.9 85.2
...
739. 389674171 0.2 1.2 8.6 10.0
740. 380893153 3.4 0.4 5.9 9.7

© ZPR-FER-UNIZG Introduction to Programming 73


Solution (Part 1)
#include <stdio.h>
#define NR_LABS 8
int main(void) {
struct points_s {
int id;
float midterm;
float final;
float lab[NR_LABS];
float total;
};
int n, i, j;
float total;
float total_lab;
printf("Enter the number of studenats > ");
scanf("%d", &n);
struct points_s points[n]; VLA array

© ZPR-FER-UNIZG Introduction to Programming 74


Solution (Part 2)
/* enter points for n students */
for (i = 0; i < n; i = i + 1) {
printf("Enter data > ");
scanf("%d %f %f",
&points[i].id, &points[i].midterm, &points[i].final);
total = points[i].midterm + points[i].final;
// enter points for the lab. exercises
for (j = 0; j < NR_LABS; j = j + 1) {
scanf("%f", &points[i].lab[j]);
total = total + points[i].lab[j];
}
points[i].total = total;
}

© ZPR-FER-UNIZG Introduction to Programming 75


Solution (Part 3)
/* sort by total points */
int ind_max;
struct points_s aux;
for (i = 0; i < n - 1; i = i + 1) {
ind_max = i + 1;
for (j = i + 2; j < n; j = j + 1) {
if (points[j].total > points[ind_max].total) ind_max = j;
}
if (points[ind_max].total > points[i].total) {
// swap points[i] and points[ind_max]
aux = points[i];
points[i] = points[ind_max];
points[ind_max] = aux;
}
}

© ZPR-FER-UNIZG Introduction to Programming 76


Solution (Part 4)
/* print rankings */
printf("\nRankings\n");
printf(" No. Id Midterm Final LAB Total\n");
printf("===========================================\n");
for (i = 0; i < n; i = i + 1) {
total_lab = 0.f;
for (j = 0; j < NR_LABS; j = j + 1) {
total_lab = total_lab + points[i].lab[j];
}
printf("%4d. %9d %5.1f %5.1f %5.1f %7.1f\n",
i + 1, points[i].id,
points[i].midterm, points[i].final,
total_lab, points[i].total);
}
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 77


Comment on the solution
▪ Why would a solution using five arrays instead of array of
structures be inappropriate?
...
int id[n];
float midterm[n];
float final[n];
float total[n];
float lab[n][NR_LABS];
...
▪ the connectivity of the data in these arrays is not recognizable
▪ e.g. it is not immediately clear that the values id[0], midterm[0],
final[0], total[0] and the row 0 of array lab refer to the same student
▪ it is more difficult to handle data sets
▪ e.g., make a copy of all information about one student

© ZPR-FER-UNIZG Introduction to Programming 78


Introduction to Programming - Lectures

5. Data types in C

© ZPR-FER-UNIZG Introduction to Programming 1


Basic data types

© ZPR-FER-UNIZG Introduction to Programming 2


Basic data types
▪ The data type of a variable determines the characteristics of the
data stored in that variable and the operations that can be
performed on the data
▪ The following basic data types are available in programming
language C
▪ integer types
▪ char
▪ int
▪ _Bool
▪ floating point types
▪ float
▪ double
▪ optional qualifiers (short / long, signed / unsigned) describe
the additional characteristics of some of these types

© ZPR-FER-UNIZG Introduction to Programming 3


Required (and expected) foreknowledge
▪ decimal, binary, octal, hexadecimal number systems
▪ converting integers between any of the following numbering
systems: 2710 = 110112 = 338 = 1B16
▪ how positive and negative integers are stored in the computer
▪ the addition of positive and negative numbers in a binary number
system
▪ a range of numbers that can be stored in a register of n bits
▪ if only positive numbers are stored
[0, 2n - 1]
▪ if both positive and negative numbers are stored
[-(2n-1), 2n-1 - 1]

▪ Why is it important for developers to know how data are stored?


© ZPR-FER-UNIZG Introduction to Programming 4
Example
▪ Write a program that reads the integer n from the keyboard and
then prints the result of the operation n + 5
for n = 2 000 000 000
#include <stdio.h> 2000000000
int main(void) { 2000000005 ✓
int n, m;
for n = -2 000 000 000
scanf("%d", &n);
m = n + 5; -2000000000
printf("%d", m); -1999999995 ✓
return 0; for n = 2 147 483 647
} ·2147483647
-2147483644 ?

© ZPR-FER-UNIZG Introduction to Programming 5


Example
▪ Write a program that reads the real number x from the keyboard
and then prints the result of the operation x + 0.125, with a total
width of 15 characters, with five digits after the decimal point
for x = 2 097 151.0
#include <stdio.h> ··2097151.0
int main(void) { ··2097151.12500 ✓
float x, y;
for x = -2 097 151.0
scanf("%f", &x);
y = x + 0.125f; ·-2097151.0
printf("%15.5f", y); ·-2097150.87500 ✓
return 0; for x = 2 097 152.0
} ··2097152.0
··2097152.00000 ?
for x = 1 000 000.3
··1000000.3
··1000000.43750 ?
© ZPR-FER-UNIZG Introduction to Programming 6
Basic data types

Integer data types

© ZPR-FER-UNIZG Introduction to Programming 7


Integer data types

Data type int

© ZPR-FER-UNIZG Introduction to Programming 8


Integer types
Example of variable definition

▪ general form unsigned long int bigNumber;


short signed char smallNumber;
_Bool trueOrFalse;
signed long

unsigned long long

int

char

_Bool

▪ Prefixes (qualifiers):
▪ signed / unsigned: determine whether only positive (unsigned) or also
negative numbers (signed) can be stored in an int or char variable
▪ short / long / long long: reduce / increase the range of numbers that
can be stored in a variable of type int
© ZPR-FER-UNIZG Introduction to Programming 9
Data type int (integer) - variants
▪ qualifier signed and keyword int are implied (default), therefore,
they can be omitted
Full name of the type Synonyms Recommended form
in programs
signed int int, signed int
unsigned int unsigned unsigned int
signed short int signed short, short int, short short
unsigned short int unsigned short unsigned short
signed long int signed long, long int, long long
unsigned long int unsigned long unsigned long
signed long long int signed long long, long long int, long long long long
unsigned long long int unsigned long long unsigned long long

© ZPR-FER-UNIZG Introduction to Programming 10


Qualifiers short, long and long long
▪ The data type int, given the allowed range of numbers that can be
stored (determined by the number of binary digits), can be
further qualified as short, long or long long
▪ The number range for each subtype is not language-specific, but
the following rules apply:
▪ short: minimum 2 bytes and must not have a range greater than int
▪ int: minimum 2 bytes and must not have a range greater than long
▪ long: minimum 4 bytes and must not have a range greater than long
long
▪ long long: 8 bytes minimum
▪ The actual number ranges depend on the compiler
implementation and computer architecture

© ZPR-FER-UNIZG Introduction to Programming 11


Example
▪ gcc and architecture x86_64

Type Bytes The range of numbers that can be stored


signed short int 2 -32 768, 32767
signed int 4 -2 147 483 648, 2 147 483 647
signed long int 4 -2 147 483 648, 2 147 483 647
signed long long int 8 -9 223 372 036 854 775 808, 9 223 372 036 854 775 807

© ZPR-FER-UNIZG Introduction to Programming 12


Qualifiers signed i unsigned
▪ The value (binary digits) stored in a signed variable is considered
positive or negative, depending on the value of the most
significant bit
▪ The value stored in an unsigned variable, regardless of the value
of the most significant bit, is always considered positive
▪ this doubles the maximum positive value that can be stored
▪ Example: if a variable of type short uses 2 bytes
▪ range of numbers in signed variable: [-32 768, 32 767]
▪ range of numbers in unsigned variable: [0, 65 535]

© ZPR-FER-UNIZG Introduction to Programming 13


Example
▪ The result of an operation using signed or unsigned int
unsigned int ua = 2147483647; 01111111111111111111111111111111
ua = ua + 1; 10000000000000000000000000000000
if (ua > 0) is considered exclusively as a positive number
printf("greater than zero\n"); output: greater than zero
else
printf("less than zero");

signed int a = 2147483647; 01111111111111111111111111111111


a = a + 1; 10000000000000000000000000000000
if (a > 0) is considered as a positive or negative number
printf("greater than zero\n");
else
printf("less than zero\n"); output: less than zero

© ZPR-FER-UNIZG Introduction to Programming 14


Example
▪ compiler gcc and architecture x86_64

Type Bytes The range of numbers that can be stored


unsigned short int 2 0, 65535
unsigned int 4 0, 4 294 967 295
unsigned long int 4 0, 4 294 967 295
unsigned long long int 8 0, 18 446 744 073 709 551 615

© ZPR-FER-UNIZG Introduction to Programming 15


Qualifiers signed and unsigned
▪ Tip: Do not mix signed and unsigned types
▪ the conversion rules are complicated
▪ the result of operations may depend on the implementation of the
compiler (result: non-portable programs)
▪ it is not usually necessary to use an unsigned data type. It will be
used in this course on rare occasions, e.g.
▪ when targeted to increase the ability to store (approximately twice)
larger positive numbers, at the expense of the ability to store
negative numbers
▪ when bit operations are performed, especially in the case of bit shift
operations
▪ bit operations will be explained later

© ZPR-FER-UNIZG Introduction to Programming 16


Integer constants
▪ constants are stored in computer memory in the same way as
variables
▪ the number of bytes used to store data, and ability to store positive
or negative numbers, depends on the type of the constant
Type Examples of constants
signed short int there is no constant of type signed short, use a constant of type
int
signed int 2000000000, -2000000000
signed long int 2000000000L, -2000000000L
signed long long int -5000000000LL, 5000000000LL
unsigned short int there is no constant of type unsigned short
unsigned int 2000000000U
unsigned long int 2000000000UL
unsigned long long int 5000000000ULL
▪ instead of the suffix U, L ili LL u, l ili ll can be used (lower case U i L)
© ZPR-FER-UNIZG Introduction to Programming 17
Integer constants
▪ integers are usually written in decimal numbering system, but can
also be written in octal or hexadecimal system
▪ the octal constant begins with the prefix 0 and contains digits 0-7
▪ the hexadecimal constant begins with the prefix 0x or 0X and
contains the digits 0-9 and A-F or a-f

printf("%d", 17); 17
printf("%d", 017); 15
printf("%d", 019); the compiler reports an error!
printf("%d", 0x17); 23
printf("%d", 0X1a); 26

printf("%d", 0x7FFFFFFF); 2147483647


printf("%d", 0xFFFFFFFF); -1

© ZPR-FER-UNIZG Introduction to Programming 18


Integer constants
▪ the suffixes U, L and LL can be added to the constants written in
any numbering system
017LL signed long long constant, equals 15LL
0x17L signed long constant, equals 23L
0xFFFFFFFFu unsigned int constant, equals 4294967295U
0xFFFFFFFF signed int constant, equals -1

© ZPR-FER-UNIZG Introduction to Programming 19


Conversion specifications for printf and scanf
Type signed unsigned ▪ u can be replaced by x, X, o for
short int %hd %hu reading or printing in
int %d %u hexadecimal or octal form
long int %ld %lu
long long int %lld %llu

printf("%d", 0xFFFFFFFF); -1
printf("%u", 0xFFFFFFFF); 4294967295
printf("%lld", 0xFFFFFFFFFFFFFFFF); -1
printf("%llu", 0xFFFFFFFFFFFFFFFF); 18446744073709551615
printf("%o", 0xFFFFFFFF); 37777777777
printf("%x", 0xFFFFFFFF); ffffffff
printf("%X", 0xFFFFFFFF); FFFFFFFF
printf("%llo", 0xFFFFFFFFFFFFFFFF); 1777777777777777777777
© ZPR-FER-UNIZG Introduction to Programming 20
Example
#include <stdio.h>
int main(void) {
unsigned int uNumber = 2000000000U;
uNumber = uNumber * 2 / 2;
printf("uNumber=%u\n", uNumber); uNumber=2000000000

signed int sNumber = 2000000000;


sNumber = sNumber * 2 / 2;
printf("sNumber=%d\n", sNumber); sNumber=-147483648
return 0;
}

▪ Explanation:
▪ uNumber * 2 = 4000000000, 4000000000 / 2 = 2000000000
▪ sNumber * 2 = -294967296, -294967296 / 2 = -147483648

© ZPR-FER-UNIZG Introduction to Programming 21


Conversion specifications - logical errors
▪ It is important to use appropriate conversion specifications as the
compiler will not recognize their misuse
▪ difficult to identify logical errors occur
printf("%lld", 10000000000LL); 10000000000
printf("%d", 10000000000LL); 1410065408

int a = 98304;
scanf("%hd", &a); enter: 10
printf("%d", a); 65546

© ZPR-FER-UNIZG Introduction to Programming 22


Integer data types

Data type char

© ZPR-FER-UNIZG Introduction to Programming 23


Data type char
▪ an integer data type used to store small numbers
▪ pronunciation of the data type char: tʃaː or (less frequently) 'kær
▪ in English, both forms are used
▪ the standard requires the data type char to store integers in at least
one byte
▪ usually this is exactly one byte (e.g. for gcc and architecture x86_64)
▪ ranges allowed
▪ signed: [-128, 127]
▪ unsigned: [0, 255]

© ZPR-FER-UNIZG Introduction to Programming 24


Using the char data type to represent
characters
▪ Characters cannot be stored in the computer!
▪ it is possible to store binary numbers representing predefined
character codes, e.g. Character binary decimal
A 01000001 65
▪ various code pages are in use B 01000010 66

▪ ASCII (7-bit): contains 128 different characters and control characters


encoded with values 0-127
▪ ISO-8859: codes 0-127 as in 7-bit code, while codes 128-255 are used
for various additional characters depending on the code page, e.g.
▪ ISO 8859-1: additional signs of Western European languages
▪ ISO 8859-2: additional signs of Eastern European languages
▪ e.g. š = 18510, Č = 20010
▪ In this course, ASCII code page will be used
ASCII - American Standard Code for Information Interchange
ISO - International Organization for Standardization
© ZPR-FER-UNIZG Introduction to Programming 25
Unicode
▪ Newer industry standard for character encoding
▪ Uses multiple bytes for character encoding and enables almost all
letters to be represented using a unique character set
▪ The Unicode Consortium: www.unicode.org

▪ Example: code for character LA from Tagalog (Philippines) is 170E16

© ZPR-FER-UNIZG Introduction to Programming 26


ASCII character code table (1)
Dec. val. C const. Character Dec. val. Character
0 '\0' Nul character (NULL) 16 Data link escape (DLE)
1 Start of header (SOH) 17 Device control 1(DC1)
2 Start of text (STX) 18 Device control 2 (DC2)
3 End of text (ETX) 19 Device control 3 (DC3)
4 End of transmission (EOT) 20 Device control 4 (DC4)
5 Enquiry (ENQ) 21 Negativne acknowledge (NAK)
6 Acknowledge (ACK) 22 Synchronous idle (SYN)
7 '\a' Alarm (BEL) 23 End of transmisson block (ETB)
8 '\b' Backspace (BS) 24 Cancel (CAN)
9 '\t' Horizontal tab (HT) 25 End of medium (EM)
10 '\n' Line feed (LF) 26 Substitute (SUB)
11 '\v' Vertical tab (VT) 27 Escape (ESC)
12 '\f' Form feed (FF) 28 File separator (FS)
13 '\r' Carriage return (CR) 29 Group separator (GS)
14 Shift out (SO) 30 (RS)
15 Shif in (SI) 31 Unit separator (US)

© ZPR-FER-UNIZG Introduction to Programming 27


ASCII character code table (2)
Dec. val. Character Dec. val. Character Dec. val. Character Dec. val. Character
32 space 48 0 65 A 80 P
33 ! 49 1 66 B 81 Q
34 " 50 2 67 C 82 R
35 # 51 3 68 D 83 S
36 $ 52 4 69 E 84 T
37 % 53 5 70 F 85 U
38 & 54 6 71 G 86 V
39 ' 55 7 72 H 87 w
40 ( 56 8 73 I 88 X
41 ) 57 9 74 J 89 Y
42 * 58 : 75 K 90 Z
43 + 59 ; 76 L 91 [
44 , 60 < 77 M 92 \
45 - 61 = 78 N 93 ]
46 . 62 > 79 O 94 ^
47 / 63 ? 95 _
64 @
© ZPR-FER-UNIZG Introduction to Programming 28
ASCII character code table (3)
Dec. val. Character Dec. val. Character
96 ` 112 p The control characters
97 a 113 q for the computer
98 b 114 r input/output units (non-
99 c 115 s printable characters) are
100 d 116 t located at positions 0-31
101 e 117 u and at position 127 (DEL)
102 f 118 v
103 g 119 w
104 h 120 x Printable characters are
105 i 121 y in positions 32-126
106 j 122 z
107 k 123 {
108 l 124 |
109 m 125 }
110 n 126 ~
111 o 127 DEL

© ZPR-FER-UNIZG Introduction to Programming 29


Conversion specifications for printf i scanf
▪ in the case where the data type char displays as a number
Tip signed unsigned ▪ d or u can be replaced with x, X, o
char %hhd %hhu for printing in hexadecimal or octal
form
signed char a = -10;
unsigned char b = 255;
printf("%hhd %hhu", a, b); -10 255
printf("%hho %hhx", a, b); 366 ff

▪ in most applications it is allowed to use the format %d because the


corresponding conversions char ↔ int are performed automatically
char a = 65;
printf("%d", a); 65

© ZPR-FER-UNIZG Introduction to Programming 30


Conversion specifications for printf i scanf
▪ when char data is displayed or read as a character, the conversion
specification %c is used
char a, b, c, d;
a = 65;
printf("%hhd %c", a, a); 65 A
b = a + 3;
printf("%hhd %c", b, b); 68 D
scanf("%c", &c); input 7
printf("%hhd %c", c, c); 55 7
scanf("%c", &d); input E
printf("%hhd %c", d, d); 69 E

© ZPR-FER-UNIZG Introduction to Programming 31


Constants
▪ a char-type constant does not exist. Constants of type int are
used.
▪ it is appropriate to use a special form of writing an int constant
▪ a character (printable) from an ASCII table written in single quotes, e.g.
'B'
▪ the int-type constant so written takes up 4 bytes and has a value
0000004216, respectively 6610
▪ the following two program sections will result in the same content in x:
char x; char x;
x = 66; x = 'B';

▪ in either case, the contents of a 4-byte constant will be stored in a


single-byte variable (discarding three bytes with significant bits, which
contains only zeros anyway)

© ZPR-FER-UNIZG Introduction to Programming 32


Examples of integer constants
C program Hex. Dec. Corresponds to ASCII character:
'A' 0x61 65 Capital A
'0' 0x30 48 Digit zero

▪ Characters that have a special meaning in syntax or cannot be easily represented


with a single character are represented using so-called "escape sequence"
▪ a string of two or more characters beginning with a character \ that indicates the
"special" meaning of the characters that follow
C program Hex. Dek. Corresponds to ASCII character:
'\a' 0x07 7 alarm (bell, beep), activates sound on the terminal
'\t' 0x09 9 Horizontal tab
'\n' 0x0A 10 Line feer
'\0' 0x00 0 Null-character, string terminating character
'\\' 0x5C 92 Backslash
'\'' 0x27 39 Single quotation mark
'\"' 0x22 34 Double quotation mark
© ZPR-FER-UNIZG Introduction to Programming 33
Simplification of expression

char c1;
c1 = 'E';

▪ For simplicity, colloquial expressions will be used:


▪ 'E' is a character constant
▪ although it is known to be an integer (int) constant with value of 6910
▪ variable c1 is of character type
▪ although it is known to be of integer type (but will obviously be used to
store ASCII character code)
▪ character E is stored in the variable c1
▪ although it is known that the ASCII code of the character E, integer
6910, is stored in the variable c1

© ZPR-FER-UNIZG Introduction to Programming 34


Example
#include <stdio.h>
int main(void) {
char x = 'A', y = x + 32, z = '\n';
printf("%hhd %c\n", x, x);
printf("%hhd %c\n", y, y);
printf("%hhd %c\n", z, z);
printf("%d %c\n", '0' + 2, '0' + 2);
printf("%d %c\n", '0' + '2', '0' + '2');
return 0;
}

65 A
97 a
10 

50 2
98 b

© ZPR-FER-UNIZG Introduction to Programming 35


Example
#include <stdio.h>
int main(void) {
char c = 'D';
printf ("%c %d\n", c, c);
printf ("%c\n", c + 32);
printf ("%d\n", 'C' - 'A');
return 0;
}

D 68
d
2

© ZPR-FER-UNIZG Introduction to Programming 36


Digits 0 - 9 in the ASCII table
▪ Note that codes of ASCII digits 0-9 do not match the numeric
values of the digits
char a = '1'; a numeric value of 49 is stored in the variable

▪ if a numeric value is to be derived from a digit code, 48 should be


subtracted from that value, because 48 represents the character
code '0', 49 is '1' and so on
char c;
scanf("%c", &c); input 7
printf("%c %hhd %d", c, c, c - 48); 7 55 7
ili
printf("%c %hhd %d", c, c, c - '0'); 7 55 7

© ZPR-FER-UNIZG Introduction to Programming 37


Digression: character strings

© ZPR-FER-UNIZG Introduction to Programming 38


Character string
▪ There is no basic data type in C that supports character strings
▪ one-dimensional array whose members are of type char is used to
store a string of characters, with the end of the string by a
member of the array containing a null character '\0' (ASCII code 0)

7310 11810 9710 11010 010


char name[5];
name 01001001 01110110 01100001 01101110 00000000
name[0] = 'I';
name[1] = 'v'; ▪ for simplicity, characters will be shown instead
name[2] = 'a'; of character codes
name[3] = 'n';
name[4] = '\0'; name I v a n \0
▪ use conversion specification %s
▪ use the name of the array as the argument to
printf("%s", name); Ivan printf
© ZPR-FER-UNIZG Introduction to Programming 39
What the purpose of the string terminator '\0' ?
▪ Using a character '\0' it can be inferred where the character string
ends For example:
▪ printf function, according to conversion specification %s, prints
characters from a given character string, character by character,
until it reaches a member with the value '\0'
▪ if the end of the string is not correctly indicated by a character '\0',
the function will continue to print characters whose ASCII codes
correspond to the values in memory after the end of the string
char name[4]; name I v a n ? ? ? ...
name[0] = 'I';
name[1] = 'v';
▪ the printout will continue until a byte
name[2] = 'a'; is found in memory with a value of
name[3] = 'n'; zero
printf("%s", name); Ivan*)%&/!)=()Z)(B#DW=)$/")#*'@!"/...

© ZPR-FER-UNIZG Introduction to Programming 40


Definition of a character string with initialization

▪ As with other data types:


▪ without initialization, array members contain undefined values
char name[4]; name ? ? ? ?

▪ initial values can be listed in the so-called initializer


char name[4] = {'I', 'v', 'a', '\0'}; name I v a \0

▪ ili
char name[] = {'I', 'v', 'a', '\0'}; name I v a \0

▪ ili

char name[4] = {'I', 'v', 'a'}; name I v a \0

© ZPR-FER-UNIZG Introduction to Programming 41


Definition of a character string with initialization
▪ Pay attention
▪ following initialization is incorrect if the array is intended to be used
as a string:
char name[4] = {'I', 'v', 'a', 'n'}; name I v a n

▪ correctly:
char name[4+1] = {'I', 'v', 'a', 'n'}; name I v a n \0

© ZPR-FER-UNIZG Introduction to Programming 42


An easier way to initialize a string of characters
▪ Instead of: char name[4] = {'I', 'v', 'a', '\0'};

▪ a different form of initializer can be used


char name[4] = "Iva"; character \0 will be added, the developer
must provide space for at least one more
character!
▪ ili
char name[] = "Iva"; the required array size will be determined by
the compiler, character \0 will be added

▪ usually character strings are defined using symbolic constants. In


doing so, it is good practice to use notation "+ 1". This emphasizes
that the space used to terminate the string is not forgotten
#define MAX_NAME 10
char name[MAX_NAME + 1] = "Ivan";

name I v a n \0 \0 \0 \0 \0 \0 \0
© ZPR-FER-UNIZG Introduction to Programming 43
Constant character string
▪ In a program, a constant character string is denoted by double
quotes initializer. This is not an assignment!

#define MAX_NAME 5
char name[MAX_NAME + 1] = "Iva";
printf("%s\n", name); printing a string of characters stored in a variable
printf("%s\n", "Marko"); printing a constant character string

constant character
string
Iva
Marko

char name[10 + 1];


name = "Iva"; Not allowed! Array is non-modifiable lvalue!

© ZPR-FER-UNIZG Introduction to Programming 44


Constant character string
#define MAX_NAME 5
char name[MAX_NAME + 1] = "Iva";
printf("%s\n", name);
printf("%s\n", "Marko");

▪ constant character string "Marko" is stored in the memory similar


to the character string name
string (array) name constant character string

... I v a \0 \0 \0 ... M a r k o \0 ...

▪ but there is a significant difference: the content of a character


string can be modified

name[1] = 'd'; Ida


printf("%s\n", name);

© ZPR-FER-UNIZG Introduction to Programming 45


Constant character string
▪ Constant character strings in programs should not be broken
across multiple lines
printf("%s", "Faculty
in Unska 3"); the compiler reports an error

▪ if the string is too long to be written in one line, simple


concatenation should be used
printf("%s", "Faculty"
" in Unska 3");

▪ a constant character string written in two or more parts will be


stored in memory in the same way as if it was written in one part
printf("%s", "Faculty in Unska 3");

... F a c u l t y i n U n s k a 3 \0 ...

© ZPR-FER-UNIZG Introduction to Programming 46


Conversion specification %s for printf
▪ A conversion specification %s is used to print a character string
(also a constant character string)
printf("Name: %s\nSurname: %s\nAddress:\n%s\n",
"Ana",
"Novak",
"Ilica 1\n10000 Zagreb\\Center");

Name: Ana
Surname: Novak
Address:
Ilica 1
10000 Zagreb\Center

© ZPR-FER-UNIZG Introduction to Programming 47


Conversion specification %s for scanf
▪ Conversion specification %s lets you read a series of characters
until the first blank, newline, or tab appears
char name[10 + 1], surname[10 + 1];
scanf("%s %s", name, surname);
printf("%s, %s", surname, name);

Anamarija Horvat Novak


Horvat, Anamarija

▪ Reading with conversion specification %s embeds '\0' at the end


of the string
▪ Reading a character string using a function scanf and conversion
specification %s is potentially dangerous
▪ what happens if the user types too many characters for first name
or last name (compares to the length of the character string
specified in the definition) e.g. Anamarija Horvat-Novak
© ZPR-FER-UNIZG Introduction to Programming 48
Read character strings securely
▪ If it is necessary to disable the input of too long character strings,
or to make it possible to read a character string containing blanks
or tabs, then the fgets function should be used instead of
scanf to read the character string from the keyboard.
▪ the fgets function will be explained in more detail later. An
abridged description is provided here, which will be sufficient for its
proper use
▪ the fgets function expects three arguments
▪ array name (character string type variable) where the character string
is to be stored
▪ maximum number of characters n the fgets function can accept while
reading characters from the keyboard
▪ data stream from which characters are read. For now, always stdin
(abbreviation comes from standard input - very simplified: the
keyboard). See the section on files for a more detailed explanation.
© ZPR-FER-UNIZG Introduction to Programming 49
Reading character strings
char text[10]; ... ? ? ? ? ? ? ? ? ? ? ...
garbage values
fgets(text, 10, stdin);

▪ reads characters from the keyboard into the array text until it reads a
new line tag or reads n-1 characters (in this example 9). Behind the last
character read, it adds the character '\0'
▪ why the maximum number of characters must be given to this function?
 ... \n \0 ? ? ? ? ? ? ? ? ...

Dog
... D o g \n \0 ? ? ? ? ? ...

Five dogs
... F i v e d o g s \0 ...

Two cats
... T w o c a t s \n \0 ...

Eleven dogs ... E l e v e n d o \0 ...


© ZPR-FER-UNIZG Introduction to Programming 50
Example
▪ enter a character string from a single line from the keyboard. The
character string, including the newline character, cannot be
longer than 10 characters.
▪ if the entered string contains a newline character, delete it from
the string. Turn all lowercase letters into uppercase letters. Print
the new the string followed by an exclamation mark.

Enter a character string > Catch 22


CATCH 22!

Enter a character string > The right stuff


THE RIGHT !

Enter a character string > 


!

© ZPR-FER-UNIZG Introduction to Programming 51


Solution
#include <stdio.h>
#define MAX_STRING 10
int main(void) {
char s[MAX_STRING + 1];
int i = 0;
printf("Enter a character string > ");
fgets(s, MAX_STRING + 1, stdin);
while (s[i] != '\0') {
if (s[i] >= 'a' && s[i] <= 'z') {
s[i] = s[i] - ('a' - 'A');
} else if (s[i] == '\n') {
s[i] = '\0';
}
i = i + 1;
}
printf("%s!", s);
return 0;
}

© ZPR-FER-UNIZG Introduction to Programming 52


Explanation
char s[10]; ... ? ? ? ? ? ? ? ? ? ? ? ...

fgets(s, 10, stdin); ... C a t c h 2 2 \n \0 ? ...

after the while loop ... C A T C H 2 2 \0 \0 ? ...

fgets(s, 10, stdin); ... T h e r i g h t \0 ...

after the while loop ... T H E R I G H T \0 ...

fgets(s, 10, stdin); ... \n \0 ? ? ? ? ? ? ? ? ? ...

after the while loop ... \0 \0 ? ? ? ? ? ? ? ? ? ...

© ZPR-FER-UNIZG Introduction to Programming 53


Integer data types

Data type _Bool

© ZPR-FER-UNIZG Introduction to Programming 54


Data type _Bool
▪ an integer data type used to store a logical value true ili false
▪ internally, the value of type _Bool is stored as an integer
▪ logical value true is represented by an integer value 1, logical value
false is represented by an integer value 0
▪ e.g. for gcc and architecture x86_64, 1 byte is used
▪ what makes the _Bool type different from other integer types?
▪ if any non-zero numeric value is assigned to a variable of type _Bool
the variable will be set to 1

_Bool itIsRaining;
itIsRaining = 37;
printf("%hhd", itIsRaining);
1

© ZPR-FER-UNIZG Introduction to Programming 55


Logical values in C
▪ any data, of any type, can be used as a logical value in C (posible
but not encouraged). This means that any value that is numeric and
▪ equal to zero, corresponds to a logical value false
▪ not equal to , corresponds to a logical value true
▪ the following example is not a guideline for how programs should
be written (quite the opposite), but just an illustration of the above

correct but unnecessarily vague corect and clear


float a, b; float a, b;
scanf("%f %f", &a, &b); scanf("%f %f", &a, &b);
if (a + b) { if (a + b != 0.f) {
printf("The sum is not zero"); printf(" The sum is not zero ");
} }

© ZPR-FER-UNIZG Introduction to Programming 56


The result of a logical expression

▪ in C programming language, the result of a logical expression is


always an integer value 0 (if the result is false) or integer value 1
(if the result is true). The result is of data type int

float x = 5.0f;
printf("%d\n", x > 10.f || x < 0.f);
printf("%d", x != 20.f);

0
1
▪ the fact that the result of a logical expression is an integer 0 or 1,
is not the justification for writing e.g.:

VERY BAD!
if (x != 20.0 == 1)

© ZPR-FER-UNIZG Introduction to Programming 57


The result of logical expression
▪ the result of a logical expression can be stored in a variable of
type _Bool and then used in further logical expressions
▪ The following example is an illustration, not a guideline:
float x;
_Bool x_is_greater_than_10, x_is_less_than_20;
scanf("%f", &x);
x_is_greater_than_10 = x > 10.f;
x_is_less_than_20 = x < 20.f;
if (is_greater_than && x_is_less_than_20)
printf("x is in interval <10, 20>");

VERY BAD!
if (x_is_greater_than_10 == 1 && x_is_less_than_20 == 1)
if ((x_is_greater_than_10 && x_is_less_than_20) == 1)

© ZPR-FER-UNIZG Introduction to Programming 58


Example
▪ enhanced example with prime numbers
...
int i, n, divisible = 0;
_Bool divisible = 0; // hypothesis: not divisible
printf("Enter a number > ");
scanf("%d", &n);
i = 2;
while (i <= n - 1 && divisible == 0 !divisible) {
if (n % i == 0) {
divisible = 1; // hypothesis was wrong
}
i = i + 1;
}
if (divisible == 1 divisible || n == 1) // 1 is a special case
printf("%d is not a prime number\n", n);
else
...

© ZPR-FER-UNIZG Introduction to Programming 59


Alternate name for _Bool, constants false and true

▪ <stdbool.h> contains:
▪ macro definition bool
▪ allows an alternate name bool to be used instead of _Bool
▪ bool is more appropriate than _Bool because it is more in the spirit of
language C: other embedded data types, such as int, float, etc., do not
have the _ character in their name and do not contain uppercase
letters
▪ macro definitions true i false
▪ allow the use of symbolic constants true and false, instead of integer
constants 0 and 1
▪ the clarity of the program increases

Macro definitions will be explained in detail in later lectures. For now, it is enough to
know that after the file <stdbool.h> is included, bool, true i false can be used in the
program as a replacement for _Bool, 1 i 0.
© ZPR-FER-UNIZG Introduction to Programming 60
Example
▪ further enhancement of the prime numbers exampe
#include <stdbool.h>
...
int i, n;
_Bool divisible = 0;
bool divisible = false; // hypothesis: not divisible

printf("Enter a number > ");


scanf("%d", &n);
i = 2;
while (i <= n - 1 && divisible == 0 !divisible) {
if (n % i == 0) {
divisible = 1 true; // hypothesis was wrong
}
...

© ZPR-FER-UNIZG Introduction to Programming 61


Floating point data types

Data type float

© ZPR-FER-UNIZG Introduction to Programming 62


Data type float
▪ Example of a variable definition
float temperature;

▪ Examples of constants of type float


2f = 2.0
-2.34F = -2.34
-1.34e5F = -1.34 ∙ 105
9.1093E-31f = 9.1093 ∙ 10-31

▪ How the values of type float are stored in the computer?

© ZPR-FER-UNIZG Introduction to Programming 63


Binary fractions
▪ rational number q is a decimal fraction if it can be written in form
q = ± ( cn ∙ 10n + cn-1 ∙ 10n-1 + ... c1 ∙ 101 + c0 ∙ 100
+ r1 ∙ 10-1 + r2 ∙ 10-2 + ... + rm ∙ 10-m )
ci ∈ {0, 1, 2, ..., 9}, i = 0, ..., n
rj ∈ {0, 1, 2, ..., 9}, j = 1, ..., m
13.7510 = 1 ∙ 101 + 3 ∙ 100 + 7 ∙ 10-1 + 5 ∙ 10-2
▪ similar, binary fraction q can be written in the form
q = ± ( cn ∙ 2n + cn-1 ∙ 2n-1 + ... c1 ∙ 21 + c0 ∙ 20
+ r1 ∙ 2-1 + r2 ∙ 2-2 + ... + rm ∙ 2-m )
ci ∈ {0, 1}, i = 0, ..., n
rj ∈ {0, 1}, j = 1, ..., m
1101.112 = 1 ∙ 23 + 1 ∙ 22 + 0 ∙ 21 + 1 ∙ 20 + 1 ∙ 2-1 + 1 ∙ 2-2

© ZPR-FER-UNIZG Introduction to Programming 64


Conversion of decimal fraction to binary fraction
▪ the integral part (part in front of the decimal point) is converted
into the integral part (part in front of the binary point) of the
binary fraction by successive divisions by 2
▪ the fractional part (the part behind the decimal point) is
converted to the fractional part of the binary fraction by
successive multiplication by number 2. Multiplication ends when
the result reaches zero
▪ 9.62510 = ?2 . 1 0 1
910 = 10012

0.625 ∙ 2 = 1.250

0.250 ∙ 2 = 0.5

0.5 ∙ 2 = 1.0 ← end

▪ 9.62510 = 1001.1012
© ZPR-FER-UNIZG Introduction to Programming 65
Conversion of decimal fraction to binary fraction
▪ if the denominator of a fraction contains a factor other than the
power of number 2, then the decimal fraction cannot be
represented as a binary number with a finite number of digits.
E.g.
▪ numbers that can be represented with a finite number of binary
digits
▪ 1/2, 1/4, 1/8, 1/16, ..., 3/2, 3/4, 3/8, ..., 5/2, 5/4, 5/8, ...
▪ numbers that cannot be represented with a finite number of binary
digits
▪ 1/3, 1/5, 1/6, 1/7, 1/9, 1/10, ..., 2/3, 2/5, 2/7, ...
▪ also obvious: if a number is not a decimal fraction (cannot be
represented with a finite number of digits after the decimal point)
then it cannot represented as a binary number with a finite
number of digits
© ZPR-FER-UNIZG Introduction to Programming 66
Conversion of decimal fraction to binary fraction
▪ 3/10 = 0.310 = ?2 . 0 1 0 0 1 1 0 0 1

0.3 ∙ 2 = 0.6

0.6 ∙ 2 = 1.2

0.2 ∙ 2 = 0.4

0.4 ∙ 2 = 0.8

0.8 ∙ 2 = 1.6

0.6 ∙ 2 = 1.2

0.2 ∙ 2 = 0.4
...
until a satisfactory precision is reached

© ZPR-FER-UNIZG Introduction to Programming 67


Multiplication of a binary number by the powers
of 2
▪ the binary number is multiplied by the power of 2 such that the
binary point moves the corresponding number of places right or
left, depending on whether the sign of the power is positive or
negative
▪ Primjer:
▪ 111.000 ∙ 22 = 11100.0
▪ 0001.101 ∙ 2-3 = 0.001101

© ZPR-FER-UNIZG Introduction to Programming 68


Representation of very large and very small
numbers
▪ How do engineers and scientists represent very large and very
small numbers?
▪ What is the average distance between Neptune and Sun?
▪ 4503930000000 m
▪ What is the mass of the electron?
▪ 0.000000000000000000000000000000910938188 kg
▪ too many digits (zeros) are consumed just to express the magnitude
▪ that is why scientific notation is used: the decimal number with
one digit in front of the decimal point, multiplied by the
corresponding power of 10 (because the radix is 10)
▪ 4.50393 ∙ 1012
power or
mantissa exponent
▪ 9.10938188 ∙ 10-31
© ZPR-FER-UNIZG Introduction to Programming 69
Representation of very large and very small
binary numbers
▪ Similarly, a binary fraction can be represented as a binary number
with one binary digit in front of the binary point, multiplied by the
corresponding power of 2 (since the radix is 2)
▪ A number in this form is said to be normalized. E.g.
101.11 = 1.0111∙22
0.000000000000010011 = 1.0011∙2-14
binary exponent
binary
(power)
mantissa
▪ Number normalization allows representing very large and very
small binary numbers, always in the same form, without using a
large number of zeros

© ZPR-FER-UNIZG Introduction to Programming 70


Representation of fractions in the computer
▪ how is data type float stored in a computer register?
▪ fractions are stored in the computer in a normalized binary
format
▪ of course, only fractions that can be represented as binary numbers
with acceptable number of binary digits
▪ how exactly to store a normalized binary number in a computer
register?
▪ The IEEE 754 standard prescribes how to store fractions
▪ IEEE 754 single precision
▪ IEEE 754 double precision

IEEE - Institute of Electrical and Electronics Engineers

© ZPR-FER-UNIZG Introduction to Programming 71


Single precision fractions
▪ IEEE 754 - single precision
▪ most commonly used to represent data type float
▪ the binary fraction, normalized, is stored in a total of 32 bits (4
bytes) in the following form:
31 30 23 22 0
S E – exponent M - mantissa without the leading bit

▪ 1 bit to store the sign of the number


▪ the bit itself determines the sign of the number (0 positive, 1 negative)
▪ 8 bits to store the exponent
▪ a positive or negative binary exponent (BE) is mapped to an always
positive exponent (E)
▪ 23 bits to store the mantissa without the leading bit
▪ storing the first bit (which is always 1) is unnecessary
© ZPR-FER-UNIZG Introduction to Programming 72
Single precision fractions
31 30 23 22 0
S E - exponent M - mantissa without the leading bit

▪ sign S: the most significant bit


▪ 1 if it is a negative number
▪ 0 if it is a positive number
▪ exponent E:
▪ range of binary exponent BE ∈ [-126, 127]
▪ to avoid representing negative exponents, a exponent E is stored instead
of BE
▪ range of exponent: E ∈ [0, 255], E = BE + 127  BE ∈ [-126, 127]
▪ E = 0 i E = 255 are used for special cases (explained later)
▪ mantissa M:
▪ the leading bit of the mantissa is not stored (1 in front of the binary
point)
© ZPR-FER-UNIZG Introduction to Programming 73
The first bit of the mantissa is implicitly
determined
▪ if the whole mantissa is to be stored in 23 bits
▪ up to 22 binary digits can be stored behind the binary point
22 0
1x x x x x x x x x x x x x x x x x x x x x x
.
▪ note: 1 is the only digit that can appear in front of a binary point in a
normalized number (except in number zero). One bit is consumed
unnecessarily because its value is implicitly known
▪ therefore, the leading bit (hidden bit) will not be stored
22 0
the hidden bit 1 x x x x x x x x x x x x x x x x x x x x x x x
.
▪ up to 23 binary digits can be stored behind the binary point
▪ the precision is increased

© ZPR-FER-UNIZG Introduction to Programming 74


Example
▪ Determine the contents of the register that stores the number 5.75
according to IEEE 754, single precision. Express the contents of the
register in binary and hexadecimal numbering systems
1. Determine the sign bit: the number is positive, therefore S = 0
2. Calculate the binary fraction and normalize the number based on
the decimal fraction
5.7510 = 101.112 = 1.01112∙22
3. Calculate the exponent and express it in binary form, in 8 bits
E = 210 + 12710 = 12910 = 1000 00012
4. Store the sign, exponent and mantissa (without the leading bit) in
the register
31 30 23 22 0
0 10000001 01110000000000000000000
S E - exponent M - mantissa without the leading bit
40 B8 00 0016
© ZPR-FER-UNIZG Introduction to Programming 75
Example
▪ 2.0
S = 0
102∙20 = 1.02∙21
BE = 1, E = 1 + 127 = 12810 = 100000002
M = 1.000 0000 ... 00002
0100 0000 0000 0000 ... 00002 = 4000 000016

▪ - 2.0
S = 1
everything else is the same as for 2.0
1100 0000 0000 0000 ... 00002 = C000 000016

© ZPR-FER-UNIZG Introduction to Programming 76


Example
▪ 4.0
S = 0
1002∙20 = 1.02∙22
BE = 2, E = 2 + 127 = 12910 = 100000012
M = 1.000 0000 ... 00002
0100 0000 1000 0000 ... 00002 = 4080 000016

▪ 6.0
S = 0
1102∙20 = 1.102∙22
BE = 2, E = 2 + 127 = 12910 = 100000012
M = 1.100 0000 ... 00002
0100 0000 1100 0000 ... 00002 = 40C0 000016

© ZPR-FER-UNIZG Introduction to Programming 77


Example
▪ 1.0
S = 0
12∙20 = 1.02∙20
BE = 0, E = 0 + 127 = 12710 = 011111112
M = 1.000 0000 ... 00002
0011 1111 1000 0000 ... 00002 = 3F80 000016

▪ 0.75
S = 0
0.112∙20 = 1.12∙2-1
BE = -1, E = -1 + 127 = 12610 = 011111102
M = 1.100 0000 ... 00002
0011 1111 0100 0000 ... 00002 = 3F40 000016

© ZPR-FER-UNIZG Introduction to Programming 78


Exercise calculator
▪ A website with a good calculator for exercising fractions

http://babbage.cs.qc.cuny.edu/IEEE-754/

© ZPR-FER-UNIZG Introduction to Programming 79


Special cases: representation of 0
▪ the leading digit (bit) of the normalized number in binary form is
always 1, except in the case of real number 0. Therefore, a special
rule is used in the IEEE 754 standard:
▪ when E = 0 and all mantissa bits are set to 0, it is a representation of
0 (then the leading bit is not considered to be implicitly 1)
▪ given that the sign bit can be set to 0 or 1, it is possible to represent
a "positive" and a "negative" zero, ie.+0 i -0
▪ 00 00 00 00 0016 → +0
▪ 80 00 00 00 0016 → -0
▪ in relational expressions, these two values are considered equal
float x = 0.f, y = -0.f;
printf("x=%f, y=%f\n", x, y); x=0.000000, y=-0.000000
if (x == y) printf("x is equal to y"); x is equal to y

© ZPR-FER-UNIZG Introduction to Programming 80


Special cases: denormalized number
▪ when E = 0 and there are mantissa bits other than 0, it is a
"denormalized" number
▪ the leading bit is implicitly set to 0
▪ the value of the binary exponent (BE) is fixed at -126 (the expression
BE = E - 127 is not used)
▪ allows even smaller numbers to be represented, but with reduced
precision
▪ therefore, avoid - use a more precise type
0000 0000 0110 0000 0000 0000 0000 0000
→ 0.11 ∙ 2-126

0000 0000 0000 0000 0000 0000 0000 0110


→ 0.000 0000 0000 0000 0000 0110 ∙ 2-126
→ 0.11 ∙ 2-146

© ZPR-FER-UNIZG Introduction to Programming 81


Special cases: representation of +∞ and −∞
▪ when E = 255 and all bits of the mantissa are set to 0, it the vaue
if implicitly +∞ ili −∞, depending on the sign bit
0111 1111 1000 0000 0000 0000 0000 0000 → +∞
1111 1111 1000 0000 0000 0000 0000 0000 → -∞
▪ those values can be obtained e.g.
▪ by dividing by zero in the floating point domain
▪ by exceeding the maximum number that can be represented
float x = 1.f / 0.f;
float y = -1.f / 0.f;
float z = 3.e38f * 2.f;
printf("%f %f %f", x, y, z);

inf -inf inf

© ZPR-FER-UNIZG Introduction to Programming 82


Special cases: representation of "not-a-number"
(NaN)
▪ If E = 255 and there are mantissa bits other than 0, this is an
undefined value or a value that cannot be represented (NaN - Not
a Number), i.e. it is not a valid representation of a number
▪ the sign bit has no meaning
▪ NaN is the consequence of performing an operation whose result is
undefined or when an error occurred during the operation, e.g.
float x = 1.f / 0.f + -1.f / 0.f;
float y = 0.f / 0.f;
float z = -1.f / 0.f * 0.f;
float w = x * 0.f;
printf("%f %f %f %f\n", x, y, z, w);

nan nan nan nan

x → 1111 1111 1100 0000 0000 0000 0000 0000


© ZPR-FER-UNIZG Introduction to Programming 83
Single precision range
▪ The smallest normalized positive number that can be represented
is:
1.000 0000 0000 0000 0000 00002 ∙ 2-126  1.17  10-38
▪ The smallest denormalized positive number that can be
represented is:
0.000 0000 0000 0000 0000 00012 ∙ 2-126
= 1 ∙ 2-149  1.4  10-45
▪ The largest number that can be represented is:
1.111 1111 1111 1111 1111 11112 ∙ 2127
 1 ∙ 2128  3.4  1038

© ZPR-FER-UNIZG Introduction to Programming 84


Single precision range

-3.4  1038 -1.4  10-45 +1.4  10-45 +3.4  1038


-1.17  10-38 0 +1.17  10-38

Invalid
Invalid Invalid
range
range range
Range of
denormalized
numbers

Range of
normalized
numbers

© ZPR-FER-UNIZG Introduction to Programming 85


Representation of integers in the computer
(reminder)
▪ A finite number of different numbers can be represented in the
registers with a finite number of bits
▪ How many different integers can be represented in a register of n
bits?
▪ 2n different integers

▪ A set of integers Z is infinite - it is not possible to represent all


numbers in a set Z, but
▪ to accurately represent all integers from the interval [0, 2n-1]or
from interval [-(2n-1), 2n-1 - 1] a register of n bits is sufficient

© ZPR-FER-UNIZG Introduction to Programming 86


Representation of fractions in the computer
▪ How many bits should a register have in which all fractions from
the interval [-1.0, 1.0] can be represented accurately?
▪ there are infinitely many numbers in the interval
[-1.0, 1.0]  = 
▪ therefore, it takes infinite number of bits
▪ Just a finite subset of fractions from some interval [-a, a] can be
accurately represented in a register with a finite number of bits.
Other fractions from this interval can only be stored as their
approximate values

© ZPR-FER-UNIZG Introduction to Programming 87


Representation of fractions in a computer
▪ Why can't all all fractions, although they have a finite number of
decimal digits behind the decimal point, be represented with a
finite number of bits?
▪ because an equivalent binary fraction can have an infinite number
of binary digits
▪ 0.310 = 0.010011001100110011001 ... 2
▪ because a binary number may have too many digits relative to the
number of bits available for storage. Eg. for single precision:
▪ 4194304.125=1.00000000000000000000000012∙222
▪ the number has too many mantis digits to be represented in IEEE 754
single precision format without error
▪ the same number can be represented exactly in the IEEE 754 double
precision format (explained later)

© ZPR-FER-UNIZG Introduction to Programming 88


How many different fractions can be represented
▪ For IEEE 754 - single precision
▪ for each E ∈ [0, 254]
▪ there are 223 different mantissas
▪ there are 2 possibe signs
▪ in total, 255 ∙ 223 ∙ 2 = 4 278 190 080 different fractions
▪ with E = 255, it is additionally possible to represent +∞, -∞ i NaN

▪ 4.3 ∙ 109 different fractions from intervals [-3.4 ∙ 1038, -1.4 ∙ 10-45] 
[1.4 ∙ 10-45, 3.4 ∙ 1038] can be represented without error, plus zero
▪ other (infinitely many) fractions from these intervals, can be
represented with approximate values (with greater or lesser error)
▪ real numbers outside the specified intervals cannot be represented at
all

© ZPR-FER-UNIZG Introduction to Programming 89


Precision
▪ Precision is a property that depends on the amount of
information used to represent the number.
▪ Greater precision implies:
▪ more different numbers can be represented
▪ the numbers are "closer" to one another (higher resolution)
▪ the largest possible error in representing the number is reduced

▪ Not to be confused with accuracy

© ZPR-FER-UNIZG Introduction to Programming 90


Errors when representing fractions
▪ x – the fraction to be stored in the register
▪ x* - actually stored approximate value of x
▪ Absolute error α
α = |x* - x|
▪ Relative error ρ
ρ = α / |x|

▪ Example:
▪ instead of the required value x = 100.57, actually stored value is
x* = 100.625
α = |100.625 - 100.57| = 0.055
ρ = 0.055 / |100.57| = 0.000546

© ZPR-FER-UNIZG Introduction to Programming 91


Errors when representing fractions

▪ The largest possible relative error depends on the number of bits


of the mantissa
▪ For IEEE 754 single precision:
ρ ≤ 2-24  6 ∙ 10-8

▪ The largest possible absolute error depends on the number of bits


of the mantissa and the actual number x
▪ For IEEE 754 single precision:
α ≤ 2-24 ∙ x   6 ∙ 10-8 ∙ x 

© ZPR-FER-UNIZG Introduction to Programming 92


Example
▪ The largest absolute error that can be expected with single
precision when storing the fraction 332.3452:
α ≤ 6 ∙ 10-8 ∙ |332.3452|  2 ∙ 10-5

float f1 = 332.3452f;
printf("%19.15f", f1);

▪ expected value: 332.3452 ± 2 ∙ 10-5

▪ actual value: 332.345214843750000

▪ indeed, the absolute error is 1.484375 ∙ 10-5, which is less than


2 ∙ 10-5

© ZPR-FER-UNIZG Introduction to Programming 93


Example
▪ The largest absolute error that can be expected with single
precision when storing the fraction 0.7:
α ≤ 6 ∙ 10-8 ∙ |0.7|  4.2 ∙ 10-8

float f2 = 0.7f;
printf("%19.15f", f2);

▪ expected value: 0.7 ± 4.2 ∙ 10-8

▪ actual value 0.699999988079071

▪ indeed, the absolute error is 1.1920929 ∙ 10-8, which is less than


4.2 ∙ 10-8

© ZPR-FER-UNIZG Introduction to Programming 94


Floating point data types

Data types double and long double

© ZPR-FER-UNIZG Introduction to Programming 95


Data type double
▪ an example of a definition of a variable of type double
double temperature;

▪ examples of constants of type double


▪ similar to float constants, but no f or F at the end
2. = 2.0
-2.34 = -2.34
-1.34e5 = -1.34 ∙ 105
9.1093E-31 = 9.1093 ∙ 10-31

▪ gcc and architecture x86_64


▪ IEEE 754 double precision is used (8 bytes)
▪ storage principles are the same as those of IEEE 754 single precision.
The difference is only in the increased number of bits used for the
exponent and mantissa
© ZPR-FER-UNIZG Introduction to Programming 96
Double precision fractions
▪ IEEE 754 - double precision
▪ most commonly used to represent values of type double
▪ binary fraction, in normalized form, is stored in a total of 64 bits (8
bytes) in the following form:
63 62 52 51 0
S E - exponent M - mantissa without leading bit

▪ 1 bit to store the sign of the number


▪ the bit content itself determines the sign of the number
▪ 11 bits to store the exponent
▪ positive or negative binary exponent (BE) mapped to an always positive
exponent (E)
▪ 52 bits to store mantissa bits without the leading bit
▪ storing the first bit (which is always 1) is unnecessary
© ZPR-FER-UNIZG Introduction to Programming 97
Double precision fractions
63 62 52 51 0
S E - exponent M - mantissa without leading bit
▪ sign S: the most significant bit is
▪ 1 if it is a negative number
▪ 0 if it is a positive number
▪ exponent E:
▪ range of binary exponent BE ∈ [-1022, 1023]
▪ to avoid representing negative exponents, exponent E is stored instead
of BE
▪ range of exponent: E ∈ [0, 2047], E = BE + 1023  BE ∈ [-1022, 1023]
▪ E = 0 and E = 2047 are used for special cases
▪ mantissa M:
▪ the leading bit of the normalized mantissa is not stored

© ZPR-FER-UNIZG Introduction to Programming 98


Double precision fractions
▪ Special cases
▪ when E = 0 and all mantissa bits are set to 0, it is a representation of
zero (then the leading bit is not considered to be implicitly 1)
▪ when E = 0 and there are mantissa bits other than 0, it is a
"denormalized" number
▪ when E = 2047 and all bits of the mantissa are set to 0, it is the
representation of +∞ ili −∞, depending on the sign bit
▪ when E = 204 and there are mantissa bits that are not 0, it is an
undefined value or a value that cannot be represented (NaN - Not a
Number), that is, it is not a valid representation of the number

© ZPR-FER-UNIZG Introduction to Programming 99


Range of double precision fractions
▪ Increase in the number of bits used for the exponent increases the
range
▪ The smallest normalized positive number that can be represented is:
1.000...0002 ∙ 2-1022  2.2  10-308
▪ The smallest denormalized positive number that can be represented is :
0.000...00012 ∙ 2-1022
= 1 ∙ 2-1074  4.9  10-324
▪ The largest number that can be represented is:
1.111...11112 ∙ 21023
 1 ∙ 21024  1.8  10308

© ZPR-FER-UNIZG Introduction to Programming 100


Range of real numbers - double precision

-1.8  10308 -4.9  10-324 +4.9  10-324 +1.8  10308


-2.2  10-308 0 +2.2  10-308

Unable to
Unable to Unable to
represent
represent represent
Possible
representation of
denormalized numbers

Possible
representation of
ormalized numbers

© ZPR-FER-UNIZG Introduction to Programming 101


IEEE 754 double precision errors
▪ Increased precision, i.e. reduction of the largest possible relative
error, is the result of using a larger number of mantissa bits
▪ The largest possible relative error
▪ For IEEE 754 double precision:
ρ ≤ 2-53  1.1 ∙ 10-16

▪ The biggest possible absolute error


▪ For IEEE 754 double precision:
α ≤ 2-53 ∙ x   1.1 ∙ 10-16 ∙ x 

© ZPR-FER-UNIZG Introduction to Programming 102


Example
▪ The largest absolute error that can be expected with double
precision when storing a real number 0.7:
α ≤ 1.1 ∙ 10-16 ∙ 0.7   7.7 ∙ 10-17

double f = 0.7;
printf("%19.17f", f);

▪ it is expected that the number to be stored is 0.7 ± 7.7 ∙ 10-17

0.69999999999999996

▪ Indeed, absolute mistake is 4.0 ∙ 10-17, which is less than 7.7 ∙


10-17

© ZPR-FER-UNIZG Introduction to Programming 103


Real numbers of extended precision
▪ IEEE 754 - extended precision
▪ the number and arrangement of bits are not prescribed by the
standard but depend on the implementation
▪ gcc implements increased precision using 80 bits, using 12 bytes for
storage
▪ 15 bits for exponent, 63 bits for mantissa
▪ E = BE + 16383
▪ used to store the data type long double
▪ range  ± [3.65 ∙ 10−4951, 1.19 ∙ 104932]
▪ the largest relative error  2-64  5.4 ∙ 10−20

© ZPR-FER-UNIZG Introduction to Programming 104


Data type long double
▪ an example of the definition of long double variable
long double temperature;

▪ examples of long double constants


▪ same as constants of type double, but with the suffix l or L
2.L = 2.0
-2.34l = -2.34
-1.34e5L = -1.34 ∙ 105
9.1093E-31l = 9.1093 ∙ 10-31

▪ gcc and architecture x86_64


▪ using IEEE 754 extended precision (80 bits)

© ZPR-FER-UNIZG Introduction to Programming 105


Conversion specifications for scanf i printf
Type spec.
float %f
double %lf
long double %Lf

▪ Example
float x;
double y;
long double z;
scanf("%f %lf %Lf", &x, &y, &z);
printf("%5.2f %.3lf %Lf", x, y, z);
Note: %Lf does not work for
1.333 -15 6.1e8 the gcc compiler on Windows
1.33 -15.000 610000000.000000

© ZPR-FER-UNIZG Introduction to Programming 106


Numerical errors
▪ Some decimal numbers cannot be represented using a finite
number of binary digits
▪ Example: float f = 0.3f;
printf("%18.16f", f);
0.3000000119209290

0011 1110 1001 1001 1001 1001 1001 1001 1001 1001 ...
0011 1110 1001 1001 1001 1001 1001 1010 (rounded to the nearest value)

▪ Some real numbers have a finite number of, but still "too many"
binary digits
float f = 4194304.125f;
▪ Example:
printf("%14.6f", f);
4194304.000000
0100 1010 1000 0000 0000 0000 0000 0000 01
0100 1010 1000 0000 0000 0000 0000 0000 (rounded to a nearest value)
© ZPR-FER-UNIZG Introduction to Programming 107
Numerical errors
▪ Calculating with numbers of significantly different order of
magnitude can lead to a numerical error
▪ Example float f = 6000000.0f; float smallf = 0.25f;
f = f + smallf;
f = f + smallf;
f = f + smallf;
f = f + smallf;
printf("%f ", f); 6000000.000000

▪ better: float smallSum = 0.f;


smallSum = smallSum + smallf;
smallSum = smallSum + smallf;
smallSum = smallSum + smallf;
smallSum = smallSum + smallf
f = f + smallSum;
printf("%f ", f); 6000001.000000

© ZPR-FER-UNIZG Introduction to Programming 108


Numerical errors
▪ Caution is required when comparing real values
▪ are the two numbers "equal"
▪ perhaps some tolerance should be considered
▪ when did the loop control variable reach the limit?

© ZPR-FER-UNIZG Introduction to Programming 109


Example
▪ Enter a positive integer n (no need to check Enter n > 2
0.500000000
that the correct number is loaded). Then print 0.600000000
real numbers from 0.5 to n in steps of 0.1. Use 0.700000000
the conversion specification %12.9f to print real 0.800000000
numbers. 0.900000000
1.000000000
1.100000000
1.200000000
1.300000000
1.400000000
1.500000000
1.600000000
1.700000000
1.800000000
1.900000000
2.000000000

© ZPR-FER-UNIZG Introduction to Programming 110


Example
#include <stdio.h> Enter n > 2
0.500000000
int main(void) {
0.600000024
int n;
0.700000048
float x; 0.800000072
printf("Enter n > "); 0.900000095
scanf("%d", &n); 1.000000119
for (x = 0.5f; x <= n; x = x + 0.1f) { 1.100000143
printf("%12.9f\n", x); 1.200000167
} 1.300000191
1.400000215
}
1.500000238
1.600000262
▪ why are exact values not printed? 1.700000286
1.800000310
▪ not even for 1.0 of 1.5? 1.900000334

▪ why the loop stopped too soon?

© ZPR-FER-UNIZG Introduction to Programming 111


Example
▪ Improvement: Enter n > 2
0.500000000
▪ allow a certain tolerance when comparing loop 0.600000024
stopping numbers/conditions 0.700000048
0.800000072
#include <stdio.h> 0.900000095
#define TOLER 0.00001f 1.000000119
1.100000143
int main(void) { 1.200000167
int n; 1.300000191
float x; 1.400000215
printf("Enter n > "); 1.500000238
scanf("%d", &n); 1.600000262
1.700000286
for (x = 0.5f; x <= n + TOLER; x = x + 0.1f) {
1.800000310
printf("%12.9f\n", x);
1.900000334
}
2.000000238
}

© ZPR-FER-UNIZG Introduction to Programming 112


Example
▪ Improvement: Enter n > 2
0.500000000
▪ where possible, use integers 0.600000024
▪ there are no numerical errors in integer 0.699999988
operations 0.800000012
0.899999976
#include <stdio.h> 1.000000000
int main(void) { 1.100000024
int n, counter; 1.200000048
float x; 1.299999952
printf("Enter n > "); 1.399999976
scanf("%d", &n); 1.500000000
1.600000024
for (counter = 5; 1.700000048
counter <= n * 10; 1.799999952
counter = counter + 1) { 1.899999976
x = counter / 10.f; 2.000000000
printf("%12.9f\n", x);
}
}

© ZPR-FER-UNIZG Introduction to Programming 113


Example
▪ Explain the differences in the results of the following operations:
double x;
x = 0.1f + 0.1f;
printf("%20.18f\n", x);
x = 0.1f + 0.1;
printf("%20.18f\n", x);
x = 0.1 + 0.1;
printf("%20.18f\n", x);

0.200000002980232240
0.200000001490116120
0.200000000000000010

© ZPR-FER-UNIZG Introduction to Programming 114


Alternative names to existing datatypes

typedef

© ZPR-FER-UNIZG Introduction to Programming 115


Alternative names to existing datatypes
▪ creating an alias (synonym) for an existing data type
▪ improving the comprehensibility (documentation) of program code
▪ improving the portability of program code
▪ simplifying variable definition commands
▪ general statement form
typedef existingTypeName newTypeName;
▪ the statement must precede (not necessarily directly) the
statements that will use the new type name
▪ Example:
int main(void) {
typedef int integer_t; This is an example of superfluous typedefs!
typedef float real_t;
integer_t m, n;
...
real_t x, y;

© ZPR-FER-UNIZG Introduction to Programming 116


Improving comprehensibility (documentation)
▪ add an alias to the existing data type
▪ further describes the domain of variable values
typedef unsigned int id_t; it is assumed that id has no more than 9 digits
and that 4 bytes are used for int storage
typedef unsigned char gradeNumeric_t; convention (not a rule): add _t to the end of the name
typedef char gradeLetter_t;
...
id_t idStud1 = 123456789;
gradeNumeric_t gradesOfGroup[10] = {1, 1, 5, 4, 2, 1, 1, 4, 3, 5};
gradeLetter_t worstLetterGrade = 'F';

it is more understandable than


unsigned int idStud1 = 123456789;
unsigned char gradesOfGroup[10] = {1, 1, 5, 4, 2, 1, 1, 4, 3, 5};
char worstLetterGrade = 'F';

© ZPR-FER-UNIZG Introduction to Programming 117


Improving portability
▪ if the previous program is to be transferred to a platform on
which the data type int is stored in only two bytes [0, 65 535],
while long int is stored in 4 bytes[0, 4 294 967 295]
▪ instead of unsigned int for all ids you will need to use unsigned long
int
▪ if the program used an alternate name of type id_t, it is enough to
change the definition of the type in a single place (!) and compile
the program on a new platform
▪ otherwise, the type in the definition of all variables in which the id is
stored should be changed
...
typedef unsigned int id_t;
typedef unsigned long int id_t;
...

© ZPR-FER-UNIZG Introduction to Programming 118


Portability - built-in type definitions
▪ some type aliases are predefined
▪ the sizeof operator (which will be explained in more detail later)
returns the size of the object (e.g. variables) expressed in bytes
▪ it is an integer that can have different ranges on different platforms
and be defined based on different basic types
▪ e.g. unsigned int or unsigned long or unsigned long long
▪ in <stdlib.h> a size_t type is defined which in most cases can be
safely used as if it were an unsigned int type
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
size_t size;
size = sizeof(n);
printf("%u", size);
... 4

© ZPR-FER-UNIZG Introduction to Programming 119


Portability - built-in type definitions
▪ the number of bytes used to store integer data types in C is not
prescribed by the standard
▪ ranges vary in different compilers and architectures
▪ if it is necessary to fix precision and range, regardless of the
translator and architecture:
#include <stdio.h>
#include <stdint.h>
int main(void) {
int m; the size (hence the range) depends on the compiler
int8_t n1; exactly 1 byte, signed
int16_t n2; exactly 2 bytes, signed
int32_t n4; exactly 4 bytes, signed
int64_t n8; exactly 8 bytes, signed
uint8_t un1; exactly 1 bytes, unsigned
uint16_t un2; exactly 2 bytes, unsigned
...
© ZPR-FER-UNIZG Introduction to Programming 120
Simplify definition statements
▪ the type definition is often used with structures
using a structure declaration: using the type definition:

struct date_s { typedef struct {


int day; int day;
int month; int month;
int year; int year;
}; } date_t;
struct interval_s { typedef struct {
struct date_s date_od; date_t date_od;
struct date_s date_do; date_t date_do;
}; } interval_t;
struct interval_s winter_term = interval_t winter_term =
{{11, 2, 2019}, {22, 2, 2019}}; {{11, 2, 2019}, {22, 2, 2019}};
struct interval_s summer_term = interval_t summer_term =
{{17, 6, 2019}, {3, 7, 2019}}; {{17, 6, 2019}, {3, 7, 2019}};

© ZPR-FER-UNIZG Introduction to Programming 121


Expressions with different data types

Implicit data type conversion

© ZPR-FER-UNIZG Introduction to Programming 122


Expressions with different data types
▪ What is the result of expression i + f
int i;
▪ 2. + 2.99  4.99 or 2 + 2  4 float f;
▪ What is the result of expression i >= f i = 2;
f = 2.99f;
▪ 2. >= 2.99  0 or 2 >= 2  1

▪ When operands are of a different type, an implicit (automatic)


conversion (conversion) of a "less important" type of operand
into a "more important" type of operands participating in the
operation is performed before the operation is performed.
▪ In the examples shown, before the operation is performed, the
value contained in the variable i (int is "less important") is
converted to the value 2.f (float is the "more important" type)
▪ in doing so the type and content of the variable i remains
unchanged.
© ZPR-FER-UNIZG Introduction to Programming 123
Implicit data type conversion
▪ Implicit conversion of data types in arithmetic and relational
expressions is performed according to one of the following 6 rules. The
first rule that can be applied to a specific case should be used!
1. If one of the operands is of the type long double, the other operand is converted
to long double
2. If one of the operands is of the type double, the other operand is converted to
double
3. If one of the operands is of the type float, p the other operand is converted to
float
4. If one of the operands is of the type long long, the other operand is converted to
long long
5. If one of the operands is of the type long, the other operand is converted to long
6. Operands od type _Bool, short and char are converted to int

▪ When unsigned types appear in expressions, the conversion rules are


more complex. Therefore, it will not be considered here.
© ZPR-FER-UNIZG Introduction to Programming 124
Example
_Bool b; char c; short s;
int i; long l; long long ll;
float f; double d; long double ld;

Type conversion before performing the According


Expression
operation to rule
ld * i content of i → long double 1.
c % i content of c → int 6.
s / f content of s → float 3.
l % i content of i → long 5.
d + c content of c → double 2.
s - c content of s → int, content of c → int 6.
b == ll sadrcontent ofžaj b → long long 4.

© ZPR-FER-UNIZG Introduction to Programming 125


Converting data types in assignment operations
▪ In an assignment operation, the data to the right of the
assignment operator is converted to the data type to the left of
the operator
▪ Example: int i;
char c = '2';
long double ld;
i = 1.75;
ld = i + c;

▪ after variable initialization


▪ the value of the constant of type double (1.75) is converted to a value
of type int (1) and associated with the variable i
▪ the value of variable c of type char (50 in one byte) is converted to int
(50 in four bytes), the result of type int (51) is calculated, converted to
long double (51.L) and stored in variable ld
© ZPR-FER-UNIZG Introduction to Programming 126
Example

char c; res = (c + s) / l – i / f + d
short int s;
int i; int int float
long l;
int float
float f;
double d; long
long long res;
long

float

float

double

long long double

© ZPR-FER-UNIZG Introduction to Programming 127


Explicit data type conversion
▪ General form of explicit conversion (cast operator):
(data_type) expression
▪ Example: to realistically divide two integer variables, a clumsy auxiliary
multiplication operation with a real constant was used so far
int i, j;
float x;
...
x = 1.f * i / j;

▪ cast operator provides a much better solution:


x = (float) i / j;

▪ analyze why the following is incorrect:


x = (float) (i / j);

© ZPR-FER-UNIZG Introduction to Programming 128


Explicit data type conversion
▪ The cast operator should not be applied unnecessarily
▪ Instead of using an operator to explicitly convert a type over a
constant, use a constant of the appropriate type

▪ Example: if you want to store the value ⅓ in a real variable x


float x;
x = 1 / 3; incorrect! A value of 0.0 will be stored in the variable x
x = (float) 1 / 3; unnecessary! No need for cast operator
x = 1.f / 3; correct
x = 1 / 3.f; correct
x = 1.f / 3.f; correct

© ZPR-FER-UNIZG Introduction to Programming 129


Data type conversion - possible losses
▪ It should be noted that when converting one type of data to
another, a smaller or larger part of the information may be "lost"
int i;
float x;
i = 2.99999f;
x = 2147483638;
printf("%d\n%f", i, x);

2 .

2147483648.000000

▪ when converting values, decimals 0.99999 are "lost"


▪ the float type has too few mantissa bits to accurately represent
values. The closest number that can be represented is greater than
2147483638 by 10

© ZPR-FER-UNIZG Introduction to Programming 130


Example
int i = 2147000000;
float x;
x = i;
printf("%f\n", x);
x = x + 1.f;
printf("%f\n", x);

2147000064.000000
2147000064.000000

▪ in the assignment operation x = i, the integer value 2147000000 was


converted to the float data type. The closest real value that can be
represented in standard precision is 2147000064.0
▪ during the summation of the values 2147000064.0 and 1.0, a numerical
error occurred due to the summation of a very large and a very small
value, the result of the summation is 2147000064.0
▪ both errors are due to the limited number of mantissa bits

© ZPR-FER-UNIZG Introduction to Programming 131


Example
double d1 = 123456789.;
double d2 = 1.e40;
float f1 = d1;
float f2 = d2;
printf("%lf\n%f\n"
"%lf\n%f",
d1, f1,
d2, f2);

123456789.000000
123456792.000000
10000000000000000303786028427003666890752.000000
inf

▪ insufficient mantissa bits in f1 for accurate storage of number 123456789


▪ insufficient mantissa bits in d2 for accurate storage of number 1 ∙ 10 40
▪ insufficient range (exponent) in f2 to store the number 1 ∙ 1040
© ZPR-FER-UNIZG Introduction to Programming 132
Examples
▪ Find the results (type and value) of:
1. 3 / 2 * 2
2. 3 / 2 * 2.
3. 3 / 2. * 2
4. 3 / (float)2 * 2
5. (double)3 / 2
6. (double)(3 / 2)
7. 2+0.5 * 4
8. (2 + 0.5) * 4
9. (int)(0.5 + 2) * 4
10. (float) ((int)1.5 + 2) / 4
11. (int)1.6 + (int)1.6
12. (int)(1.6 + 1.6)
© ZPR-FER-UNIZG Introduction to Programming 133
Introduction to programming - lectures

6. Operators

© ZPR-FER-UNIZG Introduction to programming 1


Operators: priority and associativity
OPERATOR ASOCIJATIVNOST

function call () [] . -> postfix ++ -- L→R


 Higher priority

! ~ sizeof address & indirection * prefix ++ -- unary + - R→L


(cast) R→L
arithmetical * / % L→R
binary + - L→R
<< >> L→R
< <= > >= L→R
== != L→R
bitwise & L→R
^ L→R
| L→R
Lower priority →

&& L→R
|| L→R
? : R→L
= *= /= %= += -= &= ^= |= <<= >>= R→L

operator , L→R

© ZPR-FER-UNIZG Introduction to programming 2


The same operator symbol for different
operations
▪ In the C, for some of the operator symbols, the same symbols are
used for different operations. In such cases, the type of operation
is determined based on the context in which the symbol is used
▪ e.g. the minus symbol is used for two different operations
int a = 3, b = 5, c, d;
c = b - 5; Subtraction, binary operator
d = -b; Negation, opposite sign

▪ for this reason, the symbols in the operator table, which have
different meanings depending on the context, are further described,
e.g.
▪ unary + -
▪ binary + -
▪ operator , (because the comma represents either a separator or an
operator, depending on the context)

© ZPR-FER-UNIZG Introduction to programming 3


Unary +, -
▪ Unary minus is used often
▪ The unary plus is embedded in the language mostly just for
symmetry
▪ does nothing but implicitly convert operands of type char, short,
or _Bool to type int
float x = 5.f, y = -2.f; Expression results:
-x -5, float
-x + -y -3, float
-x - -y -7, float
+ x 5, float (operator + has no effect here)

int n = -5;
char c = 'A'; Expression results:
+n -5, int (operator + has no effect here)
+c 65, int (type conversion only, char → int)

© ZPR-FER-UNIZG Introduction to programming 4


Bitwise operations
▪ Access to a single bit or group of bits
▪ operands must be integers!
▪ use: low-level programming (operating systems, drivers,
microcontrollers, low-level graphics, cryptography, programs in
which speed and memory are critical factors)
▪ compact data storage
▪ e.g. how to store 32 logical values with the smallest space
consumption? T F T F T T T T F F F T T F F T F F T F F F T F T T T F F F T T
_Bool data[32]; char data[32]; unsigned int data;
data[0] = 1; data[0] = 1; data = 0xAF1922E3;
data[1] = 0; data[1] = 0; 4 bytes. Each bit of the registry
data[2] = 1; data[2] = 1; stores one logical value.
... ...
data[31] = 1; data[31] = 1; Problem: how to access each
32 bytes 32 bytes individual logical value (bit)?

© ZPR-FER-UNIZG Introduction to programming 5


Bitwise operations
▪ Reminder: logical operators work with operands as whole
int a = 13, b = 7; Rezultati expressiona:
a && b 1, int
a || b 1, int
!a 0, int

▪ Bitwise operators act on the individual bits of the operands


int a = 13, b = 7; bitwise AND
a & b 5, int

Explanation:
0000 0000 0000 0000 0000 0000 0000 1101 2 = 1310
& 0000 0000 0000 0000 0000 0000 0000 0111 2 = 710
---------------------------------------
0000 0000 0000 0000 0000 0000 0000 0101 2 = 510

© ZPR-FER-UNIZG Introduction to programming 6


Bitwise OR, XOR i NOT
int a = 5, b = 19; bitwise OR
a | b 23, int
0000 0000 0000 0000 0000 0000 0000 0101 2 = 510
| 0000 0000 0000 0000 0000 0000 0001 0011 2 = 1910
---------------------------------------
= 0000 0000 0000 0000 0000 0000 0001 0111 2 = 2310

int a = 21, b = 19; bitwise XOR


a ^ b 6, int
0000 0000 0000 0000 0000 0000 0001 0101 2 = 2110
^ 0000 0000 0000 0000 0000 0000 0001 0011 2 = 1910
---------------------------------------
= 0000 0000 0000 0000 0000 0000 0000 0110 2 = 610

int a = 21; bitwise NOT


~a -22, int
~ 0000 0000 0000 0000 0000 0000 0001 0101 2 = 2110
= 1111 1111 1111 1111 1111 1111 1110 1010 2 = -2210

© ZPR-FER-UNIZG Introduction to programming 7


Right shift operator
▪ The right shift operator calculates the result by shifting the binary
content of the left operand to the right by the number of places
specified by the right operand
▪ The bits in the vacancies on the left are set:
▪ if the left operand is of type unsigned int: to zero
▪ if the left operand is of type signed int: depending on the value
of the first (sign) bit and the implementation, to zero or one
▪ therefore, for portability: for right shift operator, unsigned
int left operand should be used

© ZPR-FER-UNIZG Introduction to programming 8


Right shift operator
unsigned int a = 2147685213, b = 9; right shift operator
a >> b 4194697, unsigned int

1000 0000 0000 0011 0001 0011 0101 1101 2 = 214768521310


>> 9 0000 0000 0100 0000 0000 0001 1000 1001 2 = 419469710
the bits in the vacancies on the left are filled with zeros, regardless of the value of
the first bit of the left operand because the left operand is of type unsigned int

▪ numerical result of the operation a >> b corresponds to the result


of integer division a : 2b

© ZPR-FER-UNIZG Introduction to programming 9


Left shift operator
▪ Left shift operator calculates the result by shifting the binary
content of the left operand to the left by the number of places
specified by the right operand
▪ The bits in the vacancies on the right are always filled with zeros

int a = 4957, b = 9; left shift operator


a << b 2537984, int

0000 0000 0000 0000 0001 0011 0101 1101 2 = 495710


<< 9 0000 0000 0010 0110 1011 1010 0000 0000 2 = 253798410
the bits in the vacancies on the right are filled with zeros

▪ numerical result of the operation a << b corresponds to the result


of multiplication a · 2b

© ZPR-FER-UNIZG Introduction to programming 10


Setting individual bits
▪ Assuming the least significant bit is in position 0
Set jth bit of variable a to 1 (without affecting the other bits)
a = a | 0x1 << j;

Example: Set 5th bit of variable a to 1


a 0000 0000 0000 0000 0000 0001 1000 1001
0x1 << 5 0000 0000 0000 0000 0000 0000 0010 0000
a | 0x1 << 5 0000 0000 0000 0000 0000 0001 1010 1001

Set jth bit of variable a to 0 (without affecting the other bits)


a = a & ~(0x1 << j);

Example: Set 7th bit of variable a to 0


a 0000 0000 0000 0000 0000 0001 1000 1001
0x1 << 7 0000 0000 0000 0000 0000 0000 1000 0000
~(0x1 << 7) 1111 1111 1111 1111 1111 1111 0111 1111
a & ~(0x1 << 7) 0000 0000 0000 0000 0000 0001 0000 1001

© ZPR-FER-UNIZG Introduction to programming 11


Setting individual bits
Set jth bit of variable a to v (without affecting the other bits)
a = a | v << j; will not work (original bit can be 1, v can be 0)
a = a & ~(0x1 << j); ensure that bit is 0

© ZPR-FER-UNIZG Introduction to programming 12


Reading individual bits
▪ Assuming that the least significant bit is at position 0 and that
variable a of type unsigned int
Print 0 ili 1, depending on the jth bit of the variable a
printf("%d", a >> j & 0x1);

Example: print the 3rd bit of the variable a


a 0000 0000 0000 0000 0000 0001 1000 1001
a >> 3 0000 0000 0000 0000 0000 0000 0011 0001
0x1 0000 0000 0000 0000 0000 0000 0000 0001
a >> 3 & 0x1 0000 0000 0000 0000 0000 0000 0000 0001

Example: print the hexadecimal value of the group of 4 least significant bits of the
variable a
printf("%x", a & 0xF);

a 0000 0000 0000 0000 0000 0001 1000 1001


0xF 0000 0000 0000 0000 0000 0000 0000 1111
a & 0xF 0000 0000 0000 0000 0000 0000 0000 1001
© ZPR-FER-UNIZG Introduction to programming 13
Increment and decrement operators
▪ Increment: v = v + 1
▪ Unary operators ++ and --
▪ operand must be modifiable lvalue: a scalar variable, a scalar
member of an array or structure ...
▪ This operators cause side effects
▪ in addition to returning a result, it also changes the content of the
operand. Which operator have we met so far that also causes side
effects?
▪ There are prefix and postfix form of this operators. Assuming the
counter is a variable of scalar type:
Expressions with the prefix form of Expressions with postfix form of the
the operator operator
++counter counter++
--counter counter--
© ZPR-FER-UNIZG Introduction to programming 14
Prefix form
▪ the value of the operand is first increased/decreased (therefore,
the side effect occurs first), before the evaluation of the result
int a = 5, b;
b = ++a * 10; final result: a = 6, b = 60

▪ this is what happens:


▪ variable a increases by 1 (side effect of the operator ++)
▪ the result of the expression is calculated ++a (will be used in the rest of
the expression) = 6
▪ 6 * 10 is calculated and assigned to b
▪ the result of the assignment is 60 (which is not used furthermore)
b = ++a * 10; equal effect a = a + 1;
⇔ b = a * 10;

Everything said about the prefix / postfix form for the ++ operator also applies to the operator --

© ZPR-FER-UNIZG Introduction to programming 15


Postfix form
▪ The result of the expression is first evaluated based on the "old" value of the
operand, the operand is incremented/decremented later (it is not specified
when exactly, but no later than before the completion of the command in
which the expression is used)
int a = 5, b;
b = a++ * 10; final result: a = 6, b = 50

▪ this is what happens :


▪ the result of the expression a++ is calculated (will be used in the rest of the
expression) = 5
▪ immediately now or a bit later, but certainly before the command is
completed, the contents of the variable a is incremented
▪ 5 * 10 is calculated and assigned to b
▪ the result of the assignment is 50 (which is not used furthermore)

b = a++ * 10; equal effect b = a * 10;


a = a + 1;

© ZPR-FER-UNIZG Introduction to programming 16
When the prefix form == postfix form?
▪ Note: if the operator is used independently (not in more complex
expressions as in the previous examples), then there is no
difference between the action of the prefix and postfix form of
the operator
++a; equal effect a = a + 1;
a++; ⇔

▪ often, such a simple expression with increment/decrement


operators is used in loops with a predetermined number of
iterations, to increment or decrement the loop control variable

for (i = 1; i <= 10; ++i) { or i++, the effect is the same


...

© ZPR-FER-UNIZG Introduction to programming 17


Avoid undefined behavior
▪ Repeated use of a variable affected by an operator with a side
effect (within the same command) can lead to an undefined
result, i.e. a possible different result for different architectures
and compilers
int i = 5, res;
res = i * ++i;

▪ depending on whether the left or right operand is calculated first in


the multiplication operation (i or ++i) the result will be 30 ili 36.
Depending on what you actually want to achieve, it would be
correct to write one of following program segments:
++i;
res = i * i;

res = i * (i + 1);
++i;

© ZPR-FER-UNIZG Introduction to programming 18


Conditional operator
▪ The conditional operator is the (only) ternary operator (uses
three operands)
General form expression1 ? expression2 : expression3
▪ expression1 is evaluated
▪ if the result is the logical value true, expression2 s evaluated being
the overall result of the whole expression (expression3 is not
evaluated in this case!)
▪ otherwise expression3 is evaluated, being the overall result of the
whole expression (expression3 is not evaluated in this case!)
▪ Typical application: writing more compact program code
if (x >= 0.0) {
res = x; equal effect res = x >= 0.0 ? x : -x;
} else { ⇔
res = -x;
}
© ZPR-FER-UNIZG Introduction to programming 19
Conditional operator
▪ Pay special attention if the second or third expression contains
operators with side effects

int i = 5, j = 10, res;


res = i < j ? ++i : ++j; res=6, i=6, j=10 expression3 was not evaluated

int i = 5, j = 10, res;


res = i > j ? ++i : ++j; res=11, i=5, j=11 expression2 was not evaluated

© ZPR-FER-UNIZG Introduction to programming 20


Short circuit evaluation
▪ Operators with side effects should also be addressed in complex
logical conditions due to the short circuit evaluation
▪ short circuit evaluation is a property of a programming language
that calculates parts of a logical expression only until it is irrefutably
determined what the total result will be
int i = 5, j = 10, k = 15;
if (i > 5 && j == 10 && k < 15) ...
if (i > 4 || j == 10 || k < 15) ...

▪ if, for example, the first relational expression is evaluated as false (in
second expression true), the remaining relational expressions are
not evaluated
▪ Therefore, in the following example, the result may be unexpected if the
programmer is not aware that C is using short circuit evaluation.
int i = 5, j = 10, k = 15;
if (++i > 5 || ++j == 10 || ++k < 15) ... ++j and ++k will not be executed
© ZPR-FER-UNIZG Introduction to programming 21
Compound assignment operators
▪ compound assignment operators are used for abbreviated writing
of assignment expressions in which the new value of the left
operand (modifiable lvalue) is calculated based on its old value
using a binary arithmetic or bitwise operator
length = length + a; ⇔ length += a;

▪ in general, an assignment expression in which one of the binary


operators Ω is used (*, /, %, +, -, &, ^, |, <<, >>)
expression1 = expression1 Ω expression2;
it can be written using a compound assignment operator as:
expression1 Ω= expression2;

© ZPR-FER-UNIZG Introduction to programming 22


Compound assignment
▪ operators are more useful in cases when the left operand
(modifiable lvalue) is more complex (array or structure member,
etc.)
counter[index - LO_BOUND] = counter[index - LO_BOUND] + 1;

counter[index - LO_BOUND] += 1;

▪ Caution: in the application of this operator, special attention should


be paid to the priority of the operator
a *= b + 5; not the equal to a = a * b + 5;
▪ when determining the equivalent expression, it is best to visualize
the right side of the compound assignment as expression in
parentheses
a *= b + 5; is equal to a = a * (b + 5);

© ZPR-FER-UNIZG Introduction to programming 23


sizeof operator
General form sizeof(expression or type_name)

▪ The result of the operation is the number of bytes used to store the
operand
float a[10], x = 1.f;
double y = 2.;
char c = 'A';
sizeof(double) 8
sizeof(x) 4
sizeof(x + y) 8
sizeof(a) 40
sizeof('A' + 32) 4
sizeof(unsigned short int) 2
sizeof(0x100u) 4
sizeof(1LL) 8
sizeof(c) 1
sizeof(1.0L) 12

© ZPR-FER-UNIZG Introduction to programming 24


Comma operator
General form expression1, expression2

▪ expression1 is evaluated (the result is not used futhermore)


▪ expression2 is evaluated being the overall result of the whole
expression

▪ Illustration of the operation (meaningless example)


int i = 2, j = 5, k;
k = (++i, j = j * 2);
▪ ++i is evaluated, variable i becomes 3, result is not used
▪ j*2 is evaluated, 10 is assigned to j, result of this assignment (10) is
the overall result of the expression with comma operator
▪ 10 is assigned to k. The result is not used furthermore

© ZPR-FER-UNIZG Introduction to programming 25


Example
▪ Apply multiple comma operators in the same command
int i, j, k, m;
m = (i = 5, j = i + 2, k = i + 3);
▪ due to the associativity of the comma operator (L → R), this is
equivalent to
m = (((i = 5), j = i + 2), k = i + 3);
▪ 5 is assigned to i, the result (5) is discarded
▪ 7 is assigned to j, the result (7) is overall result of the first
expression with the comma operator. The result is discarded.
▪ 8 is assigned to k, the result (8) is overall result of the second
expression with comma operator. This result is assigned to m. The
result of this assignment (8) is discarded.

© ZPR-FER-UNIZG Introduction to programming 26


Comma operator
▪ In practice, this operator is used infrequently, usually in
characteristic cases
▪ Example: print pairs of "ascending and descending" counter values
int i, j;
j = 10;
for (i = 1; i <= 10; ++i) {
printf("%d %d\n", i, j);
--j;
}

Using the comma operator


int i, j;
for (i = 1, j = 10; i <= 10; ++i, --j) {
printf("%d %d\n", i, j);
}

© ZPR-FER-UNIZG Introduction to programming 27


Example
▪ Another example of usage of the comma operator
▪ enter an integer and print its product with 10 until zero is entered
int i;
do {
scanf("%d", &i);
if (i != 0) {
printf("%d\n", 10 * i);
}
} while (i != 0);

Using the comma operator


int i;
while (scanf("%d", &i), i != 0) {
printf("%d\n", 10 * i);
}

© ZPR-FER-UNIZG Introduction to programming 28


Introduction to programming - lectures

7. Functions

© ZPR-FER-UNIZG Introduction to programming 1


Functions

Introduction

© ZPR-FER-UNIZG Introduction to programming 2


Example
▪ Enter integers m and n, where 0 ≤ n ≤ m. It is not necessary to
check the entered values. Calculate the binomial coefficient C(m,
n) or "m over n", using the following expression:

▪ Examples of program execution


Enter m and n > 10 3
C(10, 3) = 120
Enter m and n > 12 8
C(12, 8) = 495

© ZPR-FER-UNIZG Introduction to programming 3


Solution without a function (part 1)
prog.c

#include <stdio.h>
int main(void) {
int m, n;
int i, mFact, nFact, mnFact, binCoef;

printf ("Enter m and n > ");


scanf ("%d %d", &m, &n);
...

© ZPR-FER-UNIZG Introduction to programming 4


Solution without a function (part 2)
prog.c (continued)

...
mFact = 1; m!
for (i = 2; i <= m; ++i)
mFact = mFact * i;
nFact = 1; n!
for (i = 2; i <= n; ++i)
nFact = nFact * i;
mnFact = 1; (m - n)!
for (i = 2; i <= m - n; ++i)
mnFact = mnFact * i;
binCoef = mFact / (nFact * mnFact);
printf("C(%d, %d) = %d", m, n, binCoef);
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 5


Comment on the previous solution
▪ A similar program section is repeated three times

▪ Disadvantages:
▪ the number of lines of program code is growing
▪ the possibility of error increases (when writing and when editing)

▪ Recommendation:
▪ divide the program into logical units that perform specific, clearly
defined tasks

© ZPR-FER-UNIZG Introduction to programming 6


Solution using the function (part 1)
prog.c

#include <stdio.h> because of printf in main

// function to calculate n!
int fact(int n) {
int i;
int product = 1;
for (i = 2; i <= n; ++i)
product = product * i;
return product;
}
...

© ZPR-FER-UNIZG Introduction to programming 7


Solution using the function (part 2)
prog.c (continued)

...
// colloquially: main program
int main(void) {
int m, n;
int binCoef;
printf ("Enter m and n > ");
scanf ("%d %d", &m, &n);
binCoef = fact(m) / (fact(n) * fact(m - n));
printf("C(%d, %d) = %d", m, n, binCoef);

return 0;
}

© ZPR-FER-UNIZG Introduction to programming 8


Alternatively: with a function for binomial
coefficient prog.c

#include <stdio.h> because of printf in main


// function to calculate n!
int fact(int n) {
int i;
int product = 1;
for (i = 2; i <= n; ++i)
product = product * i;
return product;
}
// function to calculate binomial coefficient
int binCoef(int m, int n) {
return fact(m) / (fact(n) * fact(m - n));
}
...
// function call in main
printf("C(%d, %d) = %d", binCoef(m, n));

© ZPR-FER-UNIZG Introduction to programming 9


Variant with unsigned long long instead of int
prog.c

▪ the domain of the fact function in the previous variant is a set of


integers from the interval [0, 12] because 13! = 6 227 020 800
unsigned long long fact(unsigned int n) {
unsigned int i;
▪ here the domain of the fact function
unsigned long long product = 1ULL;
is the of integers from the interval [0,
for (i = 2U; i <= n; ++i)
20].
product = product * i;
return product; Enter m i n > 20 5
} C(20, 5) = 15504

unsigned long long binCoef(unsigned int m, unsigned int n) {


return fact(m) / (fact(n) * fact(m - n));
}
// function call in main
...
printf("C(%u, %u) = %llu", m, n, binCoef(m, n));

© ZPR-FER-UNIZG Introduction to programming 10


Using a better algorithm
▪ The previous algorithm for calculating the binomial coefficient is
suitable for explaining the concept of a function, but applying a
multiplicative formula would give a much better solution:
▪ a large number of steps is avoided in separate calculations m!, n! i (m-n)!
▪ overflow that can occur due to a steep growth in n! function is avoided
int binCoef(int m, int n) {
int res = 1;
int i;
if (n < m - n)
for (i = 1; i <= n; ++i)
res = res * (m - n + i) / i;
else
for (i = 1; i <= m - n; ++i)
res = res * (n + i) / i; Enter m and n > 20 5
C(20, 5) = 15504
return res;
}
© ZPR-FER-UNIZG Introduction to programming 11
Variant with unsigned long long instead of int
unsigned long long
binCoef(unsigned int m,
unsigned int n) {
unsigned long long res = 1ULL;
unsigned int i;
if (n < m - n)
for (i = 1U; i <= n; ++i)
res = res * (m - n + i) / i;
else
for (i = 1U; i <= m - n; ++i)
res = res * (n + i) / i;
return res;
}
// function call in main
...
printf("C(%u, %u) = %llu", m, n, binCoef(m, n));

© ZPR-FER-UNIZG Introduction to programming 12


Function definition
▪ the function definition describes
▪ function (result) type
▪ function name
▪ (optional) list of function parameters. For each parameter: type and
name
▪ function body: definitions and declarations, statements that are
executed when a function is called
▪ (optional) command to return results and program sequence

General form

result_type function_name(parameter_list) {

function
definitions, declarations and statements;

body
return result;
}

© ZPR-FER-UNIZG Introduction to programming 13


Function definition: function type
▪ the result type (function type) must be specified and can be
▪ any data type except array
▪ basic types, pointers, structures
▪ e.g. if the function returns an result of type int, we say: the
function is of type int
▪ if the function does not return a result (the function is of type
void), the keyword void must be specified as the result_type

© ZPR-FER-UNIZG Introduction to programming 14


Function definition: parameters
▪ parameter type and name should be specified for each parameter
(if the function has parameters)
▪ the parameter can be of any data type except array
▪ basic types, pointers, structures
▪ the number of parameters is not limited (can be zero)
▪ if the function has no parameters, then the keyword void must be
specified in place of the parameter_list
▪ the parameter is a modifiable lvalue: it can be used in the function body in
the same way as any other variable defined in the function body
▪ the parameter differs from the variable defined in the body of the
function only in that, at the beginning of the execution of the function,
it is associated with the value of the argument with which the function
is called

© ZPR-FER-UNIZG Introduction to programming 15


Function definition: return of results
▪ return of results and continuation of program sequence at the
calling level (in the expression where the function call is located)
is performed with the statement return
▪ General form of return statement: return expressionoptional;
▪ the function can return a maximum of one value (or none)
▪ the result (expression) can be of any dana type except array
▪ if the expression type differs from the function type, an implicit conversion of
the result value to the function type is performed
▪ in a function that does not return a result this statement can be
▪ omitted, in which case the return of the program sequence will
occur at the end of the function body
▪ used without specifying the expression that represents the result
▪ the statement can be specified multiple times within the same
function (not entirely consistent with structured programming)
© ZPR-FER-UNIZG Introduction to programming 16
Example: function definition
▪ function xn, x ∈ R, n ∈ N0

The result of the function is of type double.


Function parameters
prog.c

double exp(float x, int n) { Variables i and res are local variables,


int i; visible only in the body of the function
double res = 1.;
for (i = 0; i < n; ++i)
res *= x; Return statement (program
return res; sequence and result)
}
... main function definition
int main(void) { ▪ in C, a function is never defined within the
... definition of another function

© ZPR-FER-UNIZG Introduction to programming 17


Function call: arguments
▪ function arguments are expressions that are specified when
calling a function, in parentheses after the function name,
separated by commas
▪ the argument can be of any data type except array
▪ basic types, pointers, structures
▪ the number and order of arguments should match the number and
order of parameters in the function being called
▪ argument data types must match the data types of the
corresponding parameters or it must be possible to convert the data
from the argument data type to the parameter data type
▪ e.g. if the function parameter is of type double, the function can be
called with an argument of type int (taking into account possible
information losses that may occur during data type conversion)
▪ if the function has no parameters, then when calling the function,
nothing is written in place of the argument list (no void is written)
© ZPR-FER-UNIZG Introduction to programming 18
Example: function call
prog.c
#include <stdio.h> because of printf in main
double exp(float x, int n) {
...
return res;
Parameters
} ▪ arguments can be
... expressions
int main(void) { Arguments ▪ the result of the function
... can be used in various
double y = exp(3.f, 4); expressions
printf("3 to the power of 4 = %lf", y);
printf("2 to the power of 5 = %lf", exp(2.f, 5));
exp(3.f, 2); correct but useless
y = exp(3.5f, 2) + 2 * exp(2.1f, 3); 3.52 + 2 ∙ 2.13
4
y = exp(exp(2 * 3.f, 2), 4); (62)
...
} ▪ for now, the definition of the main function is always written at the end. It will be
explained later how the order of writing function definitions can be changed.

© ZPR-FER-UNIZG Introduction to programming 19


Example
▪ a function with no parameters but returns a result
...
int count(void) { ▪ counts how many characters are typed on the
char c; keyboard before the first # character appears
int counter = 0;
do {
scanf("%c", &c);
++counter;
} while (c != '#');
return counter - 1;
}
... how many?#and now?#
9
int main(void) {
8
printf("%d\n", count());
printf("%d\n", count()); ##
... 0
0

© ZPR-FER-UNIZG Introduction to programming 20


Example
▪ a function that has parameters but does not return a result
...
void printXY(float x, float y) { ▪ prints x, y coordinates inside
printf("(%.4f, %.4f)", x, y); parentheses, with 4 digits after
return; can be omitted the decimal point
}
...
int main(void) {
float x1 = 3.25f, y1 = -12.f;
float x2 = 0.1f, y2 = 4.5f;

printf("Coordinates T1: "); Coordinates T1: (3.2500, -12.0000)


ispisXY(x1, y1); Coordinates T2: (0.1000, 4.5000)
printf("\ Coordinates T2: ");
printXY(x2, y2);
...

© ZPR-FER-UNIZG Introduction to programming 21


Example
▪ a function that has no parameters and does not return a result
...
void skip(void) { ▪ skips characters entered via the keyboard, until
char c; character # appears
do {
scanf("%c", &c);
} while (c != '#');
return; can be omitted
}
...
int main(void) { ▪ reads an integer after the first two characters #
int first, second;
skip();
skip all of this#567 skip this too#98765
scanf("%d", &first); first = 567, second = 98765
skip();
scanf("%d", &second);
printf("first = %d, second = %d", first, second);
...
© ZPR-FER-UNIZG Introduction to programming 22
Example
▪ a function that uses the return statement in multiple places
...
double absolute(double x) { ▪ calculates the absolute value of a real
if (x < 0) { number
return -x;
} else {
return x;
}
}
...
int main(void) {
double x = -3.5;
printf("abs(%lf) = %lf", x, absolute(x));
...
abs(-3.500000) = 3.500000

© ZPR-FER-UNIZG Introduction to programming 23


Example
▪ implicit conversion of arguments
...
double exp(float x, int n) {
...
return res;
}
int → float

no conversion, because the


... argument and parameter are of
int main(void) { the same type
...
double y = exp(3, 4);
printf("%lf", y);
...

▪ similar, e.g., function sqrt from <math.h>, where the parameter is of type double,
will return the correct result even when the argument is of type int
© ZPR-FER-UNIZG Introduction to programming 24
Example
▪ implicit conversion of results
...
char lower_to_upper(char c) {
if (c >= 'a' && c <= 'z')
return c - ('a' – 'A'); int → char, because c - ('a' – 'A') is int
else
return c; no conversion, c is char
}

...
int main(void) {
printf("%c", lower_to_upper('f')); F
printf("%c", lower_to_upper('B')); B
printf("%c", lower_to_upper('*')); *

© ZPR-FER-UNIZG Introduction to programming 25


Example
▪ the function cannot change the values of the arguments by
changing the parameter values
▪ because the parameter contains a copy of the argument value
#include <stdio.h>
void tryToChangeTheArgument(int n) {
n = 10;
printf("Function changed the parameter n to %d\n", n);
return;
} Function called with argument n = 5
Function changed the parameter n to 10
int main(void) { But the argument is still n = 5
int n = 5;
printf(" Function called with argument n = %d\n", n);
tryToChangeTheArgument(n);
printf("But the argument is still n = %d", n);
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 26
Functions

Mechanism of
passing the arguments and
returning the results

© ZPR-FER-UNIZG Introduction to programming 27


Function call mechanism
▪ At the time of the function call it is necessary to reserve the
memory for storing the parameters and the address of the
instruction to which to return (return address)
▪ During the execution of the function, it is necessary to reserve
memory for the variables defined in the function
▪ after the function is completed, the reserved memory should be
freed
int main(void) { double exp(float x, int n) {
double res = 1.;
double y;
Operating for (; n > 0; --n)
y = exp(3.f, 2) res *= x;
system
+ exp(2.f, 3); return res;
... }

return 0;
}

© ZPR-FER-UNIZG Introduction to programming 28


Stack
▪ each function call level requires memory reservation for its
parameters, variables, and return address
▪ implemented using stack. The basic operations on the stack are:
▪ adding data to the stack(push)
▪ taking data from the top of the stack (pop)
▪ the last data placed on the stack is the first to be taken
▪ last in, first out – LIFO
push(a) push(b) push(c) push(d) pop() pop() push(e) pop() pop() pop()
d c e b a
d

c c c e
bottom
of stack b b b b b b b

a a a a a a a a a

© ZPR-FER-UNIZG Introduction to programming 29


In C (simplified)
2 4
int main(void) { int times20(int p) { int timesN(int p,
1 int r, i = 2; 3 int res; int n) {
r = times20(i); res = timesN(p, 20); 5 int res;
... r.a.1 res = p * n;
7 return res; r.a.2 6 return res;
8 return 0;
} } }

5 res ?
r.a. = return address r.a.2 r.a.2
p 2 6 p 2
4
n 20 n 20
3 res ? res ? res ?
6
r.a.1 r.a.1 r.a.1 r.a.1
bottom 2 p 2 7 p 2 p 2 p 2
of stack
1 i 2 i 2 i 2 i 2 i 2
r ? 7 r ? r ? r ? r ?
8

© ZPR-FER-UNIZG Introduction to programming 30


Explanation
1. on stack: space for local variables r, i
2. on stack: value for parameter p and return address r.a.1
3. on stack: space for local variable res
4. on stack: values for parameters p, n and return address
r.a.2
5. on stack: space for local variable res
6. removing local variables, parameters, and return addresses
from stack after returning to r.a.2
7. removing local variables, parameters, and return addresses
after returning to r.a.1
8. removing local variables from stack upon program
termination

© ZPR-FER-UNIZG Introduction to programming 31


Functions

Recursive functions

© ZPR-FER-UNIZG Introduction to programming 32


Recursive function
▪ A function that calls itself is called recursive function
▪ direct recursion: e.g. function f contains call of function f
▪ indirect recursion: e.g. function f contains call of function g which
contains call of function f
▪ Example of definition and call of a recursive function
void print(int n) { 2
printf("%d\n", n); 1
print(n - 1); 0
... ?
return; When will printing stop?
}
... in main
int ul = 2;
print(ul);

▪ What will be the result of the function call? What major error
does this definition of a function contain?
© ZPR-FER-UNIZG Introduction to programming 33
Call order
▪ Imagine, for visualization, that there are multiple instances of the
print function
▪ print is called with ul=2, before it ends, it calls print with
argument 1. Before it ends, print is called with argument 0, etc.
main
int ul = 2;
print(ul);

n 2 n 1 n 0 n -1 etc.

void print(int n) { void print(int n) { void print(int n) {


printf("%d\n", n); printf("%d\n", n); printf("%d\n", n);
print(n - 1); print(n - 1); print(n - 1);
return; return; return;
} } }

© ZPR-FER-UNIZG Introduction to programming 34


Stack in a poorly defined recursive function
▪ Before the print function called with argument 2 ends (therefore,
before the parameter n = 2 and the return address r.a.1 to return to the
main function are removed), it calls print with argument 1. Before it
ends, it calls print with argument 0, etc. after the call with
argument -1

▪ May the stack grow indefinitely? after the call with


argument 0
r.a.4 ∞
n -1
after the call with r.a.3 r.a.3 etc.
argument 1 n 0 n 0
after the call with r.a.2 r.a.2 r.a.2
argument 2
n 1 n 1 n 1
local variable in r.a.1 r.a.1 r.a.1 r.a.1
function main n 2 n 2 n 2 n 2
ul 2 ul 2 ul 2 ul 2 ul 2

▪ when the memory initially allocated to the program stack is depleted, the
program will abort due to a run-time error.
© ZPR-FER-UNIZG Introduction to programming 35
Consequence of a poorly defined recursive
function
void print(int n) { 2 execution in Linux
printf("%d\n", n); 1
0
print(n - 1); -1
return; ...
} -392858
-392859
Segmentation fault (core dumped)

▪ A recursive function must be defined so that under certain


conditions it ceases to further invoke itself
void print(int n) { 2
printf("%d\n", n); 1
0
if (n > 0) {
print(n - 1);
}
return;
}

© ZPR-FER-UNIZG Introduction to programming 36


Call and return order
▪ imagine, for visualization, that there are multiple instances of the
print function
int ul = 2;
print(ul); main
return 0;

n 2 n 1 n 0

void print(int n) { void print(int n) { void print(int n) {


printf("%d\n", n); printf("%d\n", n); printf("%d\n", n);
if (n > 0) { if (n > 0) { if (n > 0) {
print(n - 1); print(n - 1); print(n - 1);
} } }
return; return; return;
} } }

© ZPR-FER-UNIZG Introduction to programming 37


Stack in a correctly defined recursive function
int main(void) { void print(int n) {
int ul = 2; printf("%d\n", n);
print(ul); if (n > 0) {
return 0; print(n - 1);
} }
return;
}

call return;
print(n-1);
for n=1 r.a.3
call return;
print(n-1); n 0
for n=2 r.a.2 r.a.2 r.a.2
call return;
print(ul); n 1 n 1 n 1
for ul=2 r.a.1 r.a.1 r.a.1 r.a.1 r.a.1
int ul = 2; return 0;
n 2 n 2 n 2 n 2 n 2
ul 2 ul 2 ul 2 ul 2 ul 2 ul 2 ul 2

© ZPR-FER-UNIZG Introduction to programming 38


Example: mathematical definition of a function
▪ Recursive definition of function fact(n):
1 𝑓𝑜𝑟 𝑛 = 0
▪ 𝑓𝑎𝑐𝑡 𝑛 =
𝑛 ∙ 𝑓𝑎𝑐𝑡 𝑛 − 1 𝑓𝑜𝑟 𝑛 > 0

fact(4) =
4 ∙ (fact(3)) =
4 ∙ (3 ∙ (fact(2))) =
4 ∙ (3 ∙ (2 ∙ (fact(1)))) =
4 ∙ (3 ∙ (2 ∙ (1 ∙ (fact(0))))) =
4 ∙ (3 ∙ (2 ∙ (1 ∙ (1))))

© ZPR-FER-UNIZG Introduction to programming 39


Example: definition of a function in C
▪ Mathematical recursive expressions are often easily converted
into a definition of a recursive function
int fact(int n) { int fact(int n) {
int res; if (n == 0)
if (n == 0) return 1;
res = 1; else
else return n * fact(n - 1);
res = n * fact(n - 1); }
return res;
}

© ZPR-FER-UNIZG Introduction to programming 40


Example: call and return order
▪ Imagine, for the sake of visualization, that there are multiple
instances of fact function
int f3;
main
f3 = fact(3);

n 3 n 2 n 1 n 0

int fact(int n) { int fact(int n) { int fact(int n) { int fact(int n) {


int res; int res; int res; int res;
if (n == 0) if (n == 0) if (n == 0) if (n == 0)
res = 1; res = 1; res = 1; res = 1;
else else else else
res = n * fact(n-1); res = n * fact(n-1); res = n * fact(n-1); res = n * fact(n-1);
return res; return res; return res; return res;
} 2 } 1 } 1 }

© ZPR-FER-UNIZG Introduction to programming 41


Example: stack when calling fact(3)
int fact(int n) {
main int res;
if (n == 0)
int f3;
res = 1;
f3 = fact(3); else
res = n * fact(n - 1);
fact(0); return res;
res ? → 1 return res; }
r.a.4
fact(1); n 0
res ? res ? res 1 * return res;
r.a.3 r.a.3 r.a.3
fact(2); n 1 n 1 n 1
res ? res ? res ? res ? res 2 * return res;
r.a.2 r.a.2 r.a.2 r.a.2 r.a.2

return res;
fact(3); n 2 n 2 n 2 n 2 n 2
res ? res ? res ? res ? res ? res ? res 6 *
r.a.1 r.a.1 r.a.1 r.a.1 r.a.1 r.a.1 r.a.1
n 3 n 3 n 3 n 3 n 3 n 3 n 3
f3 ? f3 ? f3 ? f3 ? f3 ? f3 ? f3 ? f3 ? f3 6

© ZPR-FER-UNIZG Introduction to programming 42


Variant with unsigned long long instead of int
▪ Using this data type, the domain of the fact function is enlarged
to integers from the interval [0, 20]
unsigned long long unsigned long long
fact(unsigned int n) { fact(unsigned int n) {
unsigned long long res; if (n == 0)
if (n == 0) return 1ULL;
res = 1ULL; else
else return n * fact(n - 1);
res = n * fact(n - 1); }
return res;
}

© ZPR-FER-UNIZG Introduction to programming 43


Introduction to programming - lectures

8. Pointers

© ZPR-FER-UNIZG Introduction to programming 1


Pointer data type

Introduction

© ZPR-FER-UNIZG Introduction to programming 2


Computer primary storage (main memory)
▪ The computer primary storage can be 0 00110001
1 11010010
viewed as a continuous series of bytes,
each of which has its own "ordinal ... ...
number" or address.
82560 11000001
▪ the image illustrates the memory of 4GB
82561 00001101
82562 11000001
82563 11101000

... ...

4294967294 00110001
4294967295 00000111

© ZPR-FER-UNIZG Introduction to programming 3


Objects and values in C
▪ Object is an area in memory whose contents ... ...

represents a value 82560 01000010 c


... ...
▪ Value is an interpretation of the content of an
82642 00000000
object based on the type and content of the
82643 00000000
object m
82644 00000000
... 82645 00000111
char c = 'B'; ... ...
... 82714 10111111
int m = 7;
82715 01000000
... x
float x = -0.75f; 82716 00000000
... 82717 00000000
... ...

© ZPR-FER-UNIZG Introduction to programming 4


Object address
▪ We say than an object is located at address A ... ...

(or the address of the object is A) if the first 82560 00001101 c


byte of the object's contents is stored at ... ...

address A. 82642 00000000


82643 00000000
▪ E.g. the variable m is located at the address m
82642, i.e. the address of the variable m is 82644 00000000

82642 82645 00000111


... ...
82714 10111111
82715 01000000
x
82716 00000000
▪ For illustration, it is assumed that the variables are located 82717 00000000
at the addresses shown. In reality, it is impossible to know
exactly what addresses are in question before the program ... ...
is launched (and it is not even important to know them in
advance).
© ZPR-FER-UNIZG Introduction to programming 5
How the value of the object is retrieved
▪ Accessing the object using an identifier ... ...
82560 00001101 c
▪ variable name (for scalar types), variable
name and index (for arrays), variable name ... ...

and member name (for structures), ... 82642 00000000

▪ object identifier is a lvalue that can be used to 82643 00000000


m
get or set the value of the object 82644 00000000

▪ the data type is known from the definition of 82645 00000111


the variable ... ...
▪ the type is important: if the data type were not 82714 10111111
known, it would not be possible to perform the 82715 01000000
operations correctly e.g. x
82716 00000000

double y; 82717 00000000


y = m + x; ... ...

© ZPR-FER-UNIZG Introduction to programming 6


Can the object be accessed by address?
▪ Can the value be reached using (only) the ... ...

object address? 82560 00001101 c


... ...
▪ e.g. if an object is known to be located at
82642? 82642 00000000
82643 00000000
▪ no, the address alone is not enough m
82644 00000000
▪ To properly access an object, we need both
82645 00000111
the address and the type of object located
... ...
at that address
82714 10111111
▪ the address and type of the object represent
82715 01000000
a form of reference to that object x
82716 00000000
▪ the type of object accessed by reference is
82717 00000000
called the referenced type
... ...

© ZPR-FER-UNIZG Introduction to programming 7


Pointer data type
▪ A data type that allows access to an object using a reference
▪ If the referenced object is of type T, then the data type pointer to T is
used to access the object. E.g. dana type pointer to int allows access
to an object of type int
▪ There are no separate keywords for the pointer data type (as for
data types int, float, etc.). Pointer data type is defined using
name of the referenced type and character *

int *p1, *p2;


float *p3;

▪ Variables p1 and p2 are of type pointer to int


▪ Variable p3 is of type pointer to float

© ZPR-FER-UNIZG Introduction to programming 8


Variables of type pointer
▪ For a variable of type pointer, everything that has been stated so
far about variables of other scalar types is valid, except:
▪ it is defined in a slightly different way: by specifying the name of the
referenced type and the * character in front of the variable name
▪ stores address of the variable of the referenced type

int m; int *p1;

referenced variable p1 is not of type int,


type but pointer to int

▪ it is allowed to define variables of some type and pointers to


variables of the same type in the same statement
int m, *p1, *p2, k;

© ZPR-FER-UNIZG Introduction to programming 9


Which value to enter in a variable of type pointer
int m = 7, *p1;
... ...
p1 = ?
82642 00000000
▪ In general, if x is a variable (or a member of a 82643 00000000
array, or a structure, or a member of a 82644 00000000
m
structure, ...), then &x is a pointer to x 82645 00000111
▪ & is address-of operator. The result of the ... ...
expression &m is pointer to int because m is 82820 00000000
object of type int
82821 00000001
▪ the address corresponds to the address of the p1
82822 01000010
variable m (82642)
82823 11010010
▪ the result is of type pointer to int
... ...
▪ since the result of an expression &m is pointer
to int, it can be assigned to variable p1 (which
is of type pointer to int)
p1 = &m;

© ZPR-FER-UNIZG Introduction to programming 10


Example
▪ Henceforth, we will display the contents of the memory in a more
appropriate way
82642 82820
int m = 7, *p1; ... 7 ... ? ...

m p1

▪ variable p1 is not yet initialized: pointer stored in variable p1 "points


to unknown location"
82642 82820
p1 = &m; ... 7 ... 82642 ...

m p1
▪ now p1 contains a pointer to int which can access int at address 82642
▪ for simplification, colloquial terms will be used:
▪ by statement int *p1; we define a pointer p1
▪ by statement p1 = &m; address of variable m is assigned to p1
▪ p1 points to the object at address 82642
▪ p1 points to the variable m, p1 points to the object m
© ZPR-FER-UNIZG Introduction to programming 11
Initialization of a pointer type variable in a
definition
▪ Like other types of variables, pointer-type variables can be
initialized at the time of definition
int m, *p1 = &m, *p2 = p1;
float x, *p3 = &x, y, *p4 = &y;

▪ take care of the order of definition and initialization. The object


whose address is calculated by the address operator must be
defined earlier
int *p1 = &m, m; Incorrect, can be repaired by reordering

▪ note that the pointer type variable can also contain "garbage value"
int m, *p1;
int *p2 = p1; At this point p1 still contains “garbage"
p1 = &m; It can be fixed by reordering the statements

© ZPR-FER-UNIZG Introduction to programming 12


Pay attention to differences in pointer types
▪ Pointer types are different from each other if their referenced
types differ
▪ it is not allowed point to a variable with a pointer of another type

int m;
int *pInt;
float x;
float *pFloat;

pInt = &m;
pFloat = &x;

pFloat = pInt; Incorrect


pInt = &x; Incorrect
pFloat = &m; Incorrect

© ZPR-FER-UNIZG Introduction to programming 13


The address is not an integer
▪ Although it looks like an integer, the address is generally not int
(nor short, nor long, ...). So it doesn't make sense:
▪ store the pointer in a variable of type int
▪ store the integer in a pointer type variable

int *p1;
int m;
m = 5;
p1 = &m;

p1 = m; Incorrect
m = p1; Incorrect

© ZPR-FER-UNIZG Introduction to programming 14


Access the object using the pointer
82642 82820
int m = 7, *p1 = &m; ... 7 ... 82642 ...

m p1
▪ the object (7, type int) at 82642 can be accessed:
▪ (of course) using the variable name m
82642 82820
m = m + 2; ... 9 ... 82642 ...

m p1
▪ but also by applying an indirection operator (unary operator *) over
the pointer stored in the variable p1
82642 82820
*p1 = 2 * *p1; ... 18 ... 82642 ...

m p1

printf("%d %d", m, *p1); get the integer from the place where p1
points, multiply the obtained result (type int)
18 18 by 2 and write the result in the place where
p1 points

© ZPR-FER-UNIZG Introduction to programming 15


Indirection operator *
▪ The operator allows the object to be accessed indirectly using a
pointer (instead of directly via a variable name)
▪ the operator is also known as the dereference operator because the
operator "dereferences" the pointer (object reference) and thus
accesses the object
▪ In general, if p points to object x, then the result of the operation
*p is lvalue which represents the object pointed to by p
▪ this means: if p is a variable that contains a pointer pointing to an
object in memory that represents the variable m, then the
expression *p can be used anywhere in the program where the
name of the variable m can be used
▪ to get values (e.g. in an expression)
▪ to set values (as on the left side of the assignment expression),
provided that the content of the object is changeable

© ZPR-FER-UNIZG Introduction to programming 16


Some language elements are a bit confusing?
int m = 7; ▪ How is it that in the definition of
int *p1 = &m; the variable p1 it is correct to say
... *p1 = &m, when the statement
p1 = &m; Correct *p1 = &m; is incorrect?
*p1 = &m; Incorrect

▪ in C, the same symbols may have different meanings in different


contexts
here the symbol * does not represent an
int *p1 = &m; indirection operator, but indicates that the variable
p1 is not of type int, but of type pointer to int
define p1 as a variable of initialize the just defined variable
type pointer to int p1, to value &m

incorrect because the result of the expression *p1


*p1 = &m; is an object of type int. This is an attempt to
assign an address to an int
© ZPR-FER-UNIZG Introduction to programming 17
Some language elements are a bit confusing?
int m = 7; ▪ How is it that in the definition
int *p1 = &m, *p2 = p1; of the variable p2 is correct to
... say *p2 = p1 , while statement
p2 = p1; Correct *p2 = p1; is incorrect?
*p2 = p1; Incorrect

the variable p1 is defined, initialized to


int *p1 = &m, *p2 = p1;
&m, then the variable p2 is defined which
is initialized to the value found in p1.

incorrect because the result of the


p2 = *p1;
expression *p1 is an object of type int,
which means that this is an attempt to
assign value of type int the variable of
type pointer to int

© ZPR-FER-UNIZG Introduction to programming 18


How much space does a pointer take up?
▪ The object address is the address where the first byte of the
object is stored
▪ this means that the size of the referenced type should not affect the
size of the space occupied by the pointer to that type
int m = 7, *p1 = &m;
double x = 3.1415926, *p2 = &x;

82642 82820 82940 82972


... 7 ... 82642 ... 3.1415926 ... 82940 ...

m p1 x p2
4 bytes 4 bytes 8 bytes 4 bytes

▪ equal space (4 bytes) is occupied by pointer p1 to an object of type


int (which is 4 bytes) and pointer p2 to an object of type double
(which is 8 bytes)
© ZPR-FER-UNIZG Introduction to programming 19
How much space does a pointer take up?
▪ Pointers on one platform (same operating system, architecture
and compiler) in principle* occupy the same amount of memory
regardless of the type of data they show
int m = 7, *p1 = &m;
double x = 3.1415926, *p2 = &x;
printf("%u %u %u\n", sizeof(p1), sizeof(m), sizeof(*p1));
printf("%u %u %u", sizeof(p2), sizeof(x), sizeof(*p2));

x86_64, Windows, gcc x86_64, Linux, gcc


4 4 4 8 4 4
4 8 8 8 8 8

* In practice, this is generally the case, but since the C standard does not explicitly
prescribe such a rule, the possibility that the size of the pointer will differ
depending on the type of data they point to must not be completely ruled out for
every platform.

© ZPR-FER-UNIZG Introduction to programming 20


Generic pointer (void pointer)
▪ The pointer type must be known so that the content of the object
can be correctly interpreted based on the address (where the
object is) and the type (what type of object is at that address)
▪ However, there is a special type of pointer for which this does not
apply
▪ generic pointer (also known in the literature: void pointer) is a
pointer that can point to an object of any type
▪ since the referenced type is not known here, it is not possible to use
such a ponter to access ana object (generic pointer cannot be
dereferenced)
▪ but therefore it is possible to make an explicit cast of a generic
pointer to a pointer type for which the referenced type will be T
▪ the result of the following operation on the generic pointer is a pointer
to the data type T (T *) generic_pointer
© ZPR-FER-UNIZG Introduction to programming 21
Example
int m = 1080033280;
void *p1;
p1 = &m;
// printf("%d", *p1); Incorrect because p1 cannot be dereferenced
printf("%d\n", *(int *)p1);
printf("%f\n", *(float *)p1);

1080033280
3.500000
*p1 is incorrect

*(int *)p1  1080033280

*(float *)p1  3.5


82642 82820
... 01000000 01100000 00000000 00000000 ... 82642 ...

m p1
© ZPR-FER-UNIZG Introduction to programming 22
Conversion specifications for printf i scanf
▪ conversion specification %p is used to print and read pointer-type
data
▪ the exact form of output is not prescribed by the standard (the value
will be printed as a number in the decimal or hexadecimal numeral
system or in some other form)
▪ it is common that the argument (pointer) is explicitly converted to a
generic pointer, but in most cases it can be omitted
int m = 7, *p1 = &m;
printf("m is at the address %p", (void *)p1);
// printf("m is at the address %p", p1); May be without
(void *)
x86_64, Windows, gcc
m is at the address 0061ff28
x86_64, Linux, gcc
m j is at the address 0x7fffd6e8d324
© ZPR-FER-UNIZG Introduction to programming 23
Example
61ff20 61ff24
int a = 5, b = 10; 5 10
int *pa, *pb; a b
pa = &a; // assumption pa = 61ff20
pb = &b; // assumption pb = 61ff24 61ff52 61ff56
61ff20 61ff24
pa pb

▪ what will be printed in the next section?


61ff20 61ff24
*pa = *pb; 10 10
printf("%d %d\n", a, b); a b
printf("%p %p\n", (void *)pa, (void *)pb);
printf("%d %d\n", *pa, *pb); 61ff52 61ff56
61ff20 61ff24
10 10 pa pb
61ff20 61ff24
10 10

© ZPR-FER-UNIZG Introduction to programming 24


Example
61ff20 61ff24
int a = 5, b = 10; 5 10
int *pa, *pb; a b
pa = &a; // assumption pa = 61ff20
pb = &b; // assumption pb = 61ff24 61ff52 61ff56
61ff20 61ff24
pa pb

▪ what will be printed in the next section?


61ff20 61ff24
pa = pb; 5 10
printf("%d %d\n", a, b); a b
printf("%p %p\n", (void *)pa, (void *)pb);
printf("%d %d\n", *pa, *pb); 61ff52 61ff56
61ff24 61ff24
5 10 pa pb
61ff24 61ff24
10 10

© ZPR-FER-UNIZG Introduction to programming 25


Example 61ff20 61ff24
2. 5.
float x = 2.f, y = 5.f;
x y
float *p1, *p2, *p3;
61ff56 61ff60 61ff64
p1 = &x;
61ff20 61ff24 61ff24
p2 = p3 = &y;
p1 p2 p3
▪ draw a picture after 61ff20 61ff24
*p3 = *p2 + 3.f * *p2; 2. 20.
p2 = p1; x y
61ff56 61ff60 61ff64
61ff20 61ff20 61ff24
p1 p2 p3
▪ and after
61ff20 61ff24
*p2 = *p3 + 0.5f; 20.5. 23.2
p1 = p3; x y
*p1 += 3.2f; 61ff56 61ff60 61ff64
61ff24 61ff20 61ff24
p1 p2 p3
© ZPR-FER-UNIZG Introduction to programming 26
Pointer data type

Using a pointer when calling a function

© ZPR-FER-UNIZG Introduction to programming 27


Reminder
▪ The function (in C) cannot change the values of the arguments by
changing the parameter values because
▪ the parameter contains a copy of the argument value. That is why
we say that arguments are passed to the function by value
#include <stdio.h>
void tryToChangeTheArgument(int n) {
n = 10;
printf(" The function changed the parameter to n = %d\n", n);
return;
} The function is called with the argument n = 5
The function changed the parameter to n = 10
int main(void) { But the argument remained n = 5
int n = 5;
printf(" The function is called with the argument n = %d\n", n);
tryToChangeTheArgument(n);
printf("But the argument remained n = %d", n);
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 28
call by value (or pass by value)
▪ So even the following program will not do what we would like:

#include <stdio.h>
void swap(int x, int y) {
int tmp;
tmp = x; ▪ At the beginning of the function execution, the x and y
x = y; parameters contain copies of the argument values
y = tmp; ▪ operations on parameters x and y do not affect the values of the
} arguments with which the procedure is called - in this case the
values of the variables a and b
int main(void) {
int a = 5, b = 10;
swap(a, b);
printf("a = %d, b = %d", a, b); a = 5, b = 10 INCORRECT RESULT!
return 0;
} ▪ In C, the swap function can only be implemented correctly using
pointers

© ZPR-FER-UNIZG Introduction to programming 29


Call by value - explanation
▪ Values of variables and parameters in each execution step:
void swap(int x, int y) { (2) Nakon a b x y tmp
int tmp; (3) (1) 5 10 - - -
tmp = x; (4)
(2) 5 10 5 10 -
x = y; (5)
y = tmp; (6) (3) 5 10 5 10 ?
return; (7) (4) 5 10 5 10 5
}
(5) 5 10 10 10 5
int main(void) {
(6) 5 10 10 5 5
int a = 5, b = 10; (1)
swap(a, b); (7) 5 10 - - -

▪ x, y do not exist before the step is performed (2)


▪ tmp does not exist before the step is performed (3)
▪ tmp contains the garbage value after performing the step (3)
▪ after the function is completed, x, y and tmp no longer exist
© ZPR-FER-UNIZG Introduction to programming 30
Call by value
▪ Parameter values may be changed, without affecting the values
of the arguments, even when the parameter name matches the
name of the variable used as the argument
double exp(float x, int n) { double exp(float x, int n) {
int i; double res = 1.;
double res = 1.; for (; n > 0; --n)
for (i = 0; i < n; ++i) res *= x;
res *= x; return res;
return res; }
}

[...] parameters can be treated as conveniently initialized local variables in the


called routine.
B. W. Kernighan, D. M. Ritchie (1988.), The C Programming Language, 2nd Edition, Englewood Cliffs, NJ: Prentice Hall

© ZPR-FER-UNIZG Introduction to programming 31


Call by reference (or pass by reference)

▪ In some languages (e.g. Pascal, Fortran) it is possible to transfer


references to arguments to parameters:
program testVar; ▪ procedura i funkcija u Pascalu - slični su funkciji u C-u
var
a, b: integer;
procedure swap(var x, y: integer);
var ▪ the word var listed in front of the parameter definition
tmp: integer;
means that the parameters x and y are references to the
begin
arguments with which the procedure was called
tmp := x;
x := y; ▪ each operation in the procedure on the parameters x and y
y := tmp; is actually an operation on the arguments - in this example
end; on the variables a and b
begin start of "main program"
a := 5; b := 10;
swap(a, b);
writeln('a = ', a, ', b = ', b); a = 10, b = 5 CORRECT RESULT!
end.

© ZPR-FER-UNIZG Introduction to programming 32


In C, there is no (implicit) call by reference
▪ But that is why there is a substitute for the transfer mechanism
by reference
▪ a copy of the argument that points to the object at the calling level
is passed to the parameter
▪ in the function, the parameter (contains a pointer) can be used to
access the value of the object at the calling level
▪ the function can now, similar to using Pascal mechanism, change the
value of an object defined at the calling level
▪ the only difference is that the parameter (which is a pointer) will have
to be dereferenced in order to access that object
▪ it is still a call by value, but because the transferred values are
pointers, we colloquially say that it is a call by pointer

© ZPR-FER-UNIZG Introduction to programming 33


Example
▪ In this example, an object defined in the main function can be accessed
using a parameter that contains a copy of the argument, which is a
pointer to the object defined in the main function.
void change(int *p) {
The figure shows the contents of the memory just
before the statement *p = 10; is executed
*p = 10;
return; variables / arguments in the function main
}
82642 82658
int main(void) {
5 82642
int n = 5, *p1 = &n;
n p1
change(p1);
alternativno:
int n = 5; by executing the
82712
change(&n); statement *p =
82642
10; the content of
p
the variable c will
variables / parameters in change
the function change
© ZPR-FER-UNIZG Introduction to programming 34
Example
void swap(int *x, int *y) { The figure shows the contents of the
int tmp; memory just before the statement tmp =
*x; is executed
tmp = *x;
in function main
*x = *y;
*y = tmp; 82642 82658
5 10
return;
a b
}

int main(void) {
82712 82742 82780
int a = 5, b = 10;
82642 82658 ?
swap(&a, &b);
x y tmp
...
in function swap

© ZPR-FER-UNIZG Introduction to programming 35


Example (additional explanation)

After a b x y tmp

(1) 5 10 - - -
void swap(int *x, int *y) { (2) (2) 5 10 82642 82658 -
int tmp; (3) (3) 5 10 82642 82658 ?
tmp = *x; (4) (4) 5 10 82642 82658 5
*x = *y; (5) (5) 10 10 82642 82658 5
*y = tmp; (6) (6) 10 5 82642 82658 5
return; (7) (7) 10 5 - - -
}
before 82642 82658
int main(void) {
call 5 10
int a = 5, b = 10; (1)
a b
swap(&a, &b);
after 82642 82658
...
call 10 5
a b
© ZPR-FER-UNIZG Introduction to programming 36
Example
▪ Program task
▪ write a function that will print the message Enter a text > and
then enter a series of characters from the keyboard (up to 20
characters including the character \n). The function should return the
number of uppercase and lowercase letters in the string
▪ write a main program that will call the function and print the results,
according to the program execution examples:
Enter a text > Acronym GPS
Number of uppercase letters: 4
Number of lowercase letters: 6

Enter a text > 12 3!456


Number of uppercase letters : 0
Number of lowercase letters : 0
Enter a text > 
Number of uppercase letters : 0
Number of lowercase letters : 0

© ZPR-FER-UNIZG Introduction to programming 37


The function can return a maximum of one value!
▪ If more values are to be obtained as a result of the function, then
pointers must be used as arguments/parameters
▪ pointers to variables in which the function should store the result
are passed to the function as arguments. In such a case, we will say
colloquially: the function should return the result using the pointer
▪ applied in this example: the function should return the number of
uppercase and lowercase letters in the entered string using the pointer
▪ when a function returns a single result with the return statement,
we will say colloquially: the result is returned using the name
▪ applied to the example of function fact: function fact should return
n! for a given number n using the name
▪ or simply: function needs to return the result
▪ applied to the example of function fact: function fact should return
n! for a given number n

© ZPR-FER-UNIZG Introduction to programming 38


Solution
#include <stdio.h>
#define MAXTEXT 20
void readAndCount(int *pNumberUpper, int *pNumberLower) {
char text[MAXTEXT + 1];
*pNumberUpper = *pNumberLower = 0;
printf("Enter a text > ");
fgets(text, MAXTEXT + 1, stdin);
int i = 0;
while (text[i] != '\0') {
if (text[i] >= 'A' && text[i] <= 'Z')
++*pNumberUpper; // or (*pNumberUpper)++
else if (text[i] >= 'a' && text[i] <= 'z')
++*pNumberLower; // or (*pNumberLower)++
++i;
}
return;
}
© ZPR-FER-UNIZG Introduction to programming 39
Solution (continued)
int main(void) {
int upper, lower;
readAndCount(&upper, &lower);
printf("Number of uppercase letters : %d\n", upper);
printf("Number of lowercase letters : %d", lower);
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 40


Alternative solution (but pretty bad)
...
int readAndCount(int *pNumberLower) {
char text[MAXTEXT + 1];
int numberUpper = 0;
*pNumberLower = 0;
...
while (text[i] != '\0') {
if (text[i] >= 'A' && text[i] <= 'Z')
++numberUpper;
else if (text[i] >= 'a' && text[i] <= 'z')
++*pNumberLower;
++i; ▪ this function returns the number of uppercase letters
} using the name, and the number of lowercase letters
return numberUpper; using the pointer
} ▪ unnatural, because the two results are similar in
meaning
...
upper = readAndCount(&lower);

© ZPR-FER-UNIZG Introduction to programming 41


Example
▪ Program task
▪ write a function that will print the message Enter text > and then
enter a sequence of characters (up to 20 characters including\n).
The function should return, using pointers, the number of uppercase
and lowercase letters in the entered text, and the logical value,
using the name, true if at least one character is entered in addition
to \n, otherwise false. Write a main program that will call the
function and print the results, according to the examples:
Enter text > Acronym GPS
Number of uppercase letters: 4
Number of lowercase letters: 6
Enter text > 12 3!456
Number of uppercase letters: 0
Number of lowercase letters: 0
Enter text > 
Empty text entered

© ZPR-FER-UNIZG Introduction to programming 42


Solution
...
_Bool readAndCount(int *pNumberUpper, int *pNumberLower) {
char text[MAXTEXT + 1];
_Bool textContainsSomething;
*pNumberUpper = *pNumberLower = 0;
... prompt and input
if (text[0] == '\0' || text[0] == '\n') {
textContainsSomething = 0;
} else {
textContainsSomething = 1;

... counting letters…

}
return textContainsSomething;
}

© ZPR-FER-UNIZG Introduction to programming 43


Solution (continued)
int main(void) {
int upper, lower;
_Bool textNotEmpty;
textNotEmpty = readAndCount(&upper, &lower);
if (textNotEmpty) { // or if (readAndCount(&upper, &lower))
printf("Number of uppercase letters: %d\n", upper);
printf("Number of lowercase letters: %d", lower);
} else {
printf("Empty text entered");
}
return 0;
}

▪ results that are similar in meaning are appropriately grouped here


▪ this does not mean that a solution in which all three results would be returned
using pointers would be bad

© ZPR-FER-UNIZG Introduction to programming 44


NULL pointer
▪ A pointer-type variable not initialized in time is a possible source of
critical and difficult-to-detect logical errors
▪ contains garbage value, which means it points "who knows where"
▪ an attempt at dereferencing will cause
▪ program interruption (if we were lucky because the "garbage" pointed to
an area of memory protected by the operating system)
▪ undefined program behavior, possibly different each time it is run (if
"garbage" points to an area of memory that the operating system allows
to be read and modified by program)
▪ Therefore, to avoid such logical errors, it is extremely important to:
▪ initialize each pointer type variable during definition
▪ if the value is unknown at the time of initialization, initialize it to a
special pointer value: NULL
▪ attempting to dereference that pointer value will certainly cause the
program to terminate (which is much better than undefined behavior!)
© ZPR-FER-UNIZG Introduction to programming 45
NULL pointer
▪ The NULL pointer is a symbolic constant defined in <stdio.h>

▪ an example of defining a single pointer type variable in a secure way

#include <stdio.h>
int main(void) {
int *res = NULL;
...

© ZPR-FER-UNIZG Introduction to programming 46


NULL pointer
▪ The NULL pointer is also useful in cases where a value that has a
special meaning in the context needs to be stored in a pointer
variable.
▪ Example: enter two integer values. The pointer p1 must point to the
variable that contains a larger value, but also must report the case when
values are equal

int a, b, *p1 = NULL; for security, set to NULL immediately


...
if (a > b)
p1 = &a;
else if (b > a)
p1 = &b;
else what if the values are equal?
p1 = NULL;
...
if (p1 == NULL) ... now we know how to ask if the values are equal

© ZPR-FER-UNIZG Introduction to programming 47


Example
▪ Program task
▪ write a function that receives pointers to two objects of type float.
The function returns a pointer to an object that contains a larger
number. If the numbers are equal, the function returns a NULL
pointer.
▪ write a main program that will call the function and print the results,
according to the program execution examples

Enter two numbers > 4.1 5.1


Bigger number is 5.100000

Enter two numbers > 4.1 4.1


The numbers are equal

© ZPR-FER-UNIZG Introduction to programming 48


Solution
#include <stdio.h>
float *returnBigger(float *px, float *py) {
if (*px > *py)
return px;
else if (*py > *px)
return py;
else
return NULL;
}
int main(void) {
float a, b, *res = NULL;
printf("Enter two numbers > ");
scanf("%f %f", &a, &b);
res = returnBigger(&a, &b);
if (res == NULL)
printf("The numbers are equal");
else
printf("Bigger number is %f", *res);
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 49


Dangling pointer
#include <stdio.h>
#include <math.h>
▪ what is the big error in this program?

double *returnRoot(double x) {
double res;
res = sqrt(x);
return &res;
}
int main(void) {
double *ptrToRoot = NULL;
ptrToRoot = returnRoot(4.0);
printf("The result is %lf", *ptrToRoot);
return 0;
}

▪ returns a pointer to the object (variable) defined in the function


▪ that object no longer exists when the function ends, which means that
we are trying to print the value of an object that no longer exists at the
time of printing
▪ a pointer pointing to such an object is called a dangling pointer
© ZPR-FER-UNIZG Introduction to programming 50
Pointers

Arithmetic with pointers

© ZPR-FER-UNIZG Introduction to programming 51


Addition of pointers and integers
int m = 7, *p = &m; ... ...

82560 82560
▪ increasing the pointer by one gives a pointer p - 1 82561
of the same type, but pointing to an address 82562
higher by the size (in bytes) of the 82620 82563

referenced type. E.g. 82564 82564 00000000

p 82565 00000000
▪ p+1 is a pointer to an object of type int at
the address that is 4 bytes higher than the
82566 00000000 m
82567 00000111
address stored in p
82568 82568
▪ similarly: p + 1 82569
▪ p+2 is a pointer to an object of type int at 82570
the adress 8 bytes higher than the address 82571
stored p 82572 82572
▪ p-1 is a pointer to an object of type int on p + 2 82573
the adress 4 bytes lower than the address ...
stored in p
© ZPR-FER-UNIZG Introduction to programming 52
Addition of pointers and integers
▪ the same is true for other data types
char c, *cp = &c;
short s, *sp = &s;
int i, *ip = &i;
double d, *dp = &d;
long double ld, *ldp = &ld;
printf(" cp = %p cp + 1 = %p\n", cp, cp + 1);
printf(" sp = %p sp + 1 = %p\n", sp, sp + 1);
printf(" ip = %p ip + 1 = %p\n", ip, ip + 1);
printf(" dp = %p dp + 1 = %p\n", dp, dp + 1);
printf("ldp = %p ldp + 1 = %p ", ldp, ldp + 1);

cp = 0061ff1b cp + 1 = 0061ff1c 1 byte "further"


sp = 0061ff18 sp + 1 = 0061ff1a 2 bytes "further"
ip = 0061ff14 ip + 1 = 0061ff18 4 bytes "further"
dp = 0061ff08 dp + 1 = 0061ff10 8 bytes "further"
ldp = 0061fef0 ldp + 1 = 0061fefc 12 bytes "further"

© ZPR-FER-UNIZG Introduction to programming 53


Array members in memory
▪ The members of the array are always located in a continuous area
of memory, one member immediately after the other
int a[5] = {2, 3, 5, 7, 11};

82644 82648 82652 82656 82660


... 2 3 5 7 11 ...

a[0] a[1] a[2] a[3] a[4]

int b[3][4] = {{2, 3, 5, 7}, ▪ members of the two-


{11, 13, 17, 19}, dimensional array are
{23, 29, 31, 37} stored in memory row by
};
row
82704 82708 82712 82716 82720 82724 82728 82732 82736 82740 82744 82748
... 2 3 5 7 11 13 17 19 23 29 31 37 ...

b[0][0] b[0][1] b[0][2] b[0][3] b[1][0] b[1][1] b[1][2] b[1][3] b[2][0] b[2][1] b[2][2] b[2][3]

© ZPR-FER-UNIZG Introduction to programming 54


Array members in memory
int c[2][2][3] = {{{2, 3, 5},
{7, 11, 13}
},
{{17, 19, 23},
{29, 31, 37}
}
};

▪ members of the three-dimensional array are stored in memory layer by


layer, and inside each layer, row by row
82826 82830 82834 82838 82842 82846 82850 82854 82858 82862 82866 82870
... 2 3 5 7 11 13 17 19 23 29 31 37 ...
c[0][0][0] c[0][0][1] c[0][0][2] c[0][1][0] c[0][1][1] c[0][1][2] c[1][0][0] c[1][0][1] c[1][0][2] c[1][1][0] c[1][1][1] c[1][1][2]

© ZPR-FER-UNIZG Introduction to programming 55


Arrays and pointers
▪ the pointer arithmetic and the way the members of arrays are stored in
memory allow access to any member of the array based on the pointer
pointing to the first member of the array
int a[5] = {2, 3, 5, 7, 11}; ▪ how to use a pointer to the first
int *p = &a[0]; member of an array to access a
member of an array with an index [i]?
82644
p ▪ e.g. the result of the operation p + 3
82644 82648 82652 82656 82660 is a pointer to int which points to
... 2 3 5 7 11 ... the object at the address 82656
a[0] a[1] a[2] a[3] a[4]

p+0 p+1 p+4


za i=0 za i=1 za i=4

if p is a pointer to the first member of the array a, then we can access the
member of the array a[i] using expression *(p + i)
© ZPR-FER-UNIZG Introduction to programming 56
Example
▪ Print members of a one-dimensional array on the screen. Access array
members using a pointer.
...
int a[5] = {2, 3, 5, 7, 11};
int *p = &a[0];
int i;
for (i = 0; i < 5; ++i) {
printf("%d\n", *(p + i));
}
or
for (i = 0; i < 5; ++i) {
printf("%d\n", *p);
p = p + 1; or ++p; or p++;
}
...

© ZPR-FER-UNIZG Introduction to programming 57


Array name as a pointer
▪ The name of a one-dimensional array specified in an expression
will result in a pointer to the first member of that array
int a[5] = {2, 3, 5, 7, 11};
int *p = NULL;
p = a; will give the same result as p = &a[0];
p = a + 2; will give the same result as p = &a[2];

▪ as opposed to the variable p whose value may be changed (because


the variable p is modifiable lvalue), variable a must not be changed
because it represent an array, and array is non-modifiable lvalue
allowed not allowed
p = a; for (i = 0; i < 5; ++i) {
for (i = 0; i < 5; ++i) { printf("%d\n", *a);
printf("%d\n", *p); a = a + 1;
p = p + 1; }
}
© ZPR-FER-UNIZG Introduction to programming 58
Example
▪ Program task
▪ enter 10 members of an integer array from the keyboard. Print the
value of the largest member on the screen. Access array members
only with a pointer
▪ example of program execution
Enter members > 1 2 3 4 -1 9 -2 9 8 7
Largest member is 9

© ZPR-FER-UNIZG Introduction to programming 59


Solution
#include <stdio.h>
#define DIMENSION 10
int main(void) {
int a[DIMENSION], *p = a;
int largest, i;
printf("Enter members > ");
for (i = 0; i < DIMENSION; ++i) {
scanf("%d", p + i); or a + i or &a[0] + i or &a[i]
// due to short circuit evaluation we may write
if (i == 0 || *(p + i) > largest) {
largest = *(p + i);
}
}
printf("Largest member is %d", largest);
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 60


Solution (alternative)
#include <stdio.h>
#define DIMENSION 10
int main(void) {
int a[DIMENSION], *p = a;
int largest, i;
printf("Enter members > ");
for (i = 0; i < DIMENSION; ++i) {
scanf("%d", p);
// due to short circuit evaluation we may write
if (i == 0 || *p > largest) {
largest = *p;
}
++p;
}
printf("Largest member is %d", largest);
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 61
Pointer arithmetic - other operations
▪ the result of the operation of subtracting two pointers, p1 and p2 (which
must be of the same type) is an integer that represents the "address
distance" of the objects that the pointers point to, but expressed in the
number of objects of the referenced type (not in the number of bytes).
int a[7] = {2, 3, 5, 7, 11, 13, 17};
int *p1 = &a[3];
int *p2 = &a[6];
printf("%d %d %d %d", p2 - p1, p1 - p2, p2 - a, *p2 - *p1);

82656 82668
p1 p2
82644 82648 82652 82656 82660 82664 82668
... 2 3 5 7 11 13 17 ...

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


p2 - p1
3 -3 6 10

© ZPR-FER-UNIZG Introduction to programming 62


Pointer arithmetic - other operations
▪ if for some reason we want to calculate the "address distance"
expressed in bytes, the cast to char* operator should be applied
int a[7] = {2, 3, 5, 7, 11, 13, 17};
int *p1 = &a[3];
int *p2 = &a[6];
printf("%d %d %d %d", (char *)p2 - (char *)p1,
(char *)p1 - (char *)p2,
(char *)p2 - (char *)a,
*p2 - *p1);

82656 82668
p1 p2
82644 82648 82652 82656 82660 82664 82668
... 2 3 5 7 11 13 17 ...

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


p2 - p1
12 -12 24 10

© ZPR-FER-UNIZG Introduction to programming 63


Example
82644 82648 82652 82656 82660
int a[] = {10, 20, 30, 40, 50};
... 10 20 30 40 50 ...
int *p1 = &a[0], *p2 = p1 + 3;
a[0] a[1] a[2] a[3] a[4]

*p2 = ++*p1 + 5; 82644 82656


p1 p2
▪ right side:
▪ ++*p1 : increment the value of the object that p1 points to by one, result is 11
▪ a[0] becomes 11
▪ + 5 : overall result on the right: 16
▪ left side
▪ store 16 in the place where p2 points to,
82644 82648 82652 82656 82660
... 11 20 30 16 50 ...

a[0] a[1] a[2] a[3] a[4]

82644 82656
p1 p2

© ZPR-FER-UNIZG Introduction to programming 64


Example
82644 82648 82652 82656 82660
int a[] = {10, 20, 30, 40, 50};
... 10 20 30 40 50 ...
int *p1 = &a[0], *p2 = p1 + 3;
a[0] a[1] a[2] a[3] a[4]

*p2 = *++p1 + 5; 82644 82656


p1 p2
▪ calculate the right side:
▪ ++p1 : increment p1 by one, p1 points to 82648
▪ value at the address 82648 is 20, add 5 to that value, total on the right is 25
▪ left side:
▪ store 25 in the place where p2 points to
82644 82648 82652 82656 82660
... 10 20 30 25 50 ...

a[0] a[1] a[2] a[3] a[4]

82648 82656
p1 p2

© ZPR-FER-UNIZG Introduction to programming 65


Example
82644 82648 82652 82656 82660
int a[] = {10, 20, 30, 40, 50};
... 10 20 30 40 50 ...
int *p1 = &a[0], *p2 = p1 + 3;
a[0] a[1] a[2] a[3] a[4]

*p2++ = *p1++; tj. *(p2++) = *(p1++); 82644 82656


p1 p2
▪ right side:
▪ p1++ : the result is a pointer to 82644 (p1 will increase later)
▪ *p1++ : the result is the value at the address 82644, i.e. 10
▪ lijeva strana:
▪ p2++ : the result is a pointer to 82656 (p2 will increase later)
▪ store 10 to address 82656
▪ increment p1 and p2 by 1 82644 82648 82652 82656 82660
... 10 20 30 10 50 ...

a[0] a[1] a[2] a[3] a[4]

82648 82660
p1 p2
© ZPR-FER-UNIZG Introduction to programming 66
Pointers

Arrays, functions and pointers

© ZPR-FER-UNIZG Introduction to programming 67


How to enable functions to access array members?
▪ The array cannot be used as an argument/parameter of a function
▪ how then to give the function access to the members of the array
defined at the calling level?
▪ Use the ability to access array members with a pointer
▪ specify a pointer to the first member of the array as an
argument/parameter
▪ the parameter will be a copy of the argument, but that doesn't matter:
a copy of the pointer will also point to the first member of that array
▪ add an argument/parameter that describes how many members the
array has
▪ in the function use a pointer to access the members of the array
defined at the calling level
▪ if p is pointer to the first member of the array a, then the member a[i]
can be accessed using pointer p, by expression *(p + i)

© ZPR-FER-UNIZG Introduction to programming 68


Example
▪ Program task
▪ write a function largestMember1D which returns the largest value
in a given one-dimensional integer array
▪ write a main program that will read 10 members of an integer array
from the keyboard, use the function to determine the largest
member, and print it on the screen
▪ example of program execution
Enter members > 1 2 3 4 -1 9 -2 9 8 7
The largest member is 9

▪ common errors
▪ the function only works with 10-member arrays. The function should
work with arrays that have any number of members
▪ the function prints the result on the screen, instead of returning the
result to the function at the calling level

© ZPR-FER-UNIZG Introduction to programming 69


Rješenje
#include <stdio.h>
#define DIMENSION 10
Not DIMENSION!
int largestMember1D (int *p, int n) {
Not 10!
int largest, i;
Why?
for (i = 0; i < n; ++i)
if (i == 0 || *(p + i) > largest)
largest = *(p + i);
return largest;
}
int main(void) {
int a[DIMENSION];
/* the usual code for reading array members is omitted */
printf("The largers member is %d", largestMember1D(a, DIMENSION));
return 0;
} or &a[0]

© ZPR-FER-UNIZG Introduction to programming 70


Two-dimensional arrays and pointers
▪ how to use a pointer to the first member int b[3][4] = {{2, 3, 5, 7},
of a array to access a member of a array {11, 13, 17, 19},
with an index [i][j] in the array with m {23, 29, 31, 37}
rows i n columns? };
int *p = &b[0][0];
82704
p
82704 82708 82712 82716 82720 82724 82728 82732 82736 82740 82744 82748
... 2 3 5 7 11 13 17 19 23 29 31 37 ...

b[0][0] b[0][1] b[0][2] b[0][3] b[1][0] b[1][1] b[1][2] b[1][3] b[2][0] b[2][1] b[2][2] b[2][3]

p+4*0+0 p+4*0+1 p+4*1+0 p+4*2+0 p+4*2+3


za n=4, i=0, j=0 za n=4, i=0, j=1 za n=4, i=1, j=0 za n=4, i=2, j=0 za n=4, i=2, j=3

if p is pointer to the first member of array b having n columns, then the


member b[i][j] can be accessed using expression *(p + n * i + j)

© ZPR-FER-UNIZG Introduction to programming 71


Example
▪ Print members of a two-dimensional array on the screen. Access array
members with a pointer.
...
int b[3][4] = {{2, 3, 5, 7},
{11, 13, 17, 19},
{23, 29, 31, 37}
};
int *p = &b[0][0];
int i, j;
for (i = 0; i < 3; ++i) {
for (j = 0; j < 4; ++j) {
printf("%5d", *(p + 4 * i + j));
}
printf("\n");
}
...

© ZPR-FER-UNIZG Introduction to programming 72


Name of the two-dimensional array as a pointer?

▪ Just the name of a two-dimensional array cannot be used as a


pointer to the first member of that array

int b[3][4] = {{2, 3, 5, 7},


{11, 13, 17, 19},
{23, 29, 31, 37}
};
int *p = NULL;
p = &b[0][0]; correct!
p = b[0]; correct!
p = b; incorrect!

© ZPR-FER-UNIZG Introduction to programming 73


Example
▪ Program task
▪ Write a function sumsOfRows calculates and returns sums of rows of
the given two-dimensional array of m rows in columns (members of
type int).
▪ In the main program, define a matrix of dimensions 3 x 4, enter
members from the keyboard, call the function and print the
obtained result on the screen.
n Enter members >
mat res 1 2 3 4
1 2 3 4 10 5 6 7 8
m 5 6 7 8 26 m 9 10 11 12
Sums of rows:
9 10 11 12 42 10
26
42

© ZPR-FER-UNIZG Introduction to programming 74


Solution
#include <stdio.h>
#define ROWS 3
#define COLS 4
void sumsOfRows(int *mat, int m, int n, int *res) {
int i, j;
for (i = 0; i < m; ++i) {
*(res + i) = 0;
for (j = 0; j < n; ++j)
*(res + i) += *(mat + n * i + j);
}
return;
}
int main(void) {
int mat[ROWS][COLS], res[ROWS];
/* the usual code for reading mat members is omitted */
sumsOfRows(&mat[0][0], ROWS, COLS, &res[0]);
/* the usual code for printing res members is omitted */
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 75
Why is this solution not correct?
...
int *sumsOfRows(int *mat, int m, int n) {
int res[m], i, j;
for (i = 0; i < m; ++i) {
res[i] = 0;
for (j = 0; j < n; ++j)
res[i] += *(mat + n * i + j);
}
return &res[0];
}
...
int mat[ROWS][COLS], int *res, i;
/* the usual code for reading mat members is omitted */
res = sumsOfRows(&mat[0][0], ROWS, COLS);
for (i = 0; i < m; ++i)
printf("%d\n", *(res + i));
...

© ZPR-FER-UNIZG Introduction to programming 76


Example
▪ Program task
▪ Write a function maxByRows which finds the largest values of
members by rows in a given two-dimensional array of m rows and n
columns (members of type int) .The largest members by rows should
be returned in a one-dimensional array (members of type int)
▪ Use the already seen function maxMember1D to search for the largest
value in a single row of the matrix
int largestMember1D(int *p, int n) {
int najveci, i;
for (i = 0; i < n; ++i)
if (i == 0 || *(p + i) > largest)
largest = *(p + i);
return largest;
}
▪ In the main program, enter the dimensions of the matrix m and n,
enter the matrix members, call the function and print the result
© ZPR-FER-UNIZG Introduction to programming 77
Solution
▪ Idea
▪ in function maxByRows, for each row i of the matrix mat, call
largestMember1D with arguments: pointer to the first member of
the i-th row of the matrix, and row length c. Store the result of the
function in the appropriate place (i-th member) in the array res.
In function maxByRows call in
turn n
mat
largestMember1D( , n) 9 10 11 12
store
result in largestMember1D( , n) m 3 7 7 2
res 5 2 3 0
12 largestMember1D( , n)

m 7

© ZPR-FER-UNIZG Introduction to programming 78


Solution (continued)
#include <stdio.h>
int largestMember1D(int *p, int n) {
int largest, i;
for (i = 0; i < n; ++i)
if (i == 0 || *(p + i) > largest)
largest = *(p + i);
return largest;
}
void maxByRows(int *mat, int m, int n, int *res) {
int i;
for (i = 0; i < m; ++i) {
*(res + i) = largestMember1D(mat + n * i + 0, n);
}
return;
}

© ZPR-FER-UNIZG Introduction to programming 79


Solution (continued)
...
int main(void) {
int m, n; // number of rows and columns of matrix mat
printf("Enter number of rows > ");
scanf("%d", &m);
printf(" Enter number of columns > ");
scanf("%d", &n);
int mat[m][n]; // VLA array!
/* the usual code for reading mat members is omitted */
int res[m];
maxByRows(&mat[0][0], m, n, &res[0]);
/* the usual code for printing the results (res) is omitted */
...
}

© ZPR-FER-UNIZG Introduction to programming 80


Pointers and sizeof operator
▪ sizeof returns the same size for pointers of different types
void fun(short *p, double n) {
printf("%d\n", sizeof(p)); 4 (or 8 in Linux)
printf("%d\n", sizeof(*p)); 2
printf("%d\n", sizeof(n)); 8
...
int main(void) {
short a[5][10], *p1 = &a[0][0];
double x, *p2 = &x;
printf("%d\n", sizeof(a)); 100
printf("%d\n", sizeof(p1)); 4 (or 8 in Linux)
printf("%d\n", sizeof(*p1)); 2
printf("%d\n", sizeof(x)); 8
printf("%d\n", sizeof(p2)); 4 (or 8 in Linux)
fun(p1, x);
...

© ZPR-FER-UNIZG Introduction to programming 81


Pointers and strings
▪ to store a string of characters, a one-dimensional array whose members
are of type char is used, whereby the end of the string must be
denoted by a member of the array containing the zero character '\0'
82642 82643 82644 82645 82646 82647
char text[6] = "Ivan"; ... I a n ...
v \0 \0
char *p1 = &text[0];
text[0] text[1] text[2] text[3] text[4] text[5]

82642
String can be changed p1
*(p1 + 2) = 'e';
*(p1 + 3) = 'k';
82642 82643 82644 82645 82646 82647
or *(text + 2) = 'e'; ... I v e k \0 \0 ...

*(text + 3) = 'k'; text[0] text[1] text[2] text[3] text[4] text[5]

or text[2] = 'e'; 82642


p1
text[3] = 'k';
© ZPR-FER-UNIZG Introduction to programming 82
Pointers and string constants
▪ string constant is stored in memory in the same way
char *p2 = NULL, *p3 = NULL;
p2 = "Jure"; "Jure" is a string constant
p3 = "Ana" + 2; "Ana" is a string constant

▪ string constant is evaluated as a char * which points to the first character


in that string constant
82842 82843 82844 82845 82846 82870 82871 82872 82873
... J u r e \0 ... A n a \0 ...

82842 82872
p2 p3

The contents of a string constant cannot be changed


*(p2 + 3) = 'a'; not allowed
*p3 = 'e'; not allowed
printf("%c", *p3); allowed
© ZPR-FER-UNIZG Introduction to programming 83
Example
▪ A pointer to the first character of the string to be printed is passed as an
argument to the conversion specification %s when calling the printf
function. What will be printed by the specified printf function calls?
char text[] = "Blaise Pascal";
char *p1 = text;
printf("%s", text); Blaise Pascal
printf("%s", p1); Blaise Pascal
printf("%s", text + 7); Pascal
printf("%s", &text[0] + 7); Pascal
printf("%s", &text[7]); Pascal
printf("%s", p1 + 7); Pascal
printf("%s", "Isaac Newton"); Isaac Newton
printf("%s", "Isaac Newton" + 4); c Newton
char *p2 = "Benjamin Franklin";
printf("%s", p2); Benjamin Franklin
printf("%s", p2 + 5); min Franklin
© ZPR-FER-UNIZG Introduction to programming 84
Example
▪ Program task
▪ Write a function toUpperCase that receives a string as a
parameter and replaces every lowercase character to uppercase
▪ In the main program, initialize a text of the characters to the value
"John 123", call the function to modify the text and print the
modified text on the screen

Instructions:
Character strings are one-dimensional arrays terminated by a character '\0'.
This means that they can be treated like all other one-dimensional arrays in
functions, but with one important difference: the length of the string does not
need to be specified as an argument because the length of the text (or where the
string ends) can be reliably determined by '\0'.

© ZPR-FER-UNIZG Introduction to programming 85


Solution
#include <stdio.h>
void toUpperCase(char *text) {
int i = 0;
while (*(text + i) != '\0') {
if (*(text + i) >= 'a' && *(text + i) <= 'z') {
*(text + i) = *(text + i) - ('a' - 'A');
}
++i;
}
}
int main(void) {
char firstName[] = "Ivana 123";
toUpperCase(firstName);
This function must not be called with an
printf("%s", firstName);
argument that is string constant:
return 0; toUpperCase("Ivana 123");
}
Why?
© ZPR-FER-UNIZG Introduction to programming 86
Alternative solutions
void toUpperCase(char *text) {
while (*text != '\0') {
if (*text >= 'a' && *text <= 'z') {
*text = *text - ('a' - 'A');
}
++text;
}
}

void toUpperCase(char *text) {


for (; *text != '\0'; ++text) {
if (*text >= 'a' && *text <= 'z') {
*text = *text - ('a' - 'A');
}
}
}

© ZPR-FER-UNIZG Introduction to programming 87


Example
▪ Program task
▪ Write the function findFirst which receives a string and a character. If
the character exists in the string, the function returns the pointer to the
first appearance of the character found in the string, otherwise, the
function should return a suitable result based on which it will be possible
to recognize that this character is not in the string.
▪ In the main program, enter a string not longer than 50 characters and a
character, then use the function to determine where that character is
located and print the text from the position where the character was found
character to the end of the string
Enter text > Now is the time for all good men
Enter character > t
the time for all good men

Enter text > to come to the aid of their party"


Enter character > B
Character B was not found
© ZPR-FER-UNIZG Introduction to programming 88
Solution
#include <stdio.h>

char *findFirst(char *text, char c) {


while (*text != '\0') {
if (*text == c)
return text;
++text;
}
return NULL;
}
int main(void) {
char text[50 + 1], c, *res = NULL;
printf("Enter text > "); fgets(text, 50 + 1, stdin);
printf("Enter character > "); scanf("%c", &c);
res = findFirst(text, c);
if (res != NULL)
printf("%s", res);
else
printf("Character %c was not found", c);
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 89
Example
▪ Program task
▪ Write a function concatenate which receives character strings s1 and s2
as parameters. The function must change s1 so that it concatenates s2 at
the end of s1
▪ In the main program, initialize the first string to "Contents of the first
string" and print it, initialize the second string to "Contents of the
second string" and print it, call the function and print the new content
of the first string
Contents of the first string
Contents of the second string
Contents of the first stringContents of the second string

© ZPR-FER-UNIZG Introduction to programming 90


Solution
#include <stdio.h>

void concatenate(char *s1, char *s2) {


while (*s1 != '\0')
++s1;
while (*s2 != '\0') {
*s1 = *s2;
++s1;
++s2;
} Provide enough memory for the
*s1 = '\0'; result
}
int main(void) {
char s1[37 + 1] = "Contents of the first string";
char s2[] = "Contents of the second string";
printf("%s\n", s1);
printf("%s\n", s2);
concatenate(s1, s2);
printf("%s", s1);
return 0;
}
© ZPR-FER-UNIZG Introduction to programming 91
Pointers

Structures, functions and pointers

© ZPR-FER-UNIZG Introduction to programming 92


The structure is modifiable lvalue
▪ This means that the structure can be used as an argument/parameter of a
function, and can also be used as a result of a function.

struct point_s {double x; double y;};


struct point_s
translate(struct point_s point, double dx, double dy) {
struct point_s newPoint;
newPoint.x = point.x + dx;
newPoint.y = point.y + dy;
return newP;
}
int main(void) {
struct point_s p1 = {3.0, 4.0}, p2;
p2 = translate(p1, 2.0, -1.0);
printf("%lf, %lf => %lf, %lf", p1.x, p1.y, p2.x, p2.y);

3.000000, 4.000000 => 5.000000, 3.000000


© ZPR-FER-UNIZG Introduction to programming 93
Alternatively (using the structure type definition)
typedef struct {double x;
double y;
} point_t ;
point_t translate(point_t point, double dx, double dy) {
point_t newPoint;
newPoint.x = point.x + dx;
newPoint.y = point.y + dy;
return newPoint;
}
int main(void) {
point_t p1 = {3.0, 4.0}, p2;
p2 = translate(p1, 2.0, -1.0);
printf("%lf, %lf => %lf, %lf", p1.x, p1.y, p2.x, p2.y);

© ZPR-FER-UNIZG Introduction to programming 94


Alternatively (use the parameter)

▪ A solution in which the function returns the changed parameter


▪ this saves the space on the stack that was spent on the local variable
newPoint in the previous solution
struct point_s {double x; double y;};
struct point_s
translate(struct point_s point, double dx, double dy) {
point.x += dx;
point.y += dy;
return point;
}

▪ In both solutions, the argument (variable p1) did not change


▪ however, what if the position of the point as it was before the
translation does not need to be preserved? E.g.
p1 = translate(p1, 2.0, -1.0);

© ZPR-FER-UNIZG Introduction to programming 95


Pointer to a structure

▪ A function can use a pointer a structure as a parameter


struct point_s {double x; double y;};
void translate(struct point_s *ppoint, double dx, double dy) {
(*ppoint).x += dx;
(*ppoint).y += dy;
return;
}
int main(void) {
struct point_s p1 = {3.0, 4.0};
printf("%lf, %lf", p1.x, p1.y);
translate(&p1, 2.0, -1.0);
printf(" => %lf, %lf", p1.x, p1.y);

▪ instead of the whole structure, in this case only the pointer to the
structure is copied to the stack, and the function uses the
obtained pointer to change the content of the variable p1
© ZPR-FER-UNIZG Introduction to programming 96
Alternatively (using the structure type definition)
typedef struct {double x;
double y;
} point_t;
void translate(point_t *ppoint, double dx, double dy) {
(*ppoint).x += dx;
(*ppoint).y += dy;
return;
}
int main(void) {
point_t p1 = {3.0, 4.0};
printf("%lf, %lf", p1.x, p1.y);
translate(&p1, 2.0, -1.0);
printf(" => %lf, %lf", p1.x, p1.y);

© ZPR-FER-UNIZG Introduction to programming 97


Accessing structure members using a pointer

▪ Binary operator -> arrow operator


▪ the left operand is a pointer to a structure, the right operand is the
name of a structure member, the result is the structure member
struct person_s {
char lastName[40+1];
char firstName[40+1];
int height;
};
struct person_s person, *pPerson = &person;
scanf("%s", (*pPerson).lastName); or pPerson->lastName
scanf("%s", (*pPerson).firstName); or pPerson->firstName
scanf("%d", &(*pPerson).height); or &pPerson->height
...
printf("%s", (*pPerson).lastName); or pPerson->lastName
printf("%s", (*pPerson).firstName); or pPerson->firstName
printf("%d", (*pPerson).height); or pPerson->height

© ZPR-FER-UNIZG Introduction to programming 98


A structure can contain an array

▪ A structure containing an array can be used as a parameter


▪ Example: data on a student and points earned in the IPRO course are
stored in the following structure
struct points_s {
char code[13 + 1];
char firstName[50 + 1];
char lastName[50 + 1];
float midterm;
float final;
float lab[8];
};
Total 156 bytes

▪ write a function that accepts such a structure as a parameter, and


returns an integer that represents the corresponding grade
▪ usage of a structure containing an array as a function parameter is not
prohibited, but be aware of the memory consumption (stack)
© ZPR-FER-UNIZG Introduction to programming 99
Solution
#include <stdio.h>
struct points_s {
char code[13 + 1]; ...
};
int calcGrade(struct points_s points) {
int grade;
int sum = points.midterm + points.final + points.lab[...] ...
if (sum >= 50.0f && sum < 62.5f) grade = 2; else ...
return grade;
}
int main(void) {
struct points_s pointsSmith;
...
printf("The grade is %d", calcGrade(pointsSmith));
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 100


Do not abuse this capability of structures!

▪ In very bad programs, this capability is abused by "enclosing the


array within a structure" with the sole purpose of "transferring it
to function". This is a very bad idea!
struct wrappedArray_s {
int polje[1000];
};
int largestMember1D(struct wrappedArray_s wrappedArray, int n) {
...
return largest; By how many bytes does the content
} increase when the function is called?
int main(void) {
struct wrappedArray_s wrappedArray;
...
printf("Largest: %d", largestMember1D(wrappedArray, n));

© ZPR-FER-UNIZG Introduction to programming 101


An alternative solution that saves the stack
#include <stdio.h>
struct points_s {
char code[13 + 1]; ...
};
int calcGrade(struct points_s *points) {
int grade;
float sum = points->midterm + points->final + points->lab[…] …
if (sum >= 50.0f && sum < 62.5f) grade = 2; else …
return grade;
}
int main(void) {
struct points_s pointsSmith;
...
printf(" The grade is %d", calcGrade(&pointsSmith));
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 102


Example
▪ Program task
▪ A polygonal chain in the Cartesian
coordinate system is defined by a series of 4
T4
points. The point_s structure is used to T5 
3 
store data on one point (coordinates x and T6
y, type double). Data on the points 2  p2
defining the line are stored in a 1-D array 1
T0

T3

whose members are structures of type p1
point_s. 1 2
3 4
struct point_s {double x;
double y; struct point_s line[n];
};

x 1.0 x 3.0 x 4.0 x 3.0 x 3.5 x 1.5 x 0.5


y 1.0 y 0.0 y 2.0 y 1.0 y 3.5 y 3.0 y 2.0

© ZPR-FER-UNIZG Introduction to programming 103


Example
▪ Program task (continued)
▪ Write a function that calculates the total length of a polygonal chain
represented by a one-dimensional array whose members are
structures of type point_s. In the main program, enter the number
and coordinates of points, calculate and print
▪ Example of program execution
Enter the number of points > 7
Enter the coordinates of point p0 > 1.0 1.0
Enter the coordinates of point p1 > 3.0 0.0
Enter the coordinates of point p2 > 4.0 2.0
Enter the coordinates of point p3 > 3.0 1.0
Enter the coordinates of point p4 > 3.5 3.5
Enter the coordinates of point p5 > 1.5 3.0
Enter the coordinates of point p6 > 0.5 2.0
Total length is 11.912 (units)

© ZPR-FER-UNIZG Introduction to programming 104


Solution (Part 1)
#include <stdio.h>
#include <math.h>
struct point_s {double x;
double y;
};
/* calculates the distance between points p1 and p2 */
double distance(struct point_s *p1, struct point_s *p2) {
return sqrt(pow(p2->x - p1->x, 2.) + pow(p2->y - p1->y, 2.));
}
/* calculates the length of the polyline defined by points line */
double polylineLength(struct point_s *polyline, int n) {
double length = 0.;
for (int i = 1; i < n; ++i) {
length += distance(polyline + i, polyline + i - 1);
}
return length;
}
© ZPR-FER-UNIZG Introduction to programming 105
Solution (Part 2)
int main(void) {
int n;
printf("Enter the number of points > ");
scanf("%d", &n);
struct point_s polyline[n];
/* enter coordinates for n points */
for (int i = 0; i < n; ++i) {
printf("Enter the coordinates of point p%d > ", i + 1);
scanf("%lf %lf", &polyline[i].x, &polyline[i].y);
}
printf("Total length is %9.3f (units)"
, polylineLength(polyline, n));
return 0;
}

© ZPR-FER-UNIZG Introduction to programming 106

You might also like