Estratto del documento

Appunti linguaggio C architetture e sistemi operativi

Lezione 4 - 10/03/2016

Prima lezione sul linguaggio C. Libro di riferimento: Kernighan, Ritchie “The C Programming Language”. Ambiente di sviluppo: Eclipse for C/C++. Gli autori del libro nel 1972 hanno inventato il linguaggio prevalentemente per ambiente UNIX. La portabilità è una caratteristica che permette di usare un applicativo in diversi contesti (un applicativo che può “girare” ovunque, cioè su calcolatori e sistemi operativi- un esempio è JAVA). Il C ha dei problemi sulla portabilità. Il C, se ben utilizzato, può raggiungere livello di efficienza nell'esecuzione dei programmi pari al linguaggio assembly: è un linguaggio che mi permette di avere le stesse prestazioni del linguaggio assembly.

La possibilità di fare delle chiamate di sistema e di gestire dei puntatori mi permette di “mettere le mani” all’interno del sistema. Per scrivere il programma ho bisogno di un edit program, alla fine di questa fase ottengo il codice sorgente (il listato del programma), poi bisogna compilare l’applicativo e al termine della fase di compilazione abbiamo il codice oggetto: qui abbiamo la differenza tra linguaggio interpretativo (garantisce la portabilità es. MATLAB) e linguaggio oggetto (questo linguaggio oggetto deve essere linkato alle librerie, cioè funzioni già prescritte, che devono fare da supporto a questo linguaggio). Alla fine con il linguaggio oggetto, dopo la compilazione, otterremo un file eseguibile (.exe) mentre con il linguaggio interpretativo no.

Il problema sta nel fatto che quando abbiamo il file eseguibile, questo non è detto che funzioni dappertutto, in tutti gli ambienti (perché cambiare calcolatore significa cambiare processore), e questo rappresenta il problema della portabilità. Per sopperire a questo problema si usa l’ANSI C (C standard): un linguaggio standard dovrebbe infatti funzionare su qualsiasi supporto.

Source CodeObject Code → .exe

Il programma più noto è:

#include <stdio.h>
int main() {
    printf("Hello, World!\n");
    return 0;
}

La funzione main è una funzione che restituisce, in questo caso, un intero, cioè lo status del programma, ci dice se le cose sono andate bene o no, il return 0 indica il successo. È la prima funzione che viene eseguita quando lancio un programma eseguibile.

La direttiva “include” invita il compilatore, mediante il processore, ad importare i file definiti nell’include, in questo esempio il file incluso è stdio.h (direttiva per l’input/output). Le variabili vanno sempre dichiarate prima di essere utilizzate specificando il tipo e il nome.

Dichiarazione di variabili

Le variabili che vengono dichiarate fuori da ogni blocco (funzioni) sono variabili globali: hanno una visibilità che parte dal momento che vengono dichiarate fino alla fine del file. Le variabili locali sono quelle definite all’interno di un blocco: sono visibili solo all’interno del blocco stesso. Se una locale ha lo stesso nome della globale, all’interno di un blocco “comanda” la locale.

#include <stdio.h>
#include <stdlib.h>
int a=1; /* variabile globale */
void test() {
    printf("%d\n",a);
}
int main() {
    int a=2;
    {
        int a=3;
        printf("%d\n",a);
    }
    printf("%d\n",a);
    test();
    system("pause");
}

Tenendo conto della priorità tra variabili globali e locali, questo programma mi manda a video la seguente sequenza: 3, 2, 1.

Indicatore extern

Permette di dichiarare una variabile globale in qualsiasi parte di un programma, anche in un file separato. Dico al compilato che all’esterno del programma c’è una variabile che dovrò considerare. Nella dichiarazione “extern” esiste una variabile da considerare esterna al programma.

int a=4; /* variabile globale */
extern int b;
int test();
int main() {
    printf("a=%d\nb=%d",a,b);
    a=b=5;
    test();
    system("pause");
}
extern int a;
int b=3;
int test() {
    printf("\na=%d\nb=%d\n",a,b);
}

Quello che esce a video è: 4,3,5,5.

Vediamo un altro esempio, senza la keyword extern:

#include <stdio.h>
#include <stdlib.h>
/* test_main.c */
int a=4; /* variabile globale */
int b=2;
int test();
int main() {
    printf("a=%d\nb=%d",a,b);
    a=b=5;
    test();
    system("pause");
}
/* test.c */
int a=3;
int b=3;
int test() {
    printf("\na=%d\nb=%d\n",a,b);
}

In questo caso ho un errore dovuto alla ridefinizione della variabile a. Per evitare il problema posso fare così:

int test() {
    int a=3;
    int b=3;
    printf("\na=%d\nb=%d\n",a,b);
}

Le variabili a e b che prima erano globali ora sono locali. Le variabili automatiche esistono solo nel blocco in cui vengono definite, quando il processo esce dal blocco in cui la variabile è definita allora la variabile viene distrutta.

