Lezione 15

Capitolo Stringhe.

  • Stringhe costanti come puntatori. Le stringhe costanti sono di sola lettura, modificarle è un errore a runtime.
  • Stringhe non constanti, vettori di caratteri terminate da zero, inizializzazione, lettura con scanf, stampa con printf.
  • Funzioni di libreria: strlen, strcpy, strcat, strcmp. e tante altre: vedere libro.
  • Vettori di stringhe costanti, argomenti della linea di comando, parametri della main: argc, argv.
  • Introduzione al concetto di tipo di dato astratto. Applicazione: FILE.
  • Operazioni sui file, apertura ( fopen ), chiusura ( fclose ). Operazioni su file di testo: fprintf, fscanf, fgetc, fgets.

Esempio visti a Laboratorio:

Stringhe costanti, uso di vettori di stringhe costanti, parametri da linea di comando

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>

/* La funzione main, accetta due parametri:
   argc e' un intero, che specifica la lunghezza del vettore di stringhe argv.
   argv e' un vettore di stringhe costanti. nota: argv[0] e' sempre presente ed
   e' uguale al nome (e percorso) del file eseguibile associato al programma. */

int main(int argc, char *argv[])
{
    char *p = "Ciao ragazzi\n";

    // p e' una stringa costante, il compilatore alloca la memoria per noi, ma in sola lettura.

    printf("%s - quarto carattere: ",p); // posso leggere
    putchar(p[3]);   
    putchar('\n');

    // p[3] = 'x';   // non posso scrivere: se decommento questo, il programma si pianta a runtime.
    // morale -> non provate mai a modificare una stringa costante ad esempio gli elementi di argv.
    // stampiamo tutti gli argomenti:
    
    for (int i=0; i<argc; i++)
        printf("argomento %d: %s\n",i,argv[i]);

    return 0;
}

Varie funzioni di libreria, e file. Cosa fa questo programma?
Scrivete il codice, e salvatelo come numeri.c
Compilatelo e provate ad eseguirlo su un file di testo che potete creare voi
con notepad++, ad esempio su un file "testo.txt" che contiene:

"Ciao ragazzi, finora 10 + 100 fa 110,
ma oggi decido che 2 + 2 = 5."

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>
#include <ctype.h>

#define LINELEN 1024

void stampalo(FILE *f)
{
    char line[LINELEN]; 
    char num[LINELEN];
    
    // fgets == NULL se non leggo nulla (file finito).

    while (fgets(line,LINELEN,f) != NULL)
    {
        // ok, line contiene una linea di testo.
        // cerco la prima cifra:
        int i = 0;
        while (i<LINELEN && line[i]!='\0' && !isdigit(line[i])) i++;
     
        if (i == LINELEN) continue;   // finito, leggo la riga successiva.
 
        int j = 0, c = 0;
        while (j<LINELEN && (c = line[i++])!='\0' && isdigit(c)) num[j++] = c;
        num[j] = '\0';   // la stringa va terminata con lo zero se no..cavoli amari.
        if (j>0) printf("%s\n",num);
    }
}

int main(int argc, char *argv[])
{
    // argomento main: nome di un file.
    
    if (argc < 2) {
        fprintf(stderr,"Uso: wordstat [nomefile]\n");
        exit(1);
    }
    char *nome = argv[1];
    FILE* input = fopen(nome,"r");  // apro in lettura
    if (input == NULL) {
        fprintf(stderr,"Errore: non riesco ad aprire il file %s\n",nome);
        exit(1);
    }

    stampalo(input);

    fclose(input);
    return 0;
}

Fun with Python:

scrivete il seguente programma, e salvatelo come "webread.py", nella stessa cartella del programma C fatto sopra.

import urllib.request
import sys

if len(sys.argv) < 2:
    print("leggiweb: url")
url = sys.argv[1]
html = ""
with urllib.request.urlopen(url) as response:
    html = response.read()
print(html)

adesso eseguite:

python3 webread.py http://www.repubblica.it > giornale.html

e subito dopo:

numeri.exe giornale.html

il risultato estrarrà tutti i numeri presenti nel codice html della pagina frontale (home) di repubblica.it
(compresi tutti quelli presenti nel codice javascript presente, quindi ..molti).
Se avete problemi nell'eseguire python3 da console, potete 1) aprire una console python e poi spostarvi dentro la cartella giusta, oppure come spiegato, inserire nel path della console corrente, la cartella che contiene l'eseguibile dell'interprete python:
cercate python.exe o python3.exe nella cartella dell'installazione di python, ed una volta trovata tale cartella, inserite:

 set PATH=percorsocartella;%PATH%

se per caso ci sono spazi all'interno del percorso è necessario fare:

 set "PATH=percorsocartella;%PATH%"

e verificate se python3 viene eseguito, questo vale per ogni programma.

Esercizi

Esercizio 1: scrivere un programma "calc" che riceve da linea di comando sempre e solo due valori floating point con in mezzo un operatore "+" "-" etc. ad esempio

calc 2.4 + 3

Il programma legge gli argomenti, converte i numeri in modo appropriato, calcola il valore dell'operazione e stampa il risultato. Che problemi si pongono? cosa accade ad esempio se non inserisco gli spazi tra gli argomenti? "3+4.2".

Esercizio 2: Scrivere un piccolo "interprete" di espressioni, chiamiamolo minipython l'interprete esegue un ciclo in cui:
1. stampa il prompt " > "
2. legge una stringa che l'utente inserisce terminata con <enter>, la stringa è un espressione come sopra. accettate questa volta espressioni con spazi o senza ad esempio "2+3" o "3.14 * 2" o "3   +   4   -   8", consiglio: leggete la stringa con fgets(comando,LEN,stdin); poi elaborate carattere per carattere della stringa comando con un while. Usate le funzioni di libreria in ctypes.h per capire se il carattere è una cifra, e usate una stringa secondaria per separare i vari "pezzi" che chiameremo "token" (biscottini). Il primo passo quindi consiste nel riuscire a scomporre e stampare l'epressione sopra come I(2) OP(+) F(3) dove (I,F,OP) è un modo per far capire che quello che ho riconosciuto la parte della stringa corrispondente e l'ho convertita nel tipo adeguato (intero, float, operatore). Una volta fatto questo, potete banalmente fare uno switch sull'op per calcolare il valore dell'espressione ed eseguirla al punto sotto. Preoccupatevi solo di espressioni del tipo "numero op numero op numero op numero op numero", tipo "3 + 4.5 + 1 - 8 * 3" senza preoccuparvi di come gestire le precedenze tra gli operatori, quindi per voi "3 + 4 * 2" sarà uguale a "14" e non come dovrebbe "11".
3. esegue l'espressione e stampa il risultato, e ritorna al punto 1.

Esercizio 3: scaricare "alice dal paese delle meraviglie" da Liber Liber, come file txt, scompattate se zippato, e scrivete un programma che riceve come argomento dalla linea di comando il nome del file con dentro alice, e stampa sul terminale un elenco delle parole presenti nel file senza i segni di interpunzione (virgole, punti, etc), non vi preoccupate se i caratteri accentati non sono gestiti correttamente.