Estratto del documento

Programma e algoritmo

Programma: non è detto che termini (se termina con qualsiasi dato allora si può definire algoritmo).

Funzione main

main(): può anche non contenere dati.

int main(): ritorna un intero per indicare che se:

  • Restituisce 0: ha fatto ciò che doveva fare.
  • Altrimenti restituisce un altro numero (errore).

Se nel Main non metto return, funziona (possibilità data solo dal main il quale ha return di default).

return: è una keyword / parola chiave.

Oggetto cout

cout: oggetto di tipo ostream <<, ::, ;, () operatori.

Tipi di dati

int: se inizia con 'O' si considera ottale; con 'Ox' si considera esadecimale. 'Oul' unsigned long.

'0.0', '0.', '.0': sono numeri con la virgola di tipo double. '0.0f ': numeri con la virgola di tipo float.

Interi: short, int, long, long long, signed e relativi unsigned, unsigned char, char.

char è un intero (piccolo) speciale perché stampando si ottiene un carattere.

Manipolazione del buffer

endl: svuota il buffer (cache): è una funzione.

/n: non svuota il buffer.

Libreria e header file

Libreria: pacchetto che contiene funzioni già pronte.

#include <iostream>: è parte del codice sorgente (header file), non è una libreria. Senza <iostream> ottengo un errore di mancata dichiarazione del cout.

Header file: Un header file (o file di intestazione) è un file che aiuta il programmatore nell'utilizzo di librerie durante la programmazione. Un header file è un semplice file di testo che contiene i prototipi delle funzioni definite nel relativo file cc. I prototipi permettono al compilatore di produrre un codice oggetto che può essere facilmente unito con quello della libreria in futuro, anche senza avere la libreria sottomano al momento.

  • Dichiarazione: con essa si indica che esiste un'entità con un certo nome (non forniamo un'implementazione particolare).
  • Definizione: si fornisce anche l'implementazione.

int a=0; // è una inizializzazione quindi viene definita e non dichiarata.

extern int a; //fornisce una dichiarazione di variabile senza inizializzarla (grazie all’extern).

extern int a=0; //definizione.

extern std::ostream cout; //write one - in questo modo la modifico una sola volta nel header file e si modifica ovunque. Anche l'operatore << va ridefinito per usare cout e endl.

Compilatore G++

