Funcions d'entrada/sortida
Objectius
- Entendre el concepte d’entrada i sortida.
- Conèixer els mètodes per a llegir dades de l’entrada.
- Conèixer els mètodes per a escriure dades a la sortida.
Introducció
Els programes informàtics bàsicament són manipuladors d’informació, ja sigui un programa de comptabilitat, un sistema d’intel·ligència artificial o el sistema operatiu d’un ordinador. Per tant, els programes necessiten poder obtenir aquesta informació per a processar-la i poder donar sortida als resultats. Si no tenim entrada, els programes es limitarien a fer sempre el mateix amb les mateixes dades i, si no tenim sortida, els resultats del programa mai es podrien utilitzar per a res.
Quan pensem en entrada de dades ens referim a qualsevol tipus d’entrada; poden ser les tecles que es premen en un teclat, la posició del ratolí o pantalla tàctil, un fitxer en disc, una adreça d’internet, un lector de codis de barres, una webcam o el micròfon. De la mateixa manera, quan parlem de sortida ens podem referir a un ampli ventall d’opcions, des de la pantalla de l’ordinador, un arxiu, una impressora o el sistema de control d’un robot.
Entre tots aquests dispositius hi ha dos que tenen un paper especialment rellevant: el teclat per a l’entrada de dades i la pantalla per a la sortida de dades. De fet, si no es canvia explícitament, l’entrada estàndard (o stdin de l’anglès standard input) és el teclat, i la sortida estàndard (o stdout de l’anglès standard output) és la pantalla.
En aquesta guía veurem com podem comunicar-nos amb aquests dispositius per a llegir informació des del teclat i mostrar-la en la pantalla.
1. Entrada
El primer que cal saber és que quan es premen tecles en un teclat, aquestes es converteixen en el seu codi ASCII i s’emmagatzemen com a caràcters en el que es diu un buffer, el qual conté tota la seqüència de caràcters que han escrit i que cap programa ha llegit encara.
Els mètodes per a llegir dades aniran llegint d’aquest buffer considerant quin tipus d’informació intentem llegir. Cal tenir en compte que el salt de línia també compta com una tecla qualsevol i es representa habitualment amb ‘\n’. Aquest buffer és una estructura coneguda com a FIFO (First In First Out), la qual cosa vol dir que ho llegirem en ordre d’arribada. A continuació es mostra un exemple del contingut del buffer a mesura que es van prement tecles del teclat:
Tecla premuda | Contingut del buffer |
---|---|
1 | ‘1’ |
3 | ‘3’ ‘1’ |
2 | ‘2’ ‘3’ ‘1’ |
Salt de línia | ‘\n’ ‘2’ ‘3’ ‘1’ |
a | ‘a’ ‘\n’ ‘2’ ‘3’ ‘1’ |
Salt de línia | ‘\n’ ‘a’ ‘\n’ ‘2’ ‘3’ ‘1’ |
Per a llegir la informació d’aquest buffer, tenim a la nostra disposició un conjunt d’instruccions en llenguatge algorísmic segons el tipus de dades que volem llegir:
Instrucció | Descripció |
---|---|
readChar | Llegeix un caràcter del buffer |
readBoolean | Llegeix un booleà del buffer |
readInteger | Llegeix un enter del buffer |
readReal | Llegeix un real del buffer |
readString | Llegeix una cadena de caràcters del buffer |
Vegem quin seria el resultat d’aplicar aquestes instruccions tenint en compte que c és una variable de tipus caràcter, i una variable de tipus enter i r una de tipus real:
Buffer Inicial | Instruccions | Buffer final | Resultat |
---|---|---|---|
‘\n’ ‘a’ ‘\n’ ‘2’ ‘3’ ‘1’ | c:= readChar() | ‘\n’ ‘a’ ‘\n’ ‘2’ ‘3’ | La variable c conté el valor 49 (valor ASCII del caràcter 1). |
‘\n’ ‘a’ ‘\n’ ‘2’ ‘3’ ‘1’ | i:= readInteger() | ‘\n’ ‘a’ | La variable i conté el valor 132. Atès que els enters poden tenir diverses xifres, es llegeix fins al salt de línia o un espai. |
‘\n’ ‘a’ ‘\n’ ‘2’ ‘3’ ‘1’ | r:= readReal() | ‘\n’ ‘a’ | La variable r conté el valor 132,0. Atès que els reals poden tenir diverses xifres, es llegeix fins al salt de línia o un espai. |
‘\n’ ‘a’ | c:= readChar() | ‘\n’ | La variable c conté el valor 97 (valor ASCII del caràcter a). |
‘\n’ ‘a’ | i:= readInteger() | Error. No es pot interpretar la lletra a com un enter. | |
‘\n’ ‘a’ | r:= readReal() | Error. No es pot interpretar la lletra a com un real. |
2. Sortida
En el cas de la sortida passa una cosa similar. Quan escrivim a la sortida estàndard, tota la informació queda guardada en forma de caràcters en un buffer, que es va llegint i mostrant a la pantalla.
Per a escriure la informació en aquest buffer i es mostri, tenim a la nostra disposició una sèrie d’instruccions en llenguatge algorísmic segons el tipus de dades que volem escriure:
Instrucció | Descripció |
---|---|
writeChar | Escriu un caràcter al buffer |
writeBoolean | Escriu un booleà al buffer |
writeInteger | Escriu un enter al buffer |
writeReal | Escriu un real al buffer |
writeString | Escriu una cadena de caràcters al buffer |
3. Entrada i sortida en C
Per a poder accedir a l’entrada i sortida estàndards en C, necessitarem utilitzar una llibreria estàndard de C. Les llibreries són conjunts de funcionalitats que estenen les instruccions bàsiques del llenguatge C, facilitant fer certes tasques. En aquest cas la llibreria es diu stdio (standard input/output) i, per a poder utilitzar-la, haurem d’importar-la al nostre programa. Per a això, haurem d’afegir la següent línia de codi al principi del nostre arxiu (sense punt i coma):
Una vegada importada, podem utilitzar les seves funcionalitats directament. Tant en el cas de l’entrada com en el de la sortida, cal especificar el tipus i format de les dades. Per a això, es passa la cadena de format d’entrada i sortida, on les variables que es volen llegir o escriure s’indiquen amb el símbol % i, a continuació, una lletra especificant el tipus de variable. A continuació es mostra un resum de les més habituals:
Tipus de dada | Especificatiu de tipus | Exemple de dades |
---|---|---|
Caràcter | %c | 'a' |
Boolean | %u | 0 (equivalent de true), 1 (equivalent de false); en general, qualsevol tipus enumeratiu utilitzarà l'especificatiu %u. |
Enter | %d | 34 o -32 |
Real | %f | 3.1415 |
String | %s | "Hello World" |
Punter | %p | 0x000000AA; els punters els tractarem al mòdul "13. Punters en C". |
A continuació veurem exemples d’aquestes cadenes de format per a l’entrada i la sortida.
3.1. Entrada
El mètode genèric per a l’entrada de dades és el mètode scanf, que espera una cadena de format indicant què ha de llegir del buffer de teclat i la llista de variables on es guardaran els valors llegits. Totes les variables han d’anar precedides del símbol & (que significa «adreça de» i que veurem en la unitat de memòria). A la taula següent tenim la traducció dels mètodes en llenguatge algorísmic anteriors, tenint en compte que c és una variable de tipus caràcter, i de tipus enter i r de tipus real:
Mètode | Traducció a C |
---|---|
readChar | scanf("%c", &c) |
readBoolean | scanf("%u", &b) |
readInteger | scanf("%d", &i) |
readReal | scanf("%f", &r) |
readString | scanf("%s", s) |
A més, en el cas de llegir un caràcter tenim la instrucció getchar que ens permet fer una assignació directa:
3.2. Sortida
En el cas de la sortida per pantalla, tenim el mètode printf, que espera una cadena de format indicant què ha d’escriure i la llista de variables d’on obtenir la informació. A la taula següent tenim la traducció dels mètodes en llenguatge algorísmic anteriors, tenint en compte que c és una variable de tipus caràcter, i de tipus enter i r de tipus real:
Mètode | Traducció a C |
---|---|
writeChar | printf("%c", c) |
writeBoolean | printf("%u", b) |
writeInteger | printf("%d", i) |
writeReal | printf("%f", r) |
writeString | printf("cadena de caràcters") |
writeString | printf("%s", s) |
A més, cal recordar que tenim un caràcter especial per a indicar el salt de línia (‘\n’), que el podem utilitzar en el format per a indicar que volem que es faci un salt de línia. En cas contrari tot s’escriurà seguit a la mateixa línia.
Addicionalment, podem afegir modificacions de com volem que es mostrin les dades. Aquests modificadors es posen entre el símbol % i l’especificatiu de tipus:
%[modificadors][amplada][.precisió]especificador
A continuació veiem uns quants exemples. Podeu trobar més informació aquí.
Format | Valor variable | Sortida |
---|---|---|
"%0d" | 3 | 3 |
"%03d" | 003 | |
"%f" | 3.14 | 3.14000 |
"%2.1f" | 3.14 | 3.1 |
4. Exemples
4.1. Exemple 05_01: entrada
Enunciat:
Definiu un algorisme que llegeixi dos enters i calculi la seva suma. Feu la seva traducció a C.
Solució:
algorithm sum
var
a: integer;
b: integer;
s: integer;
end var
a:= readInteger();
b:= readInteger();
s:= a + b;
end algorithm
int main() {
int a;
int b;
int s;
scanf("%d", &a);
scanf("%d", &b);
s=a+b;
return 0;
}
4.2. Exemple 05_02: sortida
Enunciat:
Definiu un algorisme que, donades dues variables a = 2 i b = 2, escrigui per pantalla el missatge: «La suma d’a i b és 4». Feu la seva traducció a C.
Solució:
algorithm sumaSortida
var
a: integer;
b: integer;
end var
a:= 2;
b:= 2;
writeString("La suma d'a i b és :");
writeInteger(a + b);
end algorithm
int main() {
int a=2;
int b=2;
printf("La suma d'a i b és : %d", a + b);
return 0;
}
4.3. Exemple 05_03: entrada i sortida
Enunciat:
Definiu un algorisme que requereixi tres enters i mostri per pantalla el valor mitjà dels tres. Feu la seva traducció a C.
Solució:
algorithm sumaEntradaSortida
var
a: integer;
b: integer;
c: integer;
m: float;
end var
a:= readInteger();
b:= readInteger();
c:= readInteger();
m=(a+b+c)/3.0;
writeReal(m);
end algorithm
int main() {
int a;
int b;
int c;
float m;
scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);
m=(a+b+c)/3.0;
printf("%f", m);
return 0;
}
Resum
En aquesta guía hem vist la utilització dels mètodes scanf i printf per a llegir i escriure dades en els dispositius estàndard d’entrada i sortida. També hem vist que es pot modificar el format de les dades.