G. BALDI

 

            Dipartimento di Matematica

 

            Università di Torino

 

 

 

 

 

 

 

 

 

 

 

 

          LE IDEE DELLA PROGRAMMAZIONE

 

 

 

 

 

 

          volume 2

 

 

Il linguaggio C

 

 

 

 

 

 

 

 

 

 

 

            Appunti - Anno accademico 1994-1995


 

 

                        I n d i c e

 

 

            Capitolo 1 - Ciclo di sviluppo di un programma

 

1.1

-

La scrittura del testo

1

1.2

-

Fase preliminare: l'analisi strutturale

2

1.3

-

Prima stesura del testo e modifiche successive

3

1.4

-

La compilazione - programma oggetto

4

1.5

-

Il link - programma eseguibile

5

1.6

-

Fase finale: l'esecuzione

7

1.7

-

Errori logici di tipo strutturale

8

1.8

-

Debug o ricerca degli errori

9

1.8

-

Cenni ad altri ambienti operativi

10

 

 

            Capitolo 2 - Struttura di un programma

 

2.1

-

I linguaggi di programmazione

12

2.2

-

La definizione dei dati

13

2.3

-

Le istruzioni, o comandi operativi

14

2.4

-

Il flusso di esecuzione delle operazioni

17

 

-

 - a - Le alternative

17

 

-

 - b - I cicli

18

 

 

            Capitolo 3 - Elementi fondamentali di un programma in C

 

3.1

-

Prototipo di programma in C

20

3.2

-

Le istruzioni del programma

21

3.3

-

Le assegnazioni

23

3.4

-

Le funzioni

24

3.5

-

Identificatori e parole chiave

25

3.6

-

Formazione dei nomi di identificatori

27

 

 

            Capitolo 4 - Tipi, costanti, espressioni, operatori

 

4.1

-

Tipi di dati in C

28

4.2

-

Costanti

30

4.3

-

Costanti simboliche e metaistruzione #define

32

4.4

-

Espressioni ed operatori

34

4.5

-

I puntatori - definizione ed operazioni

37

 

            Capitolo 5 - Impiego degli indici e degli array

 

5.1

-

La natura degli indici

41

5.2

-

Notazione degli indici in C

42

5.3

-

Dimensionamento degli array

43

5.4

-

Array e puntatori

45

5.5

-

Le stringhe

47

 


 

            Capitolo 6 - Il controllo delle alternative

 

6.1

-

Il flusso di esecuzione del programma

50

6.2

-

Istruzione if

50

6.3

-

Alternative multiple

52

6.4

-

Il selettore switch per casi costanti

54

 

 

            Capitolo 7 - Le strutture di ciclo

 

7.1

-

Organizzazione dei cicli

57

7.2

-

Cicli basati sul conteggio - struttura for

58

7.3

-

Esempio: scrittura di una tavola pitagorica

59

7.4

-

Cicli basati sulle condizioni logiche

61

7.5

-

Strutture while e do .. while

63

7.6

-

Interruzioni di ciclo - istruzioni break e continue

65

7.7

-

Esempio: ordinamento con Bubble Sort

66

 

 

            Capitolo 8 - Le funzioni - organizzazione

 

8.1

-

Analisi strutturale di un algoritmo

67

8.2

-

Esempio di analisi: lista di numeri primi

68

8.3

-

Definizione delle funzioni

69

8.4

-

Principali norme per le funzioni in C

71

8.5

-

Esempio di applicazione: lista di numeri primi

73

8.6

-

Contesti locali e globali

74

 

 

            Capitolo 9 - Le funzioni - aspetti operativi

 

9.1

-

Scopo dei parametri

77

9.2

-

Passaggio dei paramtri per valore

78

9.3

-

Passaggio dei parametri per riferimento

79

9.4

-

Memoria temporanea: lo stack

82

9.5

-

Le funzioni ricorsive

83

9.6

-

Esempio: calcolo del massimo comun divisore

85

9.7

-

Le funzioni come parametri

87


 

 

            Capitolo 10 - Le funzioni di Input / Output

 

10.1

-

Definizione del problema

88

10.2

-

Funzioni orientate al carattere

89

10.3

-

Funzioni per I/O formattato

90

 

-

 

 

 

 

 

 

            Capitolo 11 - X

 

 

 

 

 

 

 

 

 

 

-

 

 

 

 


 

 

