• Non ci sono risultati.

DEFINITION AND

N/A
N/A
Protected

Academic year: 2021

Condividi "DEFINITION AND "

Copied!
47
0
0

Testo completo

(1)

PROGRAMMAZIONE I

A.A. 2018/2019

(2)

DEFINITION AND

DECLARATIONS

(3)

DEFINITION AND DECLARATION

Defining something means providing all of the necessary information to create that thing in its entirety.

üDefining a function means providing a function body;

üDefining a variable means allocating memory for it.

Definitions are also declarations

üNot only for functions but also for variables

Most of the time, when you declare a variable, you are also providing the definition. What does it mean to define a variable, exactly? It means you are telling the compiler where to create the storage for that variable.

(4)

IN SUMMARY

A declaration provides basic attributes of a symbol: its type and its name.

A definition provides all of the details of that symbol--if it's a function, what it does; if it's a variable, where that variable is stored.

Often, the compiler only needs to have a declaration for something in order to compile a file into an object file, expecting that the linker can find the definition from

another file. If no source file ever defines a symbol, but it is declared, you will get errors at link time complaining about undefined symbols.

There can be only one definition of the same

variable, but many declarations of it (anywhere it is used)

(5)

DIFFERENCE

A variable declaration says, "there is a variable with the following name and type in the program".

A variable definition says, "Dear Mr. Compiler, please allocate memory for a variable with the following name and type now."

(6)

EXAMPLES

int func();

int main() {

int x = func();

}

func is declared x is defined

int x;

int main() {

x = 3;

}

x is defined

int func() {

int x= 3;

}

x is defined

Of course, since a definition is also a declaration, they are also declared there

(7)

STORAGE DURATION

(8)

STORAGE CLASS SPECIFIERS

A storage class specifier in a declaration modifies the storage duration of the corresponding objects

The storage duration of an object can be automatic, static, or dynamic

auto is the storage specifier for automatic, and static is the storage specifier for static duration; dynamic is then using dynamic memory allocation/deallocation

(9)

AUTO

auto: Objects declared with the auto specifier have automatic storage duration.

This specifier is permissible only in object declarations within a function.

In ANSI C, objects declared within a function have automatic storage duration by default, and the auto specifier is archaic.

int main(void) { int a;

{

int count;

auto int month;

} a++;

} auto is not used in programs…

(10)

REGISTER

register: You can use the specifier register when declaring objects with automatic storage duration.

The register keyword is a hint to the compiler that the object should be made as quickly accessible as

possible—ideally, by storing it in a CPU register.

However, the compiler may treat some or all objects

declared with register the same as ordinary objects with automatic storage duration.

In any case, programs must not use the address

operator on objects declared with the register specifier.

(11)

EXAMPLE

{

register int miles;

}

{

register int miles;

int* p= &miles;

}

(12)

STATIC

Static: a variable identifier defined with the specifier static has static storage duration.

It is created as soon as the program starts, and destroyed (removed from memory) only when the program ends.

Global variables automatically have static storage duration.

(13)

EXAMPLE

int x= 0;

int main() {

x = 3;

}

This is the definition of a global variable (x), which has static storage duration

int main() {

static int x = 3;

}

This is the definition of a local variable (x), which has static

storage duration, because I used storage specifier static

(14)

SCOPE AND STORAGE DURATION

There are two separate concepts here:

üscope, which determines where a name can be accessed, and

üstorage duration, which determines when a variable is created and destroyed.

Automatic variables (pedantically, variables with

automatic storage duration) are local variables whose

lifetime ends when execution leaves their scope, and are recreated when the scope is reentered.

Static variables (pedantically, variables with static

storage duration) have a lifetime that lasts until the end of the program. If they are local variables, then their

value persists when execution leaves their scope.

(15)

EXAMPLE 1

