Scarica Guida ai Fondamenti del C++: Tipi di Dati, Classi e Operatori e più Dispense in PDF di Programmazione Avanzata solo su Docsity!
PRIMI PASSI IN LINUX: INTERAZIONE CON LA SHELL E
L'AMBIENTE DI COMANDO
La Shell e l'Ambiente Linux La shell è un interprete di comandi interattivo, una Command Line Interface (CLI) per il sistema operativo. In pratica, è l'interfaccia testuale che permette di comunicare con il sistema tramite comandi scritti. Pensala come il "motore" dietro le quinte, che traduce le tue istruzioni in azioni eseguite dal computer. Esempi di shell sono:
- MS-DOS : command.com
- Windows NT/2000 : cmd.exe
- Dal 2006 : MS PowerShell Nei sistemi UNIX , la shell ha un'importanza fondamentale. Alcune delle shell più comuni sono:
- Bourne shell (sh)
- C shell (csh)
- Bourne-again shell ( bash , la più utilizzata oggi)
- ksh , tcsh Installazione del Sottosistema WSL (Windows Subsystem for Linux) Il sottosistema Windows per Linux (WSL) consente agli sviluppatori di installare una distribuzione Linux (ad esempio Ubuntu , OpenSUSE , Kali , Debian , Arch Linux ) per usare applicazioni e utility Linux, e strumenti da riga di comando Bash direttamente su Windows, senza il sovraccarico di una macchina virtuale tradizionale. Per installare WSL :
- Aprire PowerShell o il prompt dei comandi di Windows in modalità amministratore facendo clic con il pulsante destro del mouse e selezionando "Esegui come amministratore".
- Immettere il comando: wsl --install
- Riavviare il computer. Il File System di Linux
Il file system è il modo in cui i file sono organizzati e memorizzati su un disco o altro dispositivo di archiviazione. La shell offre un metodo di interazione con le risorse del sistema, in primis: i file. Sul disco, i file sono raggruppati in contenitori detti directory. Le directory possono contenere a loro volta directory formando una specie di albero. La directory più in alto costituisce la radice ( root ). Il file system può essere visto come:
- I dispositivi di memoria secondaria (HD, SSD, ...) utilizzati per contenere file e directory
- Le regole e gli strumenti per organizzare i dati sul disco
- La gerarchia di file e directory ( file system tree ) visibili al sistema e ai suoi processi In un sistema operativo i file dell'utente occupano solo una parte dell'albero. Il resto è dedicato:
- Alle componenti del sistema stesso (i file contenenti, kernel, device drivers, utility, librerie, comandi...)
- Ai dati che occorrono al sistema per funzionare (file di configurazione, risorse varie, file diagnostici...)
- Alle applicazioni installate (word processor, web browser...) L'organizzazione di tutto questo materiale ( file system hierarchy ) nel sistema Linux è uno standard. Tale organizzazione si è tramandata con poche variazioni sin dalle origini del sistema UNIX. Ecco alcune directory chiave nel file system:
- /: La directory radice, il punto di partenza per tutto.
- /bin: Contiene comandi essenziali per tutti gli utenti.
- /boot: File necessari per l'avvio del sistema.
- /dev: File che rappresentano i dispositivi hardware.
- /etc: File di configurazione del sistema.
- /home: Directory personali degli utenti.
- /lib: Librerie condivise utilizzate dai programmi.
- /media: Punto di montaggio per supporti esterni (USB, DVD).
- /mnt: Punto di montaggio temporaneo per file system.
utente@linuxbox:~$ ls - s ... .bash_history .bash_logout .bash_rc .profile .ssh
L'opzione - a chiede di visualizzare i file il cui nome inizia per .. Che sono
usualmente nascosti. In genere questi sono file di configurazione o temporanei ad uso delle applicazioni utente...
- Il comando ls - la mostra delle informazioni aggiuntive: utente@linuxbox:~$ ls - la total 32 drwxr-x--- 4 lc lc 4096 Mar 10 2023. drwxr-xr-x 3 root root 4096 Mar 10 2023 ..
- rw------- 1 lc lc 153 Aug 11 19:33 .bash_history
- rw-r--r-- 1 lc lc 3771 Jan 6 2022 .bashrc drwxr----- 2 lc lc 4096 Mar 10 2023 .cache
- rw-r--r-- 1 lc lc 807 Jan 6 2022 .profile drwxr----- 2 lc lc 4096 Mar 10 2023 .ssh
- rw-r--r-- 1 lc lc 0 Mar 10 2023 .sudo_as_admin_successful
o Si provi il comando ls con le seguenti «variazioni»
ls - aF ls - as ls - laF ls - lat ls - laat
- Creiamo una nuova directory «Prove» con il comando mkdir utente@linuxbox:~$ mkdir Prove utente@linuxbox:~$ ls Prove
o Si esplori la directory Prove con i seguenti comandi:
ls Prove ls - l ls - la Prove
- Per «spostarsi» nella directory Prove i.e. per farne la nostra nuova CWD, usiamo il comando cd. Inoltre, impartiamo i seguenti comandi. utente@linuxbox:~/ cd Prove utente@linuxbox:~/Prove$ mkdir spare utente@linuxbox:~/Prove$ ls spare
o Si provi con i seguenti comandi:
ls - laF spare ls - la spark
- Il comando pwd visualizza l'attuale CWD. utente@linuxbox:~/Prove$ pwd /home/utente/Prove utente@linuxbox:~/Prove$ cd spare utente@linuxbox:~/Prove/spare$ pwd /home/utente/Prove/spare utente@linuxbox:~/Prove/spare$ la - a . .. utente@linuxbox:~/Prove/spare$
- Tutte le directory, contengono due «sottodirectory» speciali:. e .. o. è un nome speciale che indica la directory corrente. o .. è un nome speciale che indica la directory «genitrice» di quella corrente. utente@linuxbox:~/Prove/spare$ cd .. utente@linuxbox:~/Prove$ pwd /home/utente/Prove
utente@linuxbox:~/ cd Prove utente@linuxbox:~/Prove$ cp /etc/passwd copia-passwd utente@linuxbox:~/Prove$ cp /etc/group. utente@linuxbox:~/Prove$ ls copia-passwd group spare utente@linuxbox:~/Prove$ cp cp group spare utente@linuxbox:~/Prove$ ls spare
- Il comando mv rinomina (o sposta) file e directory utente@linuxbox:~/Prove$ mv copia-passwd copia-pwd utente@linuxbox:~/Prove$ ls copia-pwd group spare utente@linuxbox:~/Prove$ mv copia-pwd spare/passwd utente@linuxbox:~/Prove$ ls group spare utente@linuxbox:~/Prove$ ls spare group passwd
- Il comando rm rimuove i file utente@linuxbox:~/Prove$ ls group spare utente@linuxbox:~/Prove$ rm group utente@linuxbox:~/Prove$ ls spare
- Il comando rmdir rimuove le directory (solo se sono vuote): utente@linuxbox:~/Prove$ mkdir foo utente@linuxbox:~/Prove$ ls foo spare
utente@linuxbox:~/Prove$ rmdir foo utente@linuxbox:~/Prove$ ls spare utente@linuxbox:~/Prove$ rmdir spare rmdir: failed to remove ‘spare’: Directory not empty
- Per svuotare velocemente una directory: utente@linuxbox:~/Prove$ rm spare/* utente@linuxbox:~/Prove$ ls spare rmdir spare utente@linuxbox:~/Prove$ ls Oppure: utente@linuxbox:~/Prove$ rm - fr spare utente@linuxbox:~/Prove$ ls Caratteri Speciali (Wild Cards) Alcuni caratteri speciali (o sequenze), indicati nel nome di file e directory, permettono di «abbreviare» i comandi necessari per effettuare operazioni ripetitive (come ad esempio la rimozione di molti file da una directory). Le stringhe composte con le wild cards, rappresentano le c.d. espressioni regolari Sim. Descrizione Espressione Corrispondenze
- 0 o più caratteri in sequenza
R, AZ,
*.txt 'Rosa', 'REATO', 'RR223', AZ, AxZ, ABCDZ, AAZ, file1.txt, file2.txt (ma non txt) ? Un carattere (qualsiasi) Cap.? Cap.1, Cap.2, Cap.3, Cap.A (e non Cap.23, Cap.xxs) Hello, World! ...naturalmente...
- Creiamo il nostro primo programma in C++ utente@linuxbox:/etc$ cd utente@linuxbox:~$ mkdir Prog
a.out hello.cpp utente@linuxbox:~/Prog2$ ./a.out Hello, World! REDIREZIONE DELL'I/O E PIPE Redirezione dell'I/O sui file Impartiamo il seguente comando: utente@linuxbox:~$ ls - l /etc L'output è l'elenco dei file contenuti in quella directory, ed è piuttosto lungo. Possiamo salvare l'output del comando in un file per esaminarlo con calma. utente@linuxbox:~$ ls - l /etc > ls-etc.txt utente@linuxbox:~$ ls ls-etc.txt utente@linuxbox:~$ more ls-etc.txt
- Il comando more visualizza il file indicato sullo schermo a pagine. Una versione più recente è il comando less (sic). Il carattere speciale > prescrive la redirezione dell'output verso il file indicato a seguire.
- Se il file non esiste, viene creato
- Se il file esiste, il suo contenuto precedente è sostituito dal nuovo utente@linuxbox:~$ ls - l. > ls-etc.txt utente@linuxbox:~$ more ls-etc.txt Il file adesso conterrà il contenuto della vostra home directory utente@linuxbox:~$ rm ls-etc.txt utente@linuxbox:~$
- Il comando rm è utilizzato per rimuovere un file di cui si specifica il pathname. La rimozione è IRREVERSIBILE La sequenza >> prescrive la redirezione dell'output in coda (append) al file indicato a seguire. utente@linuxbox:~$ cat /etc/hostname > informazioni utente@linuxbox:~$ cat /etc/issue >> informazioni
- Se il file non esiste, viene creato
- Se il file esiste, il contenuto più recente è aggiunto in coda a quello precedente Il comando cat visualizza sullo schermo il contenuto del (dei) file indicati sulla linea di comando. Se i file sono più d'uno, i contenuti sono visualizzati in sequenza. A differenza di more, cat non è un pager Creiamo un nuovo file di testo che contiene, per esempio, un elenco di nomi. utente@linuxbox:~$ nano elenco.txt Linux fornisce un ricco insieme di filtri, programmi che effettuano una elaborazione dell'input e ne producono il risultato in output. Ad esempio: sort utente@linuxbox:~$ sort < elenco.txt Abate Abatte Basile Caputo Esposito Altri filtri storicamente presenti nei sistemi UNIX sono: shuf, uniq, tr Il carattere speciale < prescrive la redirezione dell'input dal file indicato a seguire. È' possibile combinare redirezioni nei due sensi. utente@linuxbox:~$ sort < elenco > elenco-ordinato
Esempio Pratico: Creazione e Manipolazione di File Supponiamo di voler creare un file contenente l'elenco dei file in una directory, ordinarlo alfabeticamente e salvare il risultato in un altro file: ls - l /home/utente > lista_file.txt # Salva l'elenco dei file in lista_file.txt sort < lista_file.txt > lista_ordinata.txt # Ordina il contenuto di lista_file.txt e lo salva in lista_ordinata.txt Esempio Pratico: Uso delle Pipeline Vogliamo contare il numero di utenti nel sistema: cat /etc/passwd | wc - l # Il comando wc - l conta il numero di righe
INTRODUZIONE A C++ E TIPI DI DATI
Il C++ è un linguaggio di programmazione orientato agli oggetti di alto livello , derivato dal linguaggio C. È noto per la sua flessibilità , efficienza e potenza , che lo rendono adatto a una vasta gamma di applicazioni, dallo sviluppo di sistemi operativi e videogiochi , alla creazione di software embedded e applicazioni scientifiche. C++ è un'estensione del linguaggio C, mantenendo la gestione degli stream di input/output attraverso librerie, ma con un approccio più orientato agli oggetti. Uno dei primi programmi che ogni programmatore impara quando si avvicina a un nuovo linguaggio è il classico " Hello, World! ". Questo semplice programma ha l'unico scopo di visualizzare una riga di testo (in genere "Hello, World!") sullo schermo, fungendo da test iniziale per la configurazione dell' ambiente di sviluppo e la comprensione delle basi del linguaggio. Ecco il codice del programma "Hello, World!" in C++: // Programma che visualizza una riga di testo. #include // Include l'header iostream int main() { // Funzione principale del programma std::cout << "Salve, mondo!" << std::endl; // Stampa "Salve, mondo!" return 0; // Indica che il programma è terminato con successo } ANALISI DEL CODICE "HELLO, WORLD!" Analizziamo il codice riga per riga:
- // Programma che visualizza una riga di testo. Questo è un commento su singola linea. I commenti sono annotazioni nel codice che vengono ignorate dal compilatore e servono per spiegare il funzionamento del programma.
- #include . Questa direttiva dice al preprocessore di includere l' header file iostream. L' header file iostream contiene le dichiarazioni delle funzioni e degli oggetti necessari per gestire l' input e l'output in C++. In particolare, definisce l'oggetto std::cout, che useremo per stampare il testo sullo schermo. Questa direttiva è fondamentale perché la gestione degli stream in C++ avviene tramite funzioni di libreria , e iostream è quella specifica per input/output.
- int main() { ... }. Questa è la definizione della funzione main(), che è il punto di ingresso principale del programma C++. Quando si esegue un programma C++, il sistema operativo inizia eseguendo le istruzioni contenute all'interno
- che si estende su più righe.
- Può essere utilizzato per spiegare
- sezioni di codice complesse. */ int punteggio = 100; GESTIONE DELL'INPUT/OUTPUT IN C++ CON IOSTREAM: CIN E COUT L' header iostream ( input/output stream ) è una parte fondamentale della libreria standard del C++, che fornisce gli strumenti per gestire l' input e l'output di dati. Questo header definisce classi e oggetti che consentono di interagire con la console (tastiera e schermo) e con i file. Il C++ utilizza lo stesso preprocessore del compilatore C, ma introduce diverse innovazioni. L' header iostream definisce gli stream di input/output per la console (tastiera e schermo). In C++, il flusso dei dati tra le periferiche (o i file) e la memoria del calcolatore (ad esempio, le variabili) è gestito tramite delle entità denominate stream. I dati possono fluire in due direzioni:
- I dati che transitano attraverso lo stream dalla memoria al dispositivo/file di destinazione sono dati in output.
- Viceversa, quelli che fluiscono nella direzione inversa sono dati in input. Uno stream può consentire il transito dei dati in una sola delle due direzioni o in entrambe. Nel linguaggio C standard la gestione dell' input e dell'output è fatta tramite funzioni esterne (printf, scanf) risiedenti nella libreria stdlib, mentre nel C++ (con la libreria iostream) si usano cout e cin. A differenza di printf e scanf, cout e cin non richiedono un input formattato. COUT E CIN: GLI OGGETTI STREAM PER INPUT E OUTPUT All'interno dell' header iostream, sono definiti due oggetti stream principali :
- cout ( console output ): Rappresenta lo stream di output standard , collegato alla console (schermo). Permette di visualizzare dati e messaggi sullo schermo. L' operatore di flusso per cout è <<.
- cin ( console input ): Rappresenta lo stream di input standard , collegato alla tastiera. Permette di leggere dati inseriti dall'utente. L' operatore di flusso per cin è >>. ESEMPIO DI OUTPUT: VISUALIZZARE COSTANTI, VARIABILI E MANIPOLATORI Per visualizzare il valore di una costante sullo schermo, si utilizza cout seguito dall' operatore << e dalla costante stessa. Ad esempio:
#include int main() { std::cout << 2010; // Visualizza 2010 std::cout << "Ciao"; // Visualizza Ciao std::cout << "Ciao" << "!"; // Visualizza Ciao! return 0; } Per visualizzare il contenuto di una variabile sullo schermo: #include int main() { int anni = 18; std::cout << anni; // Visualizza 18 return 0; } È possibile concatenare più valori da visualizzare con cout, utilizzando l' operatore << ripetutamente: #include int main() { int anni = 18; std::cout << "Età: " << anni << " anni."; // Visualizza "Età: 18 anni." return 0; } Il manipolatore endl ( end line ) inserisce un carattere di nuova linea nello stream di output , spostando il cursore alla riga successiva dello schermo. Ad esempio: #include int main() { std::cout << "Ciao" << std::endl; // Visualizza "Ciao" e va a capo std::cout << ":-" << std::endl; // Visualizza ":-" e va a capo return 0; } ESEMPIO DI INPUT: RICEVERE DATI DALLA TASTIERA Per ricevere un valore immesso da tastiera e riportarlo in una variabile , si utilizza cin seguito dall' operatore >> e dal nome della variabile. Ad esempio:
using std::endl; int main() { int num; cout << "Inserisci un numero: "; cin >> num; cout << "Hai inserito: " << num << endl; return 0; } Usare using namespace std; permette di evitare di dover specificare std:: davanti a cout, cin e altri elementi dello spazio dei nomi std. OUTPUT FORMATTATO: MANIPOLAZIONE DEI DECIMALI Il C++ offre diverse opzioni per formattare l'output , inclusa la gestione della precisione dei numeri decimali. Per default, il C++ visualizza i numeri reali con una precisione di 6 cifre decimali (se ci sono). Per modificare la precisione dei numeri decimali visualizzati, è possibile utilizzare i manipolatori di stream fixed e setprecision.
- fixed: Forza la visualizzazione dei numeri reali in notazione decimale fissa (senza notazione scientifica).
- setprecision(n): Imposta la precisione a n cifre decimali. Per utilizzare il manipolatore setprecision, è necessario includere l' header file iomanip: #include #include int main() { double valore = 3.1415926535; std::cout << "Valore originale: " << valore << std::endl; // Precisione di default std::cout << std::fixed << std::setprecision(2) << "Valore con 2 decimali: " << valore << std::endl; return 0; } L'inclusione di iomanip è necessaria per usare manipolatori come setprecision. MANIPOLATORI DI STREAM "STICKY" E RESET I manipolatori di tipo "sticky" producono il loro effetto indefinitamente, fino a che non vengono nuovamente impostati o annullati. Per esempio: fixed e setprecision.
Gli altri (per esempio endl) funzionano solo una volta. Vanno quindi inviati ogni volta che ce n'è bisogno. Una volta manipolato lo stream cout nel modo seguente: cout << fixed << setprecision(4); Per riportare tutto alle condizioni di default occorre inviare: cout << setprecision(6) << std::defaultfloat; I/O FORMATTATO: CAMPI E ALLINEAMENTI Per visualizzare i dati in output in una vera tabella, è necessario che:
- Ciascun dato sia visualizzato in uno spazio (campo) di dimensione prefissata ;
- Sia possibile decidere l' allineamento dei dati all'interno del campo Per questo scopo, si utilizzano i manipolatori :
- setw(n) riserva uno spazio (campo) di n caratteri per la visualizzazione del dato che segue
- left e right determinano il lato da cui «si comincia a scrivere» nel campo. Lo spazio non utilizzato è occupato da un carattere «di riempimento» (lo spazio, per default) Se X è più corta di 5 caratteri, il compilatore visualizza il contenuto della variabile allineandolo al limite destro del campo e riempiendo con uno spazio la parte di campo non utilizzata a sinistra. Se X è più lunga di 5 caratteri, nulla accade, il compilatore impiegherà il numero di caratteri necessario a visualizzare la X. TIPI DI DATI IN C++ In C++, la dichiarazione dei tipi di dati è un aspetto fondamentale della programmazione. Lo scopo della parte dichiarativa di un programma (prevista nel main e in altre parti del codice) è di elencare tutte le variabili e le costanti che saranno utilizzate nella parte esecutiva e di attribuire a ciascuna di esse un tipo , ossia di specificare le caratteristiche che ne regolano l'uso. Per tipo di una variabile/costante si intende l'insieme dei valori che la variabile/costante stessa può assumere. Le parole chiave int, float, char, bool specificano rispettivamente i tipi intero , reale , carattere , e booleano. In C, tutte le variabili di un programma hanno un tipo che viene loro associato, una volta per tutte, dalla dichiarazione. Ciò comporta che: