Estratto del documento

Variabili

Una variabile identifica una porzione di memoria destinata a contenere dei dati, che possono essere modificati durante l’esecuzione del programma.

  • Devono essere dichiarate prima di essere utilizzate;
  • Formato -> tipo nome;
  • La sua dichiarazione può essere anche combinata con la sua inizializzazione -> tipo nome = valore_iniziale;

Nome di una variabile

Il nome di una variabile deve rispettare alcune regole: deve iniziare con una lettera o un underscore, può essere seguito da una qualsiasi combinazione di lettere (maiuscole o minuscole), underscore e cifre da 0 a 9, non dev’essere una parola riservata (tipo int int).

Case sensitive

Le lettere maiuscole e minuscole sono diverse.

Valori a doppia precisione

I valori a doppia precisione con tipo double sono costituiti da 8 byte. Il formato è simile al formato di tipo float con la differenza che il numero viene rappresentato con un esponente a 11 bit in eccesso 1023 e con una mantissa a 52 bit, più 1 bit più significativi implicito.

Il tipo double contien 64 bit: 1 per il segno, 11 per l’esponente e 52 per la mantissa (parte decimale del numero). Questo formato specifica un intervallo di valori inclusi approssimativamente tra 1,7E-308 e 1,7E+308 con almeno 15 cifre di precisione.

Debugger

Un debugger C è un programma che consente agli sviluppatori di esaminare il codice sorgente delle loro applicazioni in C, individuare eventuali errori e correggerli. Esso consente di eseguire il passo per passo dell'esecuzione del codice, ispezionare le variabili e impostare dei punti di interruzione per sospendere l'esecuzione del programma e investigare lo stato del sistema. Ciò rende possibile individuare e correggere gli errori nel codice in modo più efficiente.

Esempio di utilizzo di un debugger

Supponiamo di avere un codice C che calcola la media di alcuni numeri. Il codice sembra funzionare correttamente, ma quando si esegue il programma, si ottiene un risultato imprevisto. Utilizzando un debugger C, si può impostare un punto di interruzione all'interno della funzione di calcolo della media, esaminare il valore delle variabili in quel punto e capire perché il risultato non è quello atteso. In questo caso si potrebbe scoprire che è stato dimenticato di inizializzare una variabile che influisce sul risultato finale.

Ciclo for e while

Ciclo for – ciclo enumerativo (definito)

While-do o do-while – ciclo indefinito. Le due forme differiscono nel fatto che la do-while controlla alla fine se deve essere ripetuto o se può continuare con il codice; mentre il while-do controlla all’inizio per cui se la condizione del ciclo non è rispettata neanche una volta il ciclo viene saltato.

Esempio di codice sul quale useremo il debugger

#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>
#include <iostream>

int main() {
    float totaleScontrino = 0, costoProdotto = 0;
    char risposta;
    do {
        char risposta2; //seconda variabile per seconda risposta. NOTARE che nome variabile è diverso
        totaleScontrino = 0; /*SI GESTISCE UNO SCONTRINO PER OGNI CLIENTE -ogni volta che riparte il ciclo esterno è importante che il totale venga impostato a zero perché si tratta di un cliente diverso*/
        do {
            printf("\nQuanto si paga per il prossimo prodotto? "); //finché ci sono prodotti si aggiunge un prezzo
            scanf("%f", &costoProdotto); //dove si legge costo prodotto che viene aggiunto al totale
            totaleScontrino += costoProdotto; //+= la variabile a sx viene incrementata del valore a dx
            printf("\nCi sono altri prodotti? (s/n) ");
            scanf(" %c", &risposta2);
        } while (risposta2 != 'n');
        printf("\nQuesto cliente paga: %0.2f!\n", totaleScontrino);
        printf("\nCi sono altri clienti? (s/n) ");
        scanf(" %c", &risposta);
    } while (risposta != 'n');
    return 0;
}

Debugging

Debugging -> andare in “opzioni” – “opzioni del progetto” – “compilatore” – “linker” – “genera le informazioni per il debug” – “sì”. Con il debugger è possibile far fermare il programma su una determinata riga selezionandola, inserendo un break point. Si fa partire il debug e su questo eseguibile (SELEZIONARE LA VOCE SOURCE - ci interessa vedere la sorgente del programma). Verrà mostrata una finestra di esecuzione per mostrare che il debugger sta controllando l’esecuzione del programma. Mentre il programma è in esecuzione si possono controllare quante valgono le variabili semplicemente passandoci sopra con il mouse. Il valore risulterà senza senso finché tale variabili non verrà inizializzata. Cliccare su “step” o passo successivo per mandare avanti e far inizializzare le variabili.