Esempio (da NON utilizzare MAI!):

#include <stdio.h>
#include <stdlib.h>
void func1() {
    int x;
    printf("1->%d\n",x);
    x=10; /* inizializzazione che in realtà non serve a nulla */
}
void func2() {
    int y=rand();
    printf("2-> %d\n",y);
}
int main() {
    int i;
    for (i=0; i<5; i++) {
        func1();
        func2();
    }
    system("pause");
}

Variabile statica: è una variabile che non viene distrutta dopo l’utilizzo. È una variabile che pur avendo una dichiarazione di tipo locale, al termine del blocco, non viene distrutta.

int count() {
    static int x=0;
    return (++x);
}
int main() {
    printf("%d", count());
    printf("%d", count());
    printf("%d", count());
}

In questo modo uscirà a schermo: 1,2,3. Se non avessi messo static int ma solo int avrei ottenuto 1,1,1.

La keyword register suggerisce al compilatore che una variabile verrà usata pesantemente e che sarebbe meglio mantenerla direttamente in un registro per aumentare l’efficienza. Stiamo invitando la macchina a tenere il contenuto di quella variabile all’interno di un registro del compilatore (magari perché ci serve spesso), ovviamente non posso riempire tutti i registri (che sono limitati) con le nostre variabili. I vincoli dunque sono:

  • Lo spazio (non posso riempire tutti i registri);
  • Solo certi tipi di dati possono essere memorizzati nei registri.

Concetto di tipo in C

In C esistono pochi tipi base:

  • char: un singolo byte in grado di contenere un singolo carattere
  • int: un intero di lunghezza fissata (32/64 bit a seconda della macchina)
  • float e double: floating point a singola e doppia precisione

Si può avere:

  • short int
  • long int
  • long double
  • unsigned int: un intero senza segno
  • unsigned char: un valore da 0 a 255 (poiché l’ANSI è a 8 bit)

Ogni tipo ha una dimensione fissa associato ad esso: questa dimensione può essere determinata a tempo di compilazione e varia a seconda dell’architettura del computer. In C possiamo usare un comando, che si chiama sizeof(), che automaticamente mi restituisce la lunghezza dei tipi che sto considerando. Nella parentesi vanno inseriti i vari tipi, ad esempio char, int, short, long, etc. Per creare un nuovo tipo possiamo usare il comando typedef: crea un nuovo tipo in modo da poter adattare l’esigenza a quella che abbiamo scritto, lo si usa per creare tipi “portabili” e per semplificare sintassi complesse.

Casting

Ha come obiettivo quello di forzare un tipo in un altro.

Esempio:

int approximation;
approximation= (int)(3.14*raggio*raggio);

La forzatura avviene aprendo la parentesi, mettendo il tipo a cui si vuole forzare e poi si chiude la parentesi: il casting è quindi (int), sto forzando un floating (poiché avrei un numero decimale) ad un intero.

È possibile anche dichiarare delle variabili come costanti, non varierà mai all’interno del programma che utilizziamo/scriviamo.

Esempio:

const double pi=3.1315926;
const int maxlenght=2356;

Esercizio 1

Si scriva un programma in linguaggio C che acquisisca un numero intero positivo N da tastiera e stampi il valore del fattoriale di N. Suggerimento. Si ricorda che il fattoriale di un numero è il prodotto di tutti i numeri compresi tra 1 ed N. N! = 1 · 2 · 3 · . . . · (N − 1) · N

Soluzione

#include <stdio.h>
#include <stdlib.h>
int main(void) {
    int N; /* numero inserito */
    int fattoriale; /* fattoriale del numero */
    /* LEGGI UN NUMERO */
    printf("Inserisci un numero intero positivo: ");
    scanf("%d", &N);
    /* VERIFICA CHE IL NUMERO INSERITO SIA POSITIVO */
    if (N < 0)
        printf("Errore: il numero inserito deve essere positivo\n");
    else {
        /* INIZIALIZZA IL VALORE DEL FATTORIALE */
        fattoriale = 1;
        /* IL FATTORIALE E’ CALCOLATO COME PRODOTTO TRA TUTTI I NUMERI COMPRESI TRA "N" E 1 */
        while (N > 1) {
            /* AGGIORNA IL VALORE DEL FATTORIALE */
            fattoriale = fattoriale * N;
            /* DECREMENTA IL VALORE DI "N" */
            N = N - 1;
        }
        /* STAMPA IL RISULTATO */
        printf("\n Il fattoriale e': %d\n", fattoriale);
    }
    system("pause");
}

Esercizio 2

Determinare la somma dei primi N numeri.

Soluzione

