Total Hack Cheat
Benvenuto/a su Total hack Cheat....
non aspettate altro tempo Registratevi!!

Parte 2 (3) guida linguaggio C

Vedere l'argomento precedente Vedere l'argomento seguente Andare in basso

Parte 2 (3) guida linguaggio C

Messaggio Da RaYoZ il Gio Mag 20, 2010 12:56 pm

Matrici e arrays

Anche questo argomento lo abbiamo gia' affrontato nei capitoli sulla programmazione strutturata.
Ripetiamo brevemente i concetti fondamentali. Una variabile dichiarata ad esempio come char potra' contenere un valore compreso tra -128 e +127 e quindi rappresentare un carttere ASCII.

Nel caso in cui dovessimo memorizzare una stringa intera o piu'stringhe dovremmo dichiarare la variabile come un arrays o una matrice di char.
Una stringa e' considerata nel linguaggio C come una sequenza di caratteri finalizzata da '\0' (carattere di fine stringa).
Supponiamo di dichiarare la variabile 'nome' come
char nome[5];

e di assegnarle la stringa "Ciao".
Avremo come risultato

+---+---+---+---+---+---+
nome[5] = | C | i | a | o |\0 | |
+---+---+---+---+---+---+
nome [ 0 , 1 , 2 , 3 , 4 , 5 ]

L'indice dell'array incomincia la numerazione da 0 e quindi la dichiarazione precedente riserva 6 bytes.
Nel caso invece di matrici utilizzeremo due indici, uno per indicare la riga e uno per la colonna.
Molte funzioni inseriscono automaticamente il carattere '\0' automaticamente ma esistono alcune situazioni in cui saremo noi a
doverlo mettere. Supponiamo ad esempio di voler estrarre da una stringa inputata da tastiera quale "Oggi ho visto Franco" la parola "Oggi".
Dovremo eseguire una funzione del tipo di quella che segue :

main()
{
/* Massimo 20 car. */ char stringa[20];
int indice, input;
indice=0;
/* Finche'!= spazio*/ while((input=getchar()) != ' ')
{
stringa[indice]=input;
++indice;
}
stringa[indice] = '\0';
}


Avremmo potuto codificare il tutto anche nel seguente modo

main()
{
char stringa[20];
int indice=0;
while((stringa[indice]=getchar())!=' ')
++indice;
stringa[indice]='\0';
}

oppure ancora

main()
{
char stringa[20];
int indice=0;
while((stringa[indice++]=getchar())!=' ');
stringa[indice]='\0';
}

In questo caso siamo stati noi mediante un opportuna operazione di assegnazione a inserire il carattere di fine stringa.
Prendiamo ad esempio una matrice del tipo che segue.

char matrice[2][3];

Supponiamo di averle assegnato le stringhe "Uno", "Due" e "Tre".
La rappresentazione avra' la seguente forma.

+---+---+---+---+
| U | n | o |\0 |
+---+---+---+---+
matrice[0][ 0 , 1 , 2 , 3 ]
+---+---+---+---+
| D | u | e |\0 |
+---+---+---+---+
matrice[1][ 0 , 1 , 2 , 3 ]
+---+---+---+---+
| T | r | e |\0 |
+---+---+---+---+
matrice[2][ 0 , 1 , 2 , 3 ]


Come e' possibile notare esiste una somiglianza con l'esempio fatto per un array monodimensionale.
Per ora trattiamo i vettori e le matrici mediante gli indici anche se posso preannunciare che non e' l'unico modo per riferirsi a queste.
Un altro metodo e' quello di accedere a ogni casella di ogni riga specificando l'indirizzo di questa.
L'argomento verra' trattato con i puntatori.



Input e output formattato

Negli esempi precedenti abbiamo utilizzato la funzione C printf per eseguire la stampa di un risultato. Printf e scanf costituiscono due funzioni che permettono rispettivamente di eseguire un output ed un input formattato.
Vediamo la forma di utilizzo del primo.

Printf e' costituito da una stringa racchiusa tra virgolette composta da caratteri che dovranno essere stampati letteralmente e da simboli "formattatori" o specifiche di conversione che indicano il tipo di dato che dovra' essere stampato in una determinata posizione.

