Te Mario
Te Mario
Problem
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
Process Output
Decision Continuation
input n
Yes No
n<0
result = - n result = n
output n, result
End
if (n < 0) {
result = -1 * n;
} else {
...
if (n < 0) {
gcc -S prog1.i result = -1 * n;
} else {
...
preprocessing, compile,
linking
gcc -o prog1.exe prog1.c
prog1.o
▪ a very detailed description of all the
translation steps will be obtained by adding
the --verbose option
file
prog1.exe
prog1.c
source code
execution execution
execution execution
Structure of a C program
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;}
Keywords
Capitalization
#Include <STDIO.h>
INT Main(Void) {
Return 0;
}
Comments
▪ 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) {
...
Function main
...
int main(void) {
int k, m = 3, n = 5; m contains 3; n contains 5
... k contains "garbage"
Preprocessor directives
▪ 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
Expressions
k 5 6
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
...
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;
Operator
Operator
associativity
Priority
* / L→R
Binary + - L→R
= R→L
#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;
}
int a = 11, b = 2;
arithmetic expression result
a + b 13
a - b 9
a * b 22
a / b 5
a % b 1
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
128, -12,256
%f total width as needed, 6 the digits behind the decimal point, rounded if needed
%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
4.500000e+000,1.280000e+003,-3.455556e+000
%e width as needed, 6 digits behind the decimal point, rounded as needed
%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
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
0.010000
actually stored:
0.009999999776482582
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
syntax errors
semantic errors
results
...
int n = 0, result;
scan("%d", -n);
...
print("Input: %d Result: %d", n, result);
...
C:\ipro>
#include <stdio.h>
int main(void) {
int n, result;
scanf("%d", -n);
printf("Read n=%d\n", n);
3. Control flow
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
input(x) input x
if x ≠ 0 then No
output(x, 1/x) x≠0
Yes
output x, 1/x
▪ Caution!
if (a < 0); a = -1 * a;
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"
if…then…else
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");
input a, b input a, b
Yes No Yes No
a=b a≠b
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;
}
Cascading selection
An important digression
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.
do {
...
} while (counter < 100);
int main(void) {
int a;
float x, y;
. .
if (a > 0) {
printf("Nuber is greater than 0\n");
...
▪ 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) {
year = p_student->birt_year;
s_student.avg_grade = 4.5f;
year++;
a = -a;
▪ 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;
}
return 0;
}
switch
*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
Flowchart Pseudocode
...
while logical_expression
tijelo petlje
logical Yes statement_1
expr. statement_2
No statement_1 ...
loop body
...
statement_2
...
C program - sintax
while (logical_expression)
statement; single statement!
C program - example
...
n = 1;
while (n <= 20) {
printf("%d ", n);
n = n + 1;
}
...
#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.
}
#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;
}
Flowchart Pseudocode
...
repeat
loop body
statement_1 statement_1
loop body
statement_2
statement_2 ...
... while logical_expression
...
Yes
logical
expr.
No
C program - sintax
do
statement; single statement!
while (logical_expression);
C program - example
...
n = 1;
do {
printf("%d ", n);
n = n + 1;
} while (n <= 20);
...
#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;
}
as = 1.f * sum / counter; Multiplication by 1.f required for floating point result
printf("%d %d %f\n", sum, counter, as);
return 0;
}
max 3 3 8 45 45 72 72 72 72 72
C program - sintax
for (expression_1; expression _2; expression _3)
statement; single statement!
change of control
variable
expression_3
loop body
logical Yes
statement
expression_2
No
expression_1;
while (expression_2) {
statement;
expression_3;
}
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
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
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.
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.
#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;
}
#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;
}
#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;
}
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.
i = 1;
while (i <= 10) {
printf("%d\n", i);
}
i = 1;
while (i <= 10); {
printf("%d\n", i);
i = i + 1;
}
▪ 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
5 15 1 2 3 -4 25 6 8 7
mean = 6.800000
15
25
8
7
▪ 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)
Arrays
Structures
One-dimensional arrays
▪ 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
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]
end array 2 4 5 6 7 9
Multidimensional arrays
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];
}
}
return 0;
}
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]
Structures
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 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
...
5. Data types in C
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
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", 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
▪ Explanation:
▪ uNumber * 2 = 4000000000, 4000000000 / 2 = 2000000000
▪ sNumber * 2 = -294967296, -294967296 / 2 = -147483648
int a = 98304;
scanf("%hd", &a); enter: 10
printf("%d", a); 65546
char c1;
c1 = 'E';
65 A
97 a
10
50 2
98 b
D 68
d
2
▪ ili
char name[] = {'I', 'v', 'a', '\0'}; name I v a \0
▪ ili
▪ correctly:
char name[4+1] = {'I', 'v', 'a', 'n'}; name I v a n \0
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
... F a c u l t y i n U n s k a 3 \0 ...
Name: Ana
Surname: Novak
Address:
Ilica 1
10000 Zagreb\Center
▪ 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 ...
_Bool itIsRaining;
itIsRaining = 37;
printf("%hhd", itIsRaining);
1
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)
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)
▪ <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
0.625 ∙ 2 = 1.250
0.250 ∙ 2 = 0.5
▪ 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
▪ - 2.0
S = 1
everything else is the same as for 2.0
1100 0000 0000 0000 ... 00002 = C000 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
▪ 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
http://babbage.cs.qc.cuny.edu/IEEE-754/
Invalid
Invalid Invalid
range
range range
Range of
denormalized
numbers
Range of
normalized
numbers
▪ 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
▪ 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
float f1 = 332.3452f;
printf("%19.15f", f1);
float f2 = 0.7f;
printf("%19.15f", f2);
Unable to
Unable to Unable to
represent
represent represent
Possible
representation of
denormalized numbers
Possible
representation of
ormalized numbers
double f = 0.7;
printf("%19.17f", f);
0.69999999999999996
▪ 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
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
0.200000002980232240
0.200000001490116120
0.200000000000000010
typedef
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
2 .
2147483648.000000
2147000064.000000
2147000064.000000
123456789.000000
123456792.000000
10000000000000000303786028427003666890752.000000
inf
6. Operators
&& L→R
|| L→R
? : R→L
= *= /= %= += -= &= ^= |= <<= >>= R→L
operator , L→R
▪ 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)
int n = -5;
char c = 'A'; Expression results:
+n -5, int (operator + has no effect here)
+c 65, int (type conversion only, char → 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
Example: print the hexadecimal value of the group of 4 least significant bits of the
variable a
printf("%x", a & 0xF);
Everything said about the prefix / postfix form for the ++ operator also applies to the operator --
res = i * (i + 1);
++i;
▪ 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;
counter[index - LO_BOUND] += 1;
▪ 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
7. Functions
Introduction
#include <stdio.h>
int main(void) {
int m, n;
int i, mFact, nFact, mnFact, binCoef;
...
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;
}
▪ 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
// function to calculate n!
int fact(int n) {
int i;
int product = 1;
for (i = 2; i <= n; ++i)
product = product * i;
return product;
}
...
...
// 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;
}
General form
result_type function_name(parameter_list) {
function
definitions, declarations and statements;
body
return result;
}
▪ 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('*')); *
Mechanism of
passing the arguments and
returning the results
return 0;
}
c c c e
bottom
of stack b b b b b b b
a a a a a a a a a
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
Recursive functions
▪ 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.
▪ 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)
n 2 n 1 n 0
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
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))))
n 3 n 2 n 1 n 0
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
8. Pointers
Introduction
... ...
4294967294 00110001
4294967295 00000111
m p1
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;
▪ 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
int m;
int *pInt;
float x;
float *pFloat;
pInt = &m;
pFloat = &x;
int *p1;
int m;
m = 5;
p1 = &m;
p1 = m; Incorrect
m = p1; Incorrect
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
m p1 x p2
4 bytes 4 bytes 8 bytes 4 bytes
* 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.
1080033280
3.500000
*p1 is incorrect
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
#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
int main(void) {
82712 82742 82780
int a = 5, b = 10;
82642 82658 ?
swap(&a, &b);
x y tmp
...
in function swap
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
}
return textContainsSomething;
}
#include <stdio.h>
int main(void) {
int *res = NULL;
...
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;
}
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
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);
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]
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++;
}
...
82656 82668
p1 p2
82644 82648 82652 82656 82660 82664 82668
... 2 3 5 7 11 13 17 ...
82656 82668
p1 p2
82644 82648 82652 82656 82660 82664 82668
... 2 3 5 7 11 13 17 ...
82644 82656
p1 p2
82648 82656
p1 p2
82648 82660
p1 p2
© ZPR-FER-UNIZG Introduction to programming 66
Pointers
▪ 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
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]
m 7
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 ...
82842 82872
p2 p3
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'.
▪ 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);