Controllo delle variabili con il debugger

Il debugger salta le righe che sono semplicemente delle dichiarazione come quelle delle variabili, le righe di strutture come quelle del do. La prima vera istruzione è quella di “totaleScontrino = 0”. Ma alcune variabili, comunque, come “float totaleScontrino = 0” ora passandoci sopra con il mouse avrà valore 0.

Con il debugger si possono tenere in considerazione molte cose: STACK, REGISTER (CPU), MEMORY ECC. Può essere scomodo però passare il mouse su ogni valore delle variabili. Quando abbiamo idea di che righe controllare si possono aggiungere alla finestra dei watches cioè delle variabili osservate. VIEW – WATCH EXPRESSION -> si scrivere il nome della variabile che servirà mettere sotto controllo. Variabile messa perennemente in tempo reale sotto controllo. Metter sotto controllo più variabili locali in un colpo solo – “LOCAL VARIABLES”. La finestra WATCH EXPRESSION non è un copione di variabili locali, perché alcune potrebbero essere anche globali. Poi non è WATCH VARIABLES ma EXPRESSION quindi si può chiedere di calcolare espressioni più complicate che vanno comunque ad utilizzare le variabili.

totaleScontrino = 0 //variabile

totaleScontrino * 1.2 = 0 //espressione, sempre 0 perché variabile = 0

Ora mandando in esecuzione il programma si vedrà in tempo reale l’esecuzione. Si può cambiare anche in tempo reale il valore di una variabile direttamente dalla finestra di WATCH EXPRESSION.

ORA MOSTRO PROGRAMMA CON ERRORE In esecuzione se è stato risposto no (‘n) perché mi richiede l’inserimento? Si utilizza il DEBUGG come prima. Si utilizzano i break point per far fermare il controllo del debug fino al punto dove si vuole che arrivi il controllo. In questo caso il problema è il fatto delle lettere se maiuscole o minuscole perché C è case sensitive. Il programma non è capace di capire che la volontà dello user è la stessa indifferentemente se la lettera è maiuscola o minuscola. NON È UN ERRORE VERO E PROPRIO È UN CASO NON GESTITO.

Per rendere il programma più intelligente

  • Si aggiunge il riconoscimento anche delle lettere maiuscole con operatori AND o OR.
  • Seconda possibilità: usare la funzione toupper che converte in maiuscolo una lettera (necessaria la libreria <ctype.h>).
  • Sintassi -> risposta2=toupper(risposta2); //tolower – funzione per conversione in minuscolo

Altro controllo sui numeri inseriti

In quanto così si possono inserire numeri negativi e grandi: si possono usare condizioni if

if(costoProdotto <=0 || costoProdotto>100) {
    printf("Errore!");
}

Funzioni

Funzioni -> unità di programmazioni più piccole facilmente riutilizzabili. Nel main vengono richiamate le funzioni dichiarate precedentemente al main. Quando il compilatore arriva all’esecuzione del cout<<PerimetroRettangolo(3,5) o printf in C -> effettua un salto e va ad eseguire il codice della funzione richiamata.

Sottoprogrammi

Possibilità di creare un file esterno tipo “mieFunzioni.h” che fa riferimento al mio “mieFunzioni.cpp”; posso riutilizzare i pezzi di codici; e se c’è un errore posso andare a risolvere direttamente l’errore all’interno di questo file.

Float PerimetroRettangolo (float base, float altezza){} Float -> perché il perimetro potrebbe essere un numero a virgola mobile. Tra parentesi vengono indicati i valori che devono essere indicati alla funzione e tramite questi svolge determinate funzioni (dichiarate all’interno della stessa) per restituire il risultato voluto.

Vantaggi

  • Riduzione complessità (non un unico programma, più pulizia del codice, se c’è un problema si risolve prima).
  • Riutilizzo del codice (NB – punto più importante), si fanno meno errori e si corregge l’errore UNA volta sola, codice più leggibile.
  • Esempio -> separare con una cornicetta (“-----“) i risultati che vengono visualizzati sullo schermo. Usando le funzioni.
void cornicetta() {
    /*void -> no valori di ritorno, perché stampa solo dei valori ma non da un valore come risultato*/
    for(int i =1; i<=60; i++) {
        printf("c");
        printf("\n");
    }
}