printf("Ciao %s. Questo e' il collegamento %d", nome, num);
^ ^ ^ ^
+-----------------------------|-----+ |
+----------+

Nell' esempio precedente il primo argomento (nome) sara' un vettore, ovvero una stringa, che conterra' un nome e il secondo argomento (num) un intero.
I simboli % seguiti da caratteri indicano il tipo di dato che deve essere stampato in quella posizione.
Supponendo che alla variabile nome sia stato assegnato "Franco" e a quella num il valore 34 avremmo come risultato

Ciao Franco. Questo e' il collegamento 34

Al fine di evitare pasticci gli argomenti devono essere accoppiati

ai rispettivi simboli % in ordine di comparsa (vedi tratteggio nell'esempio precedente).
La funzione printf non esegue automaticamente un ritorno a capo e
quindi se si desidera che dopo la stampa della stringa questo avvenga bisogna aggiungere un '\n'.
L'esempio precedente diventa in questo caso


printf("Ciao %s. Questo e' il collegamento %d \n", nome, num);

L'utilizzo di '\n' non e' necessariamente destinato al fine riga ma al contrario puo' essere inserito in qualsiasi punto della stringa ove si voglia eseguire un ritorno di carrello.
Una lista incolonnata potrebbe essere stampata in questo modo.
Supponendo che var1, var2 e var3 siano tre variabili numeriche intere che valgono rispettivamente 1, 2 e 3 avremo

printf("%d \n%d \n%d \n", var1, var2, var3);

e il risultato sara'

1
2
3


Prima di proseguire parlando della funzione di input vediamo il significato dei caratteri che formano le specifiche di conversione.


Chiameremo d'ora in poi stringa di formato quella costituita da
queste ultime.


Specificatore Descrizione
---------------------------------------------------
%d Intero decimale
%ld Interi decimale long
%u Intero unsigned
%f Float
%e Notazione esponenziale
%c Un carattere singolo
%s Una stringa
%x Valore in esadecimale
%o Valore ottale

I caratteri che abbiamo visto abbinati al simbolo % dichiarano soltanto il tipo del dato che deve essere trattato.
E' possibile mediante cifre interposte tra % e lo specificatore stabilire anche altri parametri quali lo spazio che dovra' occupare, il numero di valori prima e dopo del punto decimale.
Ad esempio

printf(" %5.2f ", var_float);

stampera' un valore in virgola mobile con 5 cifre prima della virgola e 2 dopo.
Inserendo anche lo 0 si ottiene che nel caso non si raggiunga il numero di cifre specificate le rimanenti siano completate con 0.

printf(" %03d ", var_int);

stampera' la variabile decimale intera var_int mantenendo per questa tre spazi e inserira' degli 0 se questa non occupera' tutto lo spazio a disposizione.

Ad esempio : 022 se var_int vale 22

Scanf e' simile a printf in quanto offre facilitazioni di conversione sul tipo di dati inputati.
L'operatore unario & fatto precedere ad un identificatore di variabile fornisce l'indirizzo di questa.
Nella funzione scanf dovremo fornire infatti l'indirizzo delle variabili in cui dovra' allocare i valori inputati fatta eccezione per gli array di char che gia' di default vengono trattati dal C come indirizzi.
In altre parole scanf pretende che gli vengano forniti i puntatori.
Scanf accetta come separatori dei valori inseriti spazi bianchi, tab e ritorni a capo essendo questi ultimi considerati come i primi.
La funzione termina esclusivamente dopo aver ricevuto l'ultimo valore che si aspettava.
In molte applicazioni e' conveniente utilizzare altre forme per inputare i dati in quanto la funzione scanf in alcuni casi procura dei problemi.


Ad esempio non permette di saltare un input mediante la semplice
battitura del tasto return (CR).
Vediamo ora due esempi di utilizzo della funzione di input formattato, il primo errato mentre il secondo giusto.

int var1;
/* ERRATO */ char sigla[10];
scanf("%d %s", var1, sigla);
^ Errore


int var1;
/* ESATTO */ char sigla[10];
scanf("%d %s", &var1, sigla);

La funzione , nel caso di un array di char, sostituisce il carattere di \n con il carattere di fine stringa \0.
Valgono per scanf le stesse specifiche di formato che abbiamo visto per printf.


Altre funzioni per l' I/O

Alcune funzioni di I/O pretendono la conoscenza del concetto di stream e quindi le tratteremo piu' avanti.
Vediamo ora quelle di uso piu' comune.

putchar(var); : Stampa il carattere contenuto nella variabile var sullo standard di output.

var=getchar(); : Inputa dallo standard di input un carattere e lo salva in var.
Var normalmente viene dichiarato come int in quanto la funzione getchar restituisce anche codici di errore che non possono essere salvati in un char.

puts(var); : Stampa sullo standard d'output la stringa var e aggiunge un \n alla fine di questa.

gets(var); : Inputa una stringa dallo standard di input e ritorna un argomento per indicare ad esempio un errore di fine file.

var=getch(); : Inputa un singolo carattere senza visualizzarlo sullo schermo e lo colloca in var.



Stream predefiniti (stdout, stdin, stdprn, stdaux, stderr)

Quando un programma viene eseguito questi streams vengono automaticamente aperti.
Stdout equivale normalmente allo schermo video, stdin alla tastiera, stdprn alla stampante ed stdaux a una porta ausiliaria tipo COM1.
Ho omesso stderr in quanto ha un significato particolare sotto Unix ma non e' differenziato da stdout in ambiente MS DOS.
Sotto Unix infatti, oltre allo standard di output (stdout) e a quello di input (stdin) esiste lo standard di errore (stderr).
Lo scopo di quest'ultimo e' dovuto dal fatto che essendo Unix un sistema operativo multiutente e multitasking esiste la possibilita' di eseguire piu'lavori conteporaneamente in background, ad esempio compilazioni, mentre l'utente si dedica a qualche cosa d'altro.
Nel caso di compilazioni, ad esempio, si potrebbero avere dei messaggi di errore che in caso di mancata redirezione dello standard di errore raggiungerebbero la console dell'operatore disturbando, magari, il lavoro che stava svolgendo.
Nel compilatore Microsoft questo viene incluso come uno stream separato per compatibilita' con l'ambiente Xenix.


Stream

L'utilizzo degli streams e' uno dei metodi che permette di eseguire delle funzioni di I/O su files.
Come vedremo successivamente esiste anche il modo di riferirsi all'handle di un file ovvero un valore int associato allo stesso.
In italiano handle indica il gestore del file.
L'apertura di uno stream si esegue dichiarando un identificatore come di tipo FILE.
FILE e' il nome di un tipo definito come una struttura, dichiarata nell'header stdio.h, che contiene le informazioni basilari sul file aperto.
L'apertura di uno stream ritorna un puntatore alla struttura FILE che verra' utilizzato come riferimento per tutte le operazioni di I/O su files.

FILE *files;

Dopo aver fatto una dichiarazione di questo tipo potremo utilizzare la funzione standard di libreria fopen per fare ritornare un puntatore ad un FILE.

files = fopen("nome_file","r");

Fopen pretende due argomenti ed esattamente il path del file a cui uno vuole riferirsi e il modo di apertura di quest'ultimo.

Sono validi i seguenti modi.

"r" - Apre un file in sola lettura.
Il file deve esistere. (vedi ritorno NULL)

"w" - Apre il file in scrittura.
Se il file esiste il contenuto viene
distrutto.

"a" - Apre il file per scrivere alla fine di
questo.
Se il file non esiste viene creato.

"r+" - Apre il file sia per lettura che per
scrittura.
Anche in questo caso il file deve esistere.

"w+" - Apre il file in lettura e scrittura.
Distrugge il contenuto se questo esiste
gia'.

"a+" - Apre il file per leggere e aggiungere.
Se il file non esiste viene creato.

A questi modi puo' essere aggiunto uno specificatore di
translazione ed esattamente

t Esegue l'apertura in modo testo.
Le combinazioni linefeed (LF)/carriage
return (CR) sono translate in input in un
solo carattere di LF.
In output invece un carattere di LF viene
translato in una sequenza CR/LF.

b Esegue l'apertura in modo binario.
Le translazioni precedenti sono soppresse.

Se il file specificato dall'argomento path non esiste fopen
ritorna un NULL, definito anche quest'ultimo nell'header stdio.h.
NULL puo' essere utilizzato per verificare l'esistenza di un file
prima di procedere nell'esecuzione di un programma.

FILE *files;
funz()
{
if((files=fopen("fil.ext","r")) == NULL)
{
printf("ERRORE: Non trovo il file");
exit(0);
}
..............
..............
}


Se il puntatore restituito non e' un NULL potremo riferirci a questo per le nostre operazioni sul file mediante le funzioni di libreria che ora vedremo.

** fprintf(stream,stringa formato,argomenti);

Mentre printf si riferiva esclusivamente a stdout, fprintf esegue una stampa formattata sullo stream di output aperto.
La stringa di formato ha le stesse caratteristiche di quella utilizzata con printf.

Esempio:

funz()
{
FILE *files;
char nome[20];

files = fopen("dati.arc","a");
printf("Inserisci il nome : ");
scanf("%s", nome);

fprintf(files," %s ", nome);
.............
}

Come fprintf esegue l'output formattato sullo stream, fscanf esegue l'input formattato da questo.

** fscanf(stream,stringa formato,argomenti);

Il puntatore al file viene incrementato man mano che vengono eseguite funzioni di lettura da questo in modo che ogni scanf avvenga dalla posizione successiva a quella precedente.
Viene restituito l'intero EOF se la funzione tenta di leggere oltre la fine del file.

** fgets(stringa,num_car,stream);

fgets legge dallo stream associato aperto un numero num_car di caratteri e li salva nella stringa specificata.

** fputs(stringa,stream);

Mentre la funzione precedente leggeva , fputs stampa una stringa sullo stream di output.

** var = getc(files);

Questa funzione salva in var un carattere letto dallo stream.


Un esempio di uso di getc.

#include <stdio.h>

main()
{
FILE *files;
int var;

files = fopen("data.txt","r");
while((var=getc(files)) != EOF)
putchar(var);
}

Il programma legge ad uno ad uno i caratteri dal files data.txt, fino a che non incontra la fine del file (EOF = -1), e li stampa sullo standard di output.
getc(stdin) e' l'equivalente di getchar().

** putc(var,stream);

scrive un carattere sullo stream.
Esempio di programma che esegue la copia di un file.

#include <stdio.h>

main()
{
FILE *infile, *outfile;
int var;

infile =fopen("data1,txt","r");
outfile=fopen("data2.txt","w");
while((var=getc(infile)) != EOF)
putc(var,outfile);
............
}

Quelle che abbiamo appena visto sono alcune delle funzioni principali di libreria che ci permettono di manipolare dati sui files associati agli streams.



Funzioni di controllo stream

Esistono nella libreria standard del compilatore Microsoft C alcune funzioni che ci permettono di controllare un determinato stream ad esempio per chiuderlo o per riposizionare il puntatore a questo.

La funzione fopen ci permette di aprire un determinato files e di associarlo ad uno stream.
fclose ci permette invece di chiuderlo e quindi di rilasciare il buffer di sistema.
La sintassi di utilizzo di fclose e' la seguente

fclose(stream);

Nel caso che si voglia chiudere conteporaneamente tutti gli streams aperti fino a quel punto e' possibile usare la funzione fcloseall.
fcloseall restituisce il numero di streams chiusi e quindi il modo di utilizzarla e'

int num_stream;
num_stream=fcloseall();

Le funzioni come fscanf, getc ecc. ad ogni chiamata incrementano
il puntatore al file associato in modo che questo punti al carattere successivo.
La funzione fseek permette di riposizionare il puntatore al file associato a uno stream.

var=fseek(stream,distanza,origine);

dove distanza e' un intero lungo.
Per origine si intende una delle seguenti costanti.

0 Inizio del file
1 Posizione corrente
2 Fine del file

La distanza e' relativa all'origine.
Il manuale del compilatore Microsoft avvisa che se la funzione fseek viene utilizzata con uno stream aperto in modo testo potrebbe dare luogo a risultati non aspettati.
L'unica operazione garantita in questo caso e' con un valore di distanza di 0 da qualsiasi punto specificato come origine.
fseek ritorna un valore 0 se l'operazione di posizionamento ha avuto successo mentre un valore diverso indica una condizione di errore.
Il valore puo' essere testato nella variabile var (vedi esempio precedente).
Una funzione che riposiziona all'inizio del file un puntatore associato ad uno stream e' rewind.

var = rewind(stream);

e' l'equivalente di

var = fseek(stream,0L,0);


Come nel caso di fseek, rewind restituisce 0 se l'operazione ha avuto successo.



Macro

Il concetto di macro e' simile a quello di definizione di costante solo che in questo caso la sostituzione ad ogni ricorrenza del nome della macro non e' statica ma attiva.
Esempio:

#define SOMMA(x,y) x+y

La macro verra' chiamata nel seguente modo

SOMMA(5,5);

e il compilatore sostituira' il valore dato dalla somma, in
questo caso, degli argomenti passati.
Un altro esempio

#define BELL putchar('\007')

dove \007 e' il codice ascii del beep emesso dall'altoparlante
del computer.
Quando nel programma verra' incontrato

BELL;

il computer emettera' un suono in quanto eseguira' la funzione associata al nome della macro e cioe' "stampa il carattere ascii
7".
Il linguaggio C al contrario dei linguaggi come il Basic o il Turbo Pascal non possiede funzioni di utilita' per la cancellazione dello schermo, di una linea, per lo spostamento del cursore, per la selezione degli attributi video.
Per ovviare a questa mancanza diventano particolarmente utili le
definizioni di particolari macro che utilizzano sequenze di escape per eseguire funzioni quali quelle precedenti.
Il codice di ESC per la costruzione di queste macro e'

\33[

Vedrete qui a seguito le varie funzioni ottenibili mediante queste sequenze.
Per ora vediamo come utilizzarle nel caso che siano necessari argomenti e nel caso che invece sia solo sufficente la sequenza stessa.
Supponiamo ad esempio di dover scrivere una macro che cancelli lo
schermo.

Questa non necessita del passaggio di alcun parametro e quindi sara' sufficente definirla nel seguente modo.


#define CLEAR puts("\33[2J")

Un caso ben differente e' invece quello relativo ad una macro per il posizionamento del cursore a certe coordinate dello schermo.
In questo caso dovremo fornire i valori della riga e della colonna.
Non potendo stampare dei valori contenuti in una variabile mediante la funzione puts dovremo utilizzare printf che permette di specificare la posizione di stampa mediante la sua stringa di formato.

#define AT(x,y) printf("\33[%d;%dH", x, y)

La macro verra' richiamata con

AT(x,y);

dove x e' la riga e y la colonna.
Per comodita' nell'elenco seguente ho sostituito \33[ con ESC.


Sequenze ESC per controllo video

Attenzione : nelle sintassi descritte successivamente '#' e' un
: valore numerico. Se non espresso vengono utilizzati
: i valori di default.


ESC[#,#H (Cursor Position)

Muove il cursore alla posizione specificata nei parametri.
Il primo specifica la riga mentre il secondo la colonna.
Il valore di default e' uno.

ESC[#A (Cursor Up)

Posiziona il cursore su di una o piu' righe.
# specifica il numero di righe.
Il valore di default e'uno.

ESC[#B (Cursor Down)

Come il precedente ma verso il basso.

ESC[#C (Cursor Forward)

Muove il cursore avanti di una o piu' colonne.

RaYoZ
Admin
Admin

Messaggi : 1040
Punti : 2245
Data d'iscrizione : 03.04.10
Età : 22
Località : immerso nei pensieri

Tornare in alto Andare in basso

Vedere l'argomento precedente Vedere l'argomento seguente Tornare in alto

- Argomenti simili

 
Permesso di questo forum:
Non puoi rispondere agli argomenti in questo forum