void f() { int i;

i = 1; // OK: in scope }

void g() {

i = 2; // Error: not in scope }

int i;

void f() {

i = 1; // OK: in scope }

void g() {

i = 2; // OK: still in scope }

Local variables (pedantically, variables with block scope) are only accessible within the block of code in which they are declared:

automatic storage duration

Global variables (pedantically, variables with file scope) are accessible at any point after their declaration: static storage

duration

(16)

EXAMPLE 2

// prints 1 2 3 4 5 - the value persists // n has static storage duration

// prints 1 1 1 1 1 - the previous value is lost // n has automatic storage duration

// it is created anew for every loop iteration // and destroyed at the end

for (int i = 0; i < 5; ++i) { int n = 0;

printf("%d ", ++n);

}

for (int i = 0; i < 5; ++i) { static int n = 0;

printf("%d ", ++n);

}

(17)

EXAMPLE 3

for (int i = 0; i < 5; ++i) { static int n = 0;

printf("%d ", ++n);

}

printf("%d ", n);

// error: out of scope

Being forever in memory does not mean that a variable is always accessible: it is accessible in its scope

(18)

EXAMPLE 4

#include<stdio.h>

void func(void);

int count=10;

int main() {

while (count--) func();

}

void func( void ) {

static int i = 5;

i++;

printf("i is %d and count is %d\n", i, count);

}

i is 6 and count is 9 i is 7 and count is 8 i is 8 and count is 7 i is 9 and count is 6 i is 10 and count is 5 i is 11 and count is 4 i is 12 and count is 3 i is 13 and count is 2 i is 14 and count is 1 i is 15 and count is 0 Static storage is the default for

variables outside functions

(19)

EXAMPLE 5

#include<stdio.h>

void func(void);

int count=10;

int main() {

while (count--) func();

i++;

}

void func( void ) {

static int i = 5;

i++;

printf("i is %d and count is %d\n", i, count);

}

MacBook-Francesco:ProgrammI francescosantini$ gcc -std=c99 -o test test.c test.c:11:4: error: use of undeclared identifier 'i'

i++;

^

1 error generated.

i static but not visible in main

(20)

EXAMPLE 6

#include<stdio.h>

void func(void);

int main() {

while (count--) func();

}

int count=10;

void func( void ) {

static int i = 5;

i++;

printf("i is %d and count is %d\n", i, count);

}

MacBook-Francesco:ProgrammI francescosantini$ gcc -std=c99 -o test test.c test.c:8:11: error: use of undeclared identifier 'count'

while (count--)

^

1 error generated.

count visible from here

(21)

STATIC STORAGE

Global variables, or variables within a function and with the storage class specifier static, have static storage duration.

All objects with static storage duration are initialized to 0 automatically.

Objects with automatic storage duration are not initialized to 0 by default, their value is undefined

ü It is better to always initialize variables to 0 (especially variables with automatic storage duration)

int main() { static int a;

}

int main() { int a;

}

// initialized to 0 // not initialized

(22)

DIFFERENT KINDS OF

MEMORIES

(23)

DIFFERENT ZONES IN MEMORY

All your variables (and instructions) are in memory

(24)

CHARACTERISTICS

Permanent area contains both global and static variables (and instructions): variables with static storage duration.

üSuch variables are created when the program starts end destroyed when the program ends

Local variables are memorized in the stack: it contains variables with automatic storage duration.

üTheir duration in memory begins when their definition is encountered and ends at the end of their scope

The memorization of objects in the heap area is fully under the control of the programmer

üTheir duration in memory starts when a programmer allocates it (e.g. malloc()), and ends the a programmer deallocates it (free())

(25)

EXAMPLE

int main () { int a1[3];

int * a2 = (int*) malloc(3 * sizeof(int));

}

a2[0] a2[1] a2[2]

malloc(3 * sizeof(int));

1000 1004 1008 1012

a2 == 1000

(26)

EXAMPLE

#include <stdio.h>

int size= 5;

void fun(int* b, int n) { for (int i = 0; i < n; ++i ) {

static int c= 0;

b[i] = ++c;

} }

int main(){

int* a = (int *) malloc(sizeof(int) * size);

fun(a, size);

fun(a, size);

}

a[0]

a

a[1]

a[2]

a[3]

size

c

a[4]

(27)

EXAMPLE (CONT.)

#include <stdio.h>

int size= 5;

void fun(int* b, int n) { for (int i = 0; i < n; ++i ) {

static int c= 0;

b[i] = ++c;

} }

int main(){

int* a = (int *) malloc(sizeof(int) * size);

fun(a, size);

fun(a, size);

free(a); // REMEMBER TO FREE ALLOCATED MEMORY }

a[2]

3

a[3]

4 a[1]

2

a[4]

5 a[0]

1

a[2]

8

a[3]

9 a[1]

7

a[4]

10 a[0]

6

(28)

STACK AND FUNCTIONS

(29)

CALL STACK

In computer science, a call stack is a stack data structure that stores information about the active subroutines of a computer program.

This kind of stack is also known as an execution stack, program stack, control stack, run-time stack, or machine stack, and is often shortened to just "the stack".

Since the call stack is organized as a stack.

(30)

STACK

In computer science, a stack is an abstract data type that serves as a collection of elements, with two principal

operations: push, which adds an element to the

collection, and pop, which removes the most recently added element that was not yet removed.

The order in which elements come off a stack gives rise to its alternative name, LIFO (for last in, first out).

a

push b

pop push c

d

(31)

CALL TO FUNCTIONS AND STACK

include<stdio.h>

void f2() { int c;

puts(“bye f2”);

}

void f1() { int b= 0;

f2();

puts(“bye f1”);

}

int main() { int a= 0;

f1();

puts(“bye main”);

}

a b c bye f2

bye f1 bye main

1000 1004

1008

stack

(32)

EXAMPLE 2

include<stdio.h>

void f1();

void f2() { int c;

f1();

puts(“bye f2”);

}

void f1() { int b= 0;

f2();

puts(“bye f1”);

}

int main() { int a= 0;

f1();

puts(“bye main”);

}

a b c b c . . .

MacBook-Francesco:ProgrammI francescosantini$ ./test Segmentation fault: 11

(33)

STACK OVERFLOW

Also the size of the stack is limited (as the heap) It cannot grow infinite

üNothing is infinite in a computer

In the example before, the stack grows up until it reaches a zone of memory that it cannot access anymore

üSegmentation fault

(34)

ALSO MEMORY ADDRESS

int fun(int p1, int p2, int p3) { int res= 0;

res= p1 + p2 + p3;

return res;

}

int main() {

int a= 4, b= 5, c= 7;

a= fun(a,b,c);

}

a b c The stack grows from bottom to top, heap is different

p1 p2 p3 return address

res

(35)

RECURSIVE FUNCTIONS

(36)

DIRECT AND INDIRECT

A recursive function is one that calls itself, whether directly or indirectly.

Indirect recursion means that a function calls another function (which may call a third function, and so on), which in turn calls the first function.

Because a function cannot continue calling itself

endlessly, recursive functions must always have an exit condition

(37)

HOW TO WRITE A RECURSIVE FUNCTION

You need to find base values when to stop a recursive function

Each successive call to such a function takes values that are closer to base values [RECURSIVE STEP], until you reach base values

(38)

EXAMPLE

int fatt(int n) { if (n<=1)

return 1; // Base case else

return n * fatt(n-1); // Value simplification }

int main() { int a= 4;

int res= fatt(a);

printf(“%d”, a);

}

(39)

HOW IT WORKS

When a function calls itself, it suspends its execution to execute a new call (to itself)

When the last call terminates because base values are found, then a value is returned to the previous call and so on

(40)

CALLS

main fatt(4) fatt(3) fatt(2) fatt(1)

int fatt(int n) { if (n<=1)

return 1; // Base case else

return n * fatt(n-1); // Value simplification }

int main() { int a= 4;

int res= fatt(a);

printf(Valore “%d”, res);

} main

fatt(4) fatt(3) fatt(2) fatt(1) 2 1

24 6

Valore 24

(41)

EXAMPLE 2

int fibonacci(int n) {

if ( n == 0 ) return 0;

else if ( n == 1 ) return 1;

else if (n >= 2)

return ( fibonacci(n-1) + fibonacci(n-2) );

}

1 1 2 3 5 8 13 21

(42)

REMARKS

Recursive functions depend on the fact that a function’s automatic variables are created anew on each recursive call. These variables, and the caller’s address for the

return jump, are stored on the stack with each recursion of the function that begins.

Recursive functions are a logical way to implement algorithms that are by nature recursive, such as the

binary search technique, or navigation in tree structures.

However, even when recursive functions offer an elegant and compact solution to a problem, simple solutions

using loops are often possible as well.

(43)

PROS AND CONS

Pro: for some problems, it is possible to solve a problem with few lines of code, for example, Fibonacci and

Factorial.

Cons: recursion is not efficient, because you repeatedly call functions, and this implies to create a new execution environment on the stack, for each of the opened

functions. More time (to create it) and memory space consuming.

(44)

WHEN TO USE IT

Every recursive problem can be solved in a non-

recursive way (i.e., iteratively). However, the iterative solution might be more complex to code

Where you do not have any particular memory or time

efficiency problems, you can prefer a recursive solution if the solution is more intuitive.

(45)

A NON RECURSIVE EXAMPLE

double fib(int n) {

double prev = -1;

double result = 1;

double sum;

int i;

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

sum = result + prev;

prev = result;

result = sum;

}

return result;

}

(46)

HOW IT IS EXECUTED

If you have fib(1) + fib(0) you do not know which one of the two is executed first!!!

(47)

STACK OVERFLOW

#include <stdio.h>

int factorial(int n) {

// What about n < 0?

if(n == 0) {

return 1;

}

return factorial(n-1) * n;

}

int main(void) {

int i= factorial(-1);

printf("%d\n", i);

}

Remember to have a closing case, otherwise a function keep on calling itself forever, or, better until there is a stack overflow

MacBook-Francesco:ProgrammI francescosantini$ ./test Segmentation fault: 11

Riferimenti

Documenti correlati

This paper seeks to add to the existing literature on water utility management by investigating whether the corporate go- vernance of water utilities (i.e. their ownership, board

The demonstration that the in- crementality of postural hand synergy enrollment is also preserved for optimal force distribution can be indeed ex- ploited for the development of

The muon channel has more expected background events than the electron channel owing to the lower p miss T requirement on the muon and its worse mass resolution at high p T.. Figure

Attraverso un'approfondita analisi dei documenti disponibili, in gran parte inediti, il libro dello storico Marco Cuzzi si propone di dare un contributo significativo alla

The time-based shortest path algorithm offers information on the connecting airport and the time of each intermediate connection.8 Table 8 shows the average number of fastest

1 Our econometric models suggest that the determinants of exit from an academic research career include scientific productivity and academic network which are

The resulting algorithm has several distinctive features compared to previous tools, particularly for scoring inter- actions among groups of mismatches, non-canonical 3Q sites and

At long times, the system exhibits a local quasi-stationary state (LQSS) on each ray x=t, as it happens for homogeneous integrable ballistic systems, but with a non-trivial behaviour