Opzioni:

  • - W: warming (attiva) ti dice se c'è qualche errore (“massimo livello”).
  • - Wall: controlla “tutti” gli errori.
  • - Wextra: controlla errori extra.
  • - O: dove salva l'output.
  • - E: restituisce il numero di caratteri di "hello.preproc.cc", il file creato dal processore prima di usare il compilatore. "hello.preroce.cc" contiene tutto (anche gli #include).
  • - LDD: dice quali librerie invoca il programma.
  • - Wcin e Wcout: lavorano su carattere più estesi (con più possibili simboli).

Esempi di codice

"G++ -Wall - Wextra hello.cc -O hello"

Esegue il programma indicando eventuali warming

"(G++ -Wall - Wextra hello.cc -O hello) && echo OK"

Se stampa OK è giusto quindi il programma funziona

"G++ -S -Wall - Wextra hello.cc -O hello.s"

Fa una traduzione in assembler (in codice oggetto). In codice oggetto tutti i nomi vengono resi unici (name engley).

"G++ -C -Wall - Wextra hello.cc -O hello.o"

Genera il codice oggetto in binario.

"G++ -E -Wall - Wextra hello.cc -O hello.preproc.cc"

Restituisce il numero di caratteri di "hello.preproc.cc", il file creato dal processore prima di usare il compilatore.

Preprocessore e unità di traduzione

Preprocessore: svolge funzioni prima del compilatore.

Unità di traduzione: è il file che il compilatore compila.

  • Ci sono tante unità di traduzione e su ognuna si applica la compilazione.

Errori

  • Errori sintattici: (soggetto -> verbo -> compilazione oggetto) se non si segue questo schema si sbaglia.
  • Errori di semantica statica: sommare intero e stringa.
  • Errori di semantica dinamica: provo a leggere un indirizzo di un array che però non si a dove punta.
  • Errori grammaticali: usare parole che non esistono nel linguaggio.

Undefined Behavior (UB): problema non risolto ed è colpa tua.

unsigned namespace std; evita alcune ambiguità fra i nomi.

using std::cout; , using std::endl; prende dalla libreria std solo i nomi che servono (posso usare cout senza ambiguità).

  • Meno “roba si tira dentro” più nomi posso usare per variabili.
  • Ma usare tanti using rende il codice meno riutilizzabile.

Le identità di std sono: cout, endl, <<, ...

<< però non ha mai davanti std::

Namespace

Namespace: una collezione di nomi di entità, definite dal programmatore, omogeneamente usate in uno o più file sorgente.

Lo scopo dei namespace è quello di evitare confusione ed equivoci nel caso siano necessarie molte entità con nomi simili, fornendo il modo di raggruppare i nomi per categorie.

  • Errore di non dichiarazione

Se si cerca di utilizzare una variabile fuori dallo scope della variabile stessa.

Scope: campo di azione (di una variabile).

  • Errore di non definizione

extern int a; cout << a << endl; // errore perché non so cosa stampare

"G++ -Wall - Wextra -nostdlib hello.o a.o -O hello"

  • - nostdlib: non include la libreria std
  • - hello.o a.o: collego più file oggetto.

Se in hello.o e a.o definisco a, mi darà un errore di doppia definizione.

#include<iostream>: cerca tra gli header file del sistema

#include "a.hh": cerca nella directory stessa il file a.hh

Le entità globali è meglio metterle in un file che poi verrà incluso (a.hh).

Segmentation fault e core dumped

Segmentation fault: Si verifica quando un programma tenta di accedere ad una posizione di memoria alla quale non gli è permesso accedere, oppure quando tenta di accedervi in una maniera che non gli è concessa.

Core dumped: caduta improvvisa del programma. Si verifica ad esempio, se si è riempito lo stack.

Continuando a diminuire un numero intero si arriva al minimo numero intero dopo il quale si passa al valore intero più grande.

- Errore di implementazione: i valori di un intero sono implementati.

Per i numeri senza segno, superando il massimo si ottiene lo 0.

Funzione unsigned long longfatt

unsigned long longfatt(unsigned...)

  • Meglio andare a capo.
  • Se una funzione richiede un unsigned int nulla vieta che l'utente la richiami con ad es -1

unsigned fact (unsigned n) {if (n==0U) …}

  • Unsigned controlla che il valore sia zero unsigned (se l'utente passa -1 non funziona)
  • Posso anche indicare con un commento quali sono i valori accettati

Controllare gli errori

Modi:

  • Variabile globale: sempre a zero che cambia in base all'errore. Problema: ogni volta che si richiama una funzione, c'è da controllare l'errore.
  • Modificare la variabile per generare un errore. Problema: anche qui da controllare ogni volta. Si potrebbero avere dei valori che hanno senso ora ma magari in futuro no.
  • Try catch
  • Asserzioni (assert)

Try Catch

Eccezioni: di default non potete ignorarle (anche se ci si dimentica, si propagano finché tale errore non viene gestito).

  • Non sporca il risultato.

if (n<0) throw 123; //Usando ad esempio codici numerici di errore specificati in un documento a parte.

Il throw però costa quindi scarico la responsabilità sull'utente scrivendo in una documentazione cosa necessita la funzione per funzionare.

Compromesso tra gestione degli errori mia o dell'utente:

Assert

Funzioni che restituiscono vero o falso in modo da sapere la riga di errore (assert (n>=0);).

Per usare assert serve #include<cassert>.

Durante il debug quindi verrà usato assert (controllo) per trovare l'errore.

"G++ -Wall - Wextra -dndebut hello.cc a.cc -O hello"

  • - dndebug: non fa il debug
  • Se non si fa il debug gli assert non vengono effettuati.

Sapere il valore massimo rappresentabile (in C++)

Massimo per un tipo:

  • numeric_limits<char>::max();
  • CHAR_MAX
  • SCHAR_MAX // S -> signed
  • UCHAR_MAX // U -> unsigned

Minimo per un tipo:

  • numeric_limits<char>::min();
  • CHAR_MIN
  • SCHAR_ MIN // S -> signed
  • UCHAR_ MIN // U -> unsigned

Modo per avere numeri lunghi a piacere (in C++)

È necessario includere una libreria che gestisca tali numeri.

ESEMPI

File: a.hh

#include <gmpxx.h>

extern int a;//deve essere invocato con n>=0

mpz_class fact(mpz_class n);

File: hello

#include "a.hh"

#include <limits>

#include <iostream>

int a; //SE globale, di default è definita = 0; con “explicit” non sarebbe definita

void funz(...) {

int a; //SE non globale, non è definita di default

auto b = 3.2; //determina in automatico il tipo della variabile

auto int a; //nel c++ 11 non si può più fare; nelle vecchie versioni, definiva “a” di dafault a 0

}

int main() {

std::cout << "hello" << std::endl;

std::cout << a << std::endl;

std::cout << sizeof (int); // restituisce la dimensione in byte del tipo specificato

int i=0;

short j=4;

i + j; // ”j” viene convertito da short ad intero temporaneamente per svolgere l’operazione.

j + j; // anche qui ”j” viene trattato come intero perché è il tipo numerico più efficiente.

j = j + j;// tutte le volte che uso short, char etc in operazioni, essi vengono promossi ad interi e si produce un intero che eventualmente può essere riconvertito in short se viene assegnato a short.

const int SIZE = 100;

int ai[SIZE]; // viene allocato uno spazio di 100; lo spazio da occupare deve essere definito nel momento della dichiarazione

ai[10] = 34; // alla funzione si passa il puntatore al primo elemento del vettore (decadimento del tipo)

//avviene questo decadimento per evitare di dover copiare l'intero array nel momento del passaggio per valore)

//anche in ai[10] = 34; decade il tipo a puntatore

ai[j] == *((ai)+(j)); //true; anche la seconda è una giusta scrittura del linguaggio

// * va a leggere nel puntatore calcolato

&ai[0] == &(*(ai)+(0)) == & (* ai) = ai;

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

fai_qualcosa_di_intelligente_con(a[i]); // ”a[i]” è considerato in automatico un puntatore; nel caso successivo no quindi devo specificare

for (int* pi=ai; pi != ai + SIZE; ++pi) //pi non è considerato un puntatore quindi devo specificare

fai_qualcosa_di_intelligente_con(*pi);

int* p = &SIZE; // Errore perché io potrei modificare liberamente il puntatore ma SIZE è const quindi:

const int* p = &SIZE; //puntatore varia, il valore resta costante -> const (int* p) = &SIZE;

int* const p = &SIZE; //puntatore costante, valore variabile -> int* (const p) = &SIZE;

const int* const p = &SIZE; //a sinistra del * si parla dell'oggetto puntato, a destra si parla del puntatore -> oggetto puntato * puntatore -> const (int* const (p)) = &SIZE;

const int* q;

{ const int* p = &SIZE;

q = &p;}

//termine del blocco

std::cout << *q;//Il puntatore ”q” punta ad un valore che però al termine del blocco smette di esistere e quindi il puntatore "penzola"

//Il puntatore deve essere cancellato prima del valore puntato.

int* pi = new int(18); //new = creami una porzione di memoria di intero, inserisci 18, e il puntatore punterà a tale oggetto

delete pi; //elimina oggetto puntato ma non il puntatore

pi = NULL; //punta a vuoto

pi = nullptr; //nuovo standard c++

namespace pippo {

int a = 7;}

...

namespace pippo {

... //qui vale ancora la definizione di a}

int funz(...) {

using pippo::a; // la ridefinizione vale fino al termine di questo blocco

using namespace pippo; // utilizza tutte le dichiarazioni fatte in pippo

static int a=0; // vale anche dopo la chiusura del blocco fino al termine del programma

++a;}

FINE esempi

Il carattere è la cosa più piccola indirizzabile in c++.

Il bool varia ma è almeno 1 byte (in alcune macchine è anche 4 byte).

Nella libreria std vengono definite classi chiamate trace come la classe numeric_limit (#include <limits>).

Il codice generico è un codice che funziona indipendentemente dal dato usato e per fare ciò bisogna sapere i limiti di un tipo.

  • Se si converte un intero a floating point si potrebbe avere errore di arrotondamento se il numero intero è troppo grande.
  • I floating point vanno usati solo in 2 casi:
    • Non vi interessa molto il risultato finale
    • State usando un algoritmo in cui si sa che l'errore è contenuto entro un certo range
  • Esempio di instabilità dei float: lo 0,1 che è sempre arrotondato.

Bisogna conoscere il motivo per cui certi costrutti esistono per capire se vanno usati o no.

Array

Array è un tipo di dato composto (formato da più dati).

++i --> calcola il valore e poi modifica lo stato del programma.

È meglio il preincremento (per leggibilità perché si capisce prima cosa vuole fare il programmatore).

  • Un array si può indicare con il range [ai, ai + size)

* expr: estrae l'oggetto puntato

& expr: estrae l'indirizzo di un oggetto

I puntatori permettono di creare array che non debbano avere la dimensione specificata nel momento della dichiarazione.

Scope di una variabile = DOVE è valida

Ciclo di vita di una variabile = QUANDO nasce e quando muore

Ciclo di vita

  • Allocazione statica = variabili globali (in certi casi anche locali). Prima di far partire l'esecuzione si alloca la memoria per le variabili globali. Quando termina il programma, tali variabili verranno deinizializzate (distrutte) e poi deallocate (restituire lo spazio della memoria al sistema).
  • Allocazione automatica tramite stack: nascono quando ad esse viene data una definizione (fino ad allora sullo stack non ci sono); viene deallocata al termine del blocco.
  • Allocazione dinamica: gestisco io le risorse del programma; decido io quando far morire un oggetto.

Io creo un puntatore pi ad oggetto, ma alla chiusura di un blocco il puntatore muore e quindi non ho più modo di trovare l'oggetto puntato.

Si risolve questo problema facendo delete pi;. Questo comando elimina l'oggetto puntato ma NON il puntatore.

Memory leak = quando si cancella il puntatore senza cancellare l'oggetto puntato.

Campi d'azione

  • namespace (campo d'azione globale).

extern std::ostream cout; --> variabile dichiarata a livello di namespace (scatole).

int a=7; --> namespace globale (senza nome).

Una variabile globale è presente ovunque (se la includo).

Eccezioni: se la a viene ridefinita all'interno di un altro blocco, allora la seconda a nasconderà quella globale fino al termine del blocco.

Variabile statica (static): vale come globale (dopo che è stata dichiarata)

Puntatori e riferimenti

int a;

int* pa = &a;

int& ra = a;

const int& ra = a; //posso fare modifiche su ra ma non su a

*pa; //restituisce l'oggetto puntato

a; //si riferisce già all'oggetto

  • Col puntatore si ha a che fare con due oggetti (puntatore e oggetto puntato).
  • Col riferimento si ha solo un oggetto (che è l'oggetto a cui punta).
  • Il puntatore occupa memoria, il riferimento no (l'oggetto occupa sempre memoria).
  • Il riferimento non può riferirsi a nulla, il puntatore si.
  • Il riferimento è "appiccicato" allo specifico oggetto, il puntatore invece può puntare ad altri oggetti diversi.

Passaggio dei valori ad una funzione

Quando passo i valori ad una funzione come li passo?

  • In C SOLO per valore (copia del valore passato)
  • In C++ si può passare sia per valore sia per riferimento (la funzione userà un suo nome per riferirsi al valore passato)

void fun(int a) //qualsiasi modifica fatta su a non si ripercuote all'esterno

void fun(int* pa) //le modifiche fatte sul puntatore non si ripercuotono sull'esterno, ma quelle sull'oggetto si

void fun(int &a) //si modifica anche all'esterno l'oggetto a

Si usa sempre il passaggio per valore tranne quando:

  • Voglio che la modifica fatta al valore passato si ripercuota sull'esterno.
  • Se il valore è troppo grande meglio non copiarlo quindi usare il passaggio per riferimento o puntatore.

Puntatori o riferimento?

  • I puntatori sono scomodi
  • I riferimenti sono più semplici dato che hanno un solo oggetto
  • Passare il puntatore dà l'impressione che la funzione modifichi il puntatore (bisogna specificare se è nullo o no); con i riferimenti non esiste il caso "nullo".
  • Uso il puntatore solo se necessario (spostarlo).

Tipi predefiniti scalari e non scalari

Non scalari: array, struct/class; insieme di oggetti dello stesso tipo.

Scalari: valore numerico singolo e le operazioni effettuabili su di esso.

  • Deprecato usare ++ su un bool, cioè meglio evitare anche se è possibile farlo senza errori
  • Array: blocco di oggetti di dimensione determinata
  • struct / class: di default nella struct i valori sono public, nella class invece private.

struct Razionale;

struct Razionale{

int num;

int den;};

Razionale r;

int fun() {

r.num;}

Razionale* pr = &r;

int bar() {*pr.num; //sbagliato

(*pr).num; //giusto

pr --> num; //più elegante di quello sopra ma fa la stessa cosa

a[i] == i[a]; //con i intero ed a array}

sizeof(r); //è sicuramente maggiore o uguale alla somma dei sizeof dei singoli campi

struct Razionale {

int num; //4 byte

char c; //1 byte

int den; //4 byte

short p; //2 byte}

< 4 byte > : num

< 1 byte > < padding 3 byte > : c

< 4 byte > : den

< 2 byte > < padding 2 byte > : p

Anteprima
Vedrai una selezione di 23 pagine su 106
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 1 Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 2
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 6
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 11
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 16
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 21
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 26
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 31
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 36
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 41
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 46
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 51
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 56
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 61
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 66
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 71
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 76
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 81
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 86
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 91
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 96
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 101
Anteprima di 23 pagg. su 106.
Scarica il documento per vederlo tutto.
Metodologie Programmazione - Tutto (teoria, pratica e esercizi) Pag. 106
1 su 106
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher Mr.Al di informazioni apprese con la frequenza delle lezioni di Metodologie di programmazione e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Parma o del prof Scienze matematiche Prof.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community