void main(...) {
    cornicetta();
    cornicetta();
    ...

Come mostrato nella slide a destra -> si può chiedere anche direttamente all’utente che tipo di carattere usare. PARAMETRI FORMALI -> non sono i parametri veri che l’utente specificherà. Avverrà una copia della funzione, da dove verrà richiamata, e si avrà una sostituzione di questi parametri formali.

Quando la funzione viene richiamata

  • Il numero, il tipo dei parametri e l’ordine dev’essere rispettato.
  • Ora riprendiamo lo scorso programma e inseriamo le funzioni: porre attenzione a come vengono utilizzate le variabili se globalmente o localmente.

L’uso di una variabili globale ne limita il riutilizzo -> quindi il non poter utilizzare quella riga di codice in un altro programma. (RENDERE MODULARE IL CODICE – OGNI FUNZIONE INDIPENDENTE DALLE ALTRE) Stare attento a non legarsi a variabili esterne, una funzione “furba” permette di usare tale in tanti programmi diversi. Con le funzioni è facili anche i parametri in questione utilizzati.

Passaggio di valori nelle funzioni

  • Si può passare un valore alla funzione in determinate maniere:
  • by value (per valore) -> quello che accade è una copia del valore che contiene il parametro di utilizzo (parametro attuale) e viene ricopiato nel parametro della funzione.
  • In C++ si possono impostare dei parametri di funzioni di default di bool = false, così che se tale parametro non venisse poi richiamato quando la stessa funzione venisse richiamata il programma stesso verrebbe compilato in ogni caso. Quando si imposta un parametro per default però anche tutti quelli che seguono dovranno avere un tale parametro (attenzione durante il richiamo a che valore si inserisce).
#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>

float leggiReale (float limiteInferiore, float limiteSuperiore) {
    float numero; //variabile local
    do {
        printf("\nQuanto si paga per il prossimo prodotto? ");
        scanf("%f", &numero);
        if(numero <=limiteInferiore || numero>limiteSuperiore) {
            printf("Errore! Il valore inserito deve essere compreso tra %0.1f e %0.1f", limiteInferiore, limiteSuperiore);
        }
    } while (numero <=limiteInferiore || numero>limiteSuperiore);
    return numero; //da restituire un numero dalla funzione leggiReale (chiamata poi nel main e salvata in costoProdotto)
}

int main() {
    float totaleScontrino = 0, costoProdotto = 0;
    char risposta;
    do {
        char risposta2;
        totaleScontrino = 0;
        do {
            costoProdotto = leggiReale(0,100);
            totaleScontrino += costoProdotto;
            printf("\nCi sono altri prodotti? (s/n) ");
            scanf(" %c", &risposta2);
        } while (risposta2 != 'n');
        printf("\nQuesto cliente paga: %0.2f!\n", totaleScontrino);
        printf("\nCi sono altri clienti? (s/n) ");
        scanf(" %c", &risposta);
    } while (risposta !='n');
    return 0;
}

Creazione funzione per scambiare valore di due variabili

Essendo una funzione che deve effettuare solo scambio si utilizza il tipo void.

#include <stdio.h>
#include <stdlib.h>
#include <crtdbg.h>

void scambia(int *x, int *y) {
    int aiuto = *x; //si memorizza una variabile intera (dereferenziata) in una varibile intera
    /*QUANDO CON UN PUNTATORE SI VUOLE LAVORARE CON L’INTERO PUNTATO SI DEVE DEREFERENZIARE IL PUNTATORE (PASSARE DALL’INDIRIZZO ALL’OGGETTO VERO E PRORPIO – SI FA USANDO UN *)*/
    *x = *y; //memorizza nella varibile intera nell'allocazione puntata da x memorizza il valore che è contenuto nella posizione puntata da y
    *y = aiuto; //nella varibile intera y memorizza il valore interno della variabile (già intera) 'aiuto'
}

int main() {
    int a = 100;
    int b = 500;
    /*scambia(a,b); in questa maniera viene passato il valore BY VALUE, non è la variabile ‘a’ che viene passata alla funzione scambia. Quindi la funzione non può lavorare direttamente sulla variabile a, ma viene PASSATO IL VALORE che viene copiato nel corrispondente parametro della funzione. Cioè in partenza X ha il valore della variabile ‘a’ ma SOLO IL VALORE NON LA VERA VARIABILE, QUALSIASI MODIFICA FATTA ALLA X NON SI RIPERCUOTE SULLA VARIABILE ESTERNA LA STESSA COSA PER ‘b’ E Y.*/
    /*per effettuare lo scambio si usano i PUNTATORI – QUINDI x non è una variabile intera ma un puntatore ad una variabile intera -> quindi l’indirizzo di ‘a’ viene copiato in x e lo stesso per ‘b'. La funzione tramite l'indirizzo che è univoco in tutte la RAM delle variabili esterne usando x nella maniera corretta lavora sulla variabile esterna*/
    /*QUANDO CON UN PUNTATORE SI VUOLE LAVORARE CON L'INTERO PUNTATO SI DEVE DEREFERENZIARE IL PUNTATORE (PASSARE DALL'INDIRIZZO ALL'OGGETTO VERO E PRORPIO)*/
    scambia(&a, &b); /*siccome i due parametri formali della funzione due puntatori a interi, quindi quando la funzione viene richiamata serve CHIAMARE UNA VARIABILE PUNTATORE AD INTERO (quindi l'indirizzo di una variabile intera) - BY REFERENCE*/
    printf("%d ---- %d", a, b);
}

NELLE FUNZIONI I PARAMETRI SI POSSONO SPECIFICARE COME TIPO &(REFERENCE) INVECE CHE *(PUNTATORE).

void scambia(int &x, int &y) {
    int aiuto = x;
    x = y;
    y = aiuto;
}

&-> si usa come puntatore “mascherato” per evitare tutti questi *. Così i due parametri formali non sono interi, ma indirizzi di interi. Si può lavorare come se fossero variabili normali. Anche nel richiamo della funzione non serve più *.

Prototipi

Siccome c’è la possibilità di richiamare le varie funzioni di tra di loro (in base allo stile di programmazione) ci potrebbe essere il problema di dover spostare il blocco della funzione in modo da tale da farla “vedere” dalla funzione richiamante. Per evitare ciò si usano i prototipi -> cioè delle dichiarazioni anticipate delle funzioni che seguiranno, così che possano essere “viste” globalmente. Si tratta di riproporre l’intestazione della funzione quindi senza riporre poi il blocco con la parentesi graffa – se si usano parametri di default tipo int i = 0, serve specificarli nei prototipi ma non serve rispecificarli quando si richiama la funzione vera e propria (altrimenti si ricade in messaggi d’errore del compilatore).

Array

I vettori sono dei contenitori di elementi, i nomi che si possono dare ai vettori sono lì stessi che si possono dare alle variabili semplici. Unica cosa che cambia dalle variabili semplici è la dichiarazione di [] dove si potrà specificare la posizione dell’elemento del vettore con il quale si vuole lavorare e si conta partendo da zero. Fondamentale specificare anche il tipo degli elementi che contiene (DEVE ESSERE OMOGENO). In questo caso argv è un vettore di interni, ma non si sa ancora la dimensione.

int argv []

Vettori se tipo monodimensionali e matrici se di tipo bidimensionali.

float costi [100]; -> ciascuna casella è individuata da un numero tra parentesi quadre. La prima posizione è la [0] quindi l’ultima posizione sarà sempre [n-1] quindi 99 in questo caso. In ogni posizione può essere posizionato un numero diverso (stesso tipo). C’è la possibilità sin da subito di specificare un valore per gli elementi dell’array appena dichiarato, se no tutte le caselle valgono [0].

Inizializzazione di array

INIZIALIZZO DEI VALORI PREDEFINITI PER LE PRIME CELLE (SINTASSI) ->

float costi [100] = {5,8, 4.6}; //viene seguito l’ordine crescente.

Se si inizializza GLOBLAMENTE un array float costi [2]; e poi nel main si cerca di assegnare un valore in posizione tre -> costi [3] = 200; il programma verrà compilato ed eseguito normalmente, ma viene lasciata “una mina vagante” perché così è come se io avessi sovrascritto da qualche parte una parte della RAM con una configurazione di bit che corrisponde a 200. Problema se la parte tale parte della RAM fosse utilizzato da un processo critico per windows o da un altro programma. IL PROGRAMMATORE DEVE STARE ATTENTO A NON SFORARE SUI LIMITI DEL VETTORE.

Mentre le variabili esterne, vettori compresi, sono inizializzati in automatico a 0 la stessa cosa non può essere detta per le variabili locali. Quelle locali sono allocate sullo stack (area di memoria dinamica e separata), nel senso che viene concessa quando la funzione parte, quando la funzione termina viene recuperata come spazio di memoria per concederla.

Anteprima
Vedrai una selezione di 10 pagine su 42
Programmazione in Linguaggio C e C++ Pag. 1 Programmazione in Linguaggio C e C++ Pag. 2
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 6
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 11
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 16
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 21
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 26
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 31
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 36
Anteprima di 10 pagg. su 42.
Scarica il documento per vederlo tutto.
Programmazione in Linguaggio C e C++ Pag. 41
1 su 42
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 lucaspo03 di informazioni apprese con la frequenza delle lezioni di Informatica 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 Ferrara o del prof Alberti Marco.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community