I n t r o d u z i o n e

 

 

 

                Il linguaggio C é stato progettato tra gli anni ‘60 e ‘70 da B. W. Kernighan e D. M. Ritchie assieme al sistema operativo Unix, come strumento di programmazione per costruire i moduli del sistema ed allo stesso tempo come base per la sintassi dei comandi del sistema stesso.

 

                All’origine di Unix c’era il tentativo di superare le esasperanti differenze tra i sistemi operativi reperibili su macchine di diversi costruttori, differenze dovute a necessità dell’architettura hardware e software di ogni singolo tipo di macchina, ma spesso ‘forzate’ per differenziarsi il più possibile dai concorrenti e legare potenzialmente i clienti al proprio prodotto.

 

                Unix doveva superare questa situazione proponendosi come sistema operativo indipendente dal tipo di hardware, quindi adottabile su qualunque configurazione con un minimo di variazioni. Per questo era però necessario mettere a punto un linguaggio di programmazione di ‘alto livello’, come allora erano Fortran, Cobol, PL/1, aumentandone in senso strutturale le possibilità; ma era anche necessario rendere disponibili le operazioni sui singoli bit della memoria, cui normalmente si poteva avere accesso solo con i linguaggi di ‘basso livello’, gli Assembler.

 

                Ne è derivato un linguaggio formato da un numero molto basso di parole chiave, forse il più ‘scheletrico’ dei linguaggi di programmazione, ma di uno straordinario numero di operatori e di costruzioni per la definizione dei dati e naturalmente dotato per la strutturazione in funzioni, per il quale é particolarmente facile il compito di costruire un compilatore ‘minimo’, scritto necessariamente nell’Assembler della macchina cui esso é destinato.

 

                Tutto il resto, compresa la trattazione dello Input/Output, é delegato ad una apposita libreria di funzioni, detta libreria standard, composta però di programmi scritti in linguaggio C e quindi immediatamente ricompilabili non appena messo a punto il ‘compilatore base’.

 

                Questa impostazione ha avuto uno straordinario successo ed il C é divenuto rapidamente quello che nelle ambizioni doveva essere il PL/1, cioè un compilatore per i progettisti di sistemi operativi, utilizzabile altrettanto bene anche dagli utenti di tipo generale. Oggi non esiste quasi alternativa per lo sviluppo dei sistemi, e gli stessi compilatori degli altri linguaggi sono scritti utilizzando il C; la stessa cosa é vera per i grandi package di uso generale, sia per l’utenza scientifica, sia per quella commerciale.

 

                Il C, che é l’evoluzione di una precedente versione detta B (non si hanno tracce del presumibile A), mostra fin dal nome l’attitudine alla sintesi, che si ritrova in molte parti del linguaggio; esso ha attraversato fasi di sviluppo disordinate, in particolare nella definizione delle librerie, fino a quando l’organismo preposto alla definizione dei linguaggi di programmazione (Codasyl) ne ha fissati la formulazione nelle norme ANSI, cosa avvenuta nel 1988.

 

                Il testo fondamentale rimane ancora oggi il “Linguaggio C” di Kernighan e Ritchie, pubblicato in Italia dalla Jackson, al quale rinviamo il lettore per la trattazione formale del linguaggio contenuta in appendice, oltre che per la chiara esposizione di tutti gli argomenti trattati.

 

                Le intenzioni di queste dispense sono un po' diverse da quelle consuete nella trattazione di un linguaggio di programmazione, che é in genere condotta con approccio manualistico, oppure all’opposto con una grande serie di esempi presentati magari informalmente, da cui si dovrebbero gradualmente ‘coagulare’ gli elementi sintattici.

 

                Si é invece cercato di seguire una direttrice forse più adatta agli studenti del corso di laurea in Matematica che ad altri (o, si spera, almeno ad essi). E’ convinzione dell’autore, maturata nella effettiva utilizzazione e nell’insegnamento di diversi linguaggi per quasi un ventennio, che della programmazione debbano emergere le idee, in un quadro logico coerente, anche privo di eccessi di rigore.

 

- - - - -


 

                Le convenzioni che costituisconno la sintassi di un linguaggio di programmazione esistono per rendere possibile la comunicazione con la macchina ed una sua utilizzazione razionale; se esse definiscono un linguaggio di programmazione ‘di alto livello’, che per definizione deve essere indipendente da ogni particolare architettura progettativa, quindi utilizzabile senza variazioni su una qualunque di esse.

 

                Questa caratteristica viene detta portabilità; come é noto, essa appartiene però purtroppo più al mondo dei sogni che a quello reale, perché i linguaggi di programmazione sono entità soggette ad evoluzione, in buona misura dettata da quella parallela della tecnica di progettazione delle macchine.

 

                Ne deriva che le formulazioni ufficiali dei linguaggi sono perennemente in ritardo rispetto agli elementi opzionali che ogni costruttore ritiene utile (o conveniente) offrire per una versione di un linguaggio su una propria macchina. Ne deriva uno stato di cose piuttosto esasperante, anche se ideale per la generazione di tecniche ed idee nuove.

 

- - - - -

 

                Poichè i linguaggi non possono fare astrazione del tutto dalla struttura reale delle macchine, esistono dei punti di riferimento comuni, dati dalle struttuure hardware di base: memoria centrale, microprocessore, canali di Input/Output possono diversificarsi ed evolversi, ad esempio per le macchine ad architettura parallela, ma la logica di definizione dei dati e quella della loro elaborazione é ragionevolmente stabile.

 

                Esiste quindi un substrato comune in cui si debbono ricercare i ‘perché’ di certe convenzioni linguistiche piuttosto che altre ed é qui che si può parlare di ‘idee’;  cercare di portarli alla luce é appunto una delle ambizioni di questo lavoro, che non ha come obiettivo la facilità di lettura, ma la chiarezza dell’analisi logica e forse avrebbe dovuto essere sottotitolato “come ho appreso e come ho vissuto l’esperienza dei linguaggi di programmazione”.

 

                Tale analisi  non é solo approfondimento delle necessità logiche derivanti dalla struttura base delle macchine, ma si incrocia inevitabilmente con le tecniche di progettazione e controllo degli algoritmi; da essa ci si può attendere che l’apprendimento del linguaggio (di un linguaggio, non importa quale) non si riduca ad una semplice memorizzazione di strutture di dati ed operative, ma alla comprensione della loro natura, in modo che alla fine il ruolo della memorizzazione risulti del tutto secondario.

 

                Queste sono state le intenzioni; in quanto alla realizzazione si tratta, come si suol dire, di un altro paio di maniche; come nel passato é stato prezioso il contributo, qualche volta magari involontario, ma più spesso portato con genuina passione da molti studenti, la miglior e cartina di tornasole sarà la loro reazione futura, da cui deriveranno inevitabili ‘calibrazioni’ nelle tecniche e negli obiettivi, o forse addirittura rivoluzioni profonde

 

 

                                Torino, Aprile 1995

                                                                                                                             G. Baldi