#include <stdio.h>
#include <stdlib.h>
int main() {
    int n, i = 1;
    int totale = 0;
    printf("Inserisci un numero:\n");
    scanf("%d", &n);
    /* SOMMA DEI PRIMI N NUMERI */
    for (i = 1; i <= n; i++) {
        totale = totale + i;
    }
    printf("Il risultato e':%d\n", totale);
    system("pause");
}

Soluzione 2 (con dichiarazione di funzione)

#include <stdio.h>
#include <stdlib.h>
int somma(int); /* NEL PROTOTIPO MI BASTA SEMPLICEMENTE DICHIARARE IL TIPO, POSSO EVITARE DI INSERIRE IL PARAMETRO */
int main() {
    int n;
    int totale;
    printf("Inserisci un numero:\n");
    scanf("%d", &n);
    /* SOMMA DEI PRIMI N NUMERI */
    totale = somma(n);
    printf("Il risultato e':%d\n", totale);
    system("pause");
}
int somma(int a) {
    int i = 1, tot = 0;
    for (i = 1; i <= a; i++) {
        tot = tot + i;
    }
    return tot;
}

Lezione 7 - 17/03/2016

Array, struct e union

Gli ARRAY

Gli array sono degli aggregati di variabili dello stesso tipo (tutti interi, tutti char e così via). Un esempio di dichiarazione dell’array: tipo nome_array [dimensione array]; Rispetto a MATLAB dove la dimensione andava da 1 a N, in C si va da 0 a N-1. Nel processore ci sono degli elementi di memoria: all’interno si trovano istruzioni e dati (da qui si ha il concetto di macchina programmabile), per questo il calcolatore non produce nessun errore se accedo ad una posizione superiore alla dimensione dell’array perché esso accede ad un indirizzo con un risultato imprevedibile. Oltre ad array monodimensionali, posso avere anche quelli multidimensionali (ovvero delle matrici).

Esempio: char frase[20][10] dove 20 indica le righe e 10 le colonne.

In generale: tipo nome_array[righe][colonne]

Gli array possono essere inizializzati:

int tabella[4]={10,23,34,45}; /* è uno statement e come tutti gli statement devo terminare con il ; */

In questo modo sto dicendo che: tabella[0]=10 , tabella [1]=23 e così via.. Per quelli multidimensionali si ha:

int a[2][3] = {{11, 12, 13}, {21, 22, 23}};

Oppure posso scrivere:

int a[2][3] = {11, 12, 13, 21, 22, 23};

che fornisce lo stesso risultato di prima (dovuto a come funziona il sistema operativo che gestisce il processore).

Tipo STRUCT

E’ una struttura per aggregare variabili di tipo diverso:

struct laboratorio {
    char orario[20];
    char aula;
    int studenti;
} lps;

La struttura che ho creato è di tipo laboratorio (che alla fine è una struttura) che ha all’interno un vettore di 20 elementi di tipo char, una variabile di tipo carattere e una variabile di tipo intero. La variabile che ho creato si chiama lps ed è di tipo laboratorio. Per accedere ai campi di una variabile si usa l’operatore ‘.’, cioè lps.aula: in questo modo sto dicendo che all’interno della variabile lps che è di tipo laboratorio mi vado a prendere la variabile aula. Per prendere la variabile studenti avrei scritto lps.studenti. Per creare nuovi tipi si usa typedef. In modo più ortodosso rispetto a struct posso scrivere:

typedef struct {
    char orario[20];
    char aula;
    int studenti;
} laboratorio;

Questa definisce il tipo laboratorio.

UNION

Ha molte somiglianze con il tipo struct con una differenza di fondo: i dati (le variabili contenute) sono memorizzate a partire dalla stessa locazione di memoria. Ad esempio:

union atomo {
    int posizione[3];
    long velocita;
} j;

Ho creato una variabile j di tipo atomo che contiene due variabili (che possono essere di tipi diversi) al suo interno. Decidiamo noi quale è il significato e quindi quale è il valore/dato del registro che andiamo a considerare, il motivo risiede nell’efficienza e quindi nella dimensione. Con la struct avrei un’occupazione di memoria superiore a quello che realmente può essere la mia dimensione che uso, con la union la dimensione è data dal massimo valore dei campi.

Con la UNION: Se il tipo long occupa 2 byte e il tipo int occupa 1 byte, la dimensione che sfrutto con la union è di 2 byte.

Con la STRUCT: Poiché ho posizione[0], posizione[1], posizione[2] su diverse locazioni di memoria...

Anteprima
Vedrai una selezione di 8 pagine su 31
Appunti di programmazione C Pag. 1 Appunti di programmazione C Pag. 2
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 6
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 11
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 16
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 21
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 26
Anteprima di 8 pagg. su 31.
Scarica il documento per vederlo tutto.
Appunti di programmazione C Pag. 31
1 su 31
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 massimiliano.avagliano1 di informazioni apprese con la frequenza delle lezioni di Fondamenti di infomratica 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 Salerno o del prof Colace Francesco.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community