03 – Entrada y salida en lenguaje C

Anuncio
03 – Entrada y salida en lenguaje C
Diego Andrés Alvarez Marín
Profesor Asociado
Universidad Nacional de Colombia
Sede Manizales
1
Temario
●
Entrada/salida básica (stdio.h)
●
Entrada/salida avanzada (ncurses.h)
2
Funciones de salida/entrada de
datos básicas
●
●
Las provee la librería estándar stdio.h y no el
lenguaje mismo.
stdio.h significa "standard input-output header"
(cabecera estandar E/S)
–
stdin = standard input = teclado
–
stdout = standard output = pantalla
–
stderr = standard error
3
Funciones básicas de salida a
pantalla (stdout)
●
●
Sin formato:
–
putchar() escribe un caracter a stdout
–
puts() escribe una cadena de caracteres a stdout
Con formato:
–
printf() escribe una cadena de caracteres con
formato a stdout
4
int putchar(int ch);
●
Escribe un caracter en la pantalla (stdout)
●
Retorna ch
5
Algunos caracteres especiales
Alerta (audible)
\a
Backspace
\b
Tabulador horizontal \t
Escape (solo GNU) \e
Número octal (ej: \o32)\o
Backslash
\\
Nulo
\0
Retorno de carro
Formfeed
Comillas
Cambio de linea=\r\f
Número hex (ej: \xF3)
Apóstrofe
Pregunta
\r
\f
\”
\n
\x
\'
\?
int puts(const char* str);
Escribe la cadena str a stdout y agrega automáticamente
un “\n”. La cadena str termina cuando se encuentra un
caracter “\0”. El “\0” no se copia a stdout
8
int printf(const char* formato,...)
);
printf() retorna el número de caracteres
impresos, o un valor negativo si ocurre un
error.
printf() toma un número variable de entradas
9
int printf(const char* formato,...)
formato en printf()
●
●
Es una cadena de texto que indica el formato
como se debe escribir lo deseado
Sigue el siguiente prototipo:
%[banderas][ancho][.precisión][longitud]especificador
Ver detalles en:
http://pubs.opengroup.org/onlinepubs/009695399/function
http://en.cppreference.com/w/cpp/io/c/fprintf
http://en.wikipedia.org/wiki/Format_string_attack
10
%[banderas][ancho][.precisión][longitud]especificador
Introducido en C99
Introducido en C99
Introducido en C99
11
%[banderas][ancho][.precisión][longitud]especificador
%[flags][width][.precision][longitud]especificador
12
%[banderas][ancho][.precisión][longitud]especificador
Introducido en C99
Introducido en C99
Introducido en C99
Introducido en C99
Introducido en C99
13
14
Observe que el \b no borró el guión -
15
Funciones básicas de entrada
desde el teclado (stdin)
●
●
Sin formato:
–
getchar() lee un caracter desde stdin
–
gets() lee una cadena de caracteres desde stdin
(C99 – desaconseja su uso, C11 – obsoleto)
–
gets_s() lee una cadena de caracteres desde stdin
(es el reemplazo de gets())
Con formato:
–
scanf() lee una cadena de caracteres con formato
desde stdin
16
int scanf(const char* formato, ...);
●
●
●
●
Lee datos del teclado (stdin) y lo almacena de
acuerdo al formato dado, en las direcciones de
memoria indicadas.
De forma a similar a printf() puede leer un
número variable de entradas; en este caso se
supone que cada entrada está separada por un
espacio en blanco
Ignora los espacios en blanco
Retorna el número de items de la cadena de
argumentos exitosamente leídos o un EOF
(constante igual a -1) si un error ocurre.
17
int scanf(const char* formato, ...);
●
El formato está dado por:
%[*][ancho][longitud]especificador
●
Ver detalles en:
http://en.cppreference.com/w/cpp/io/c/fscanf
18
%[*][ancho][longitud]especificador
C99
C99
C99
19
%[*][width][length]especificador
20
Observe este
comportamiento inesperado!!
21
|
22
int getchar(void);
Lee un caracter desde el teclado (mostrándolo).
A pesar de todo estoy leyendo en un char
23
char* gets (char* str);
●
El C99 no recomienda usar este comando. El
C11 lo vuelve obsoleto. La razón de esto es
que este comando hace vulnerable el programa
al ataque por hackers. Ver detalles en:
–
http://en.cppreference.com/w/c/io/gets
–
http://en.wikipedia.org/wiki/Buffer_overflow
–
http://c-faq.com/stdio/getsvsfgets.html
24
char* gets (char* str);
Buffer overflow!!
25
char* gets_s(char *str, rsize_t n);
●
●
●
Función sugerida en el C11, en reemplazo de
gets()
Lee a lo más n-1 caracteres de stdin en la
cadena apuntada por str. Automáticamente
agrega el \0 al final de la cadena
No está implementada todavía en el gcc v.4.6
(el que tengo instalado)
26
Otro
reemplazo de
gets(): fgets()
strchr() busca desde la
dirección buf hasta
que encuenta la
primera aparición de
un \n
27
Buffer
Un buffer (de datos) es un espacio de memoria, en el que se
almacenan datos para evitar que el programa o recurso que los
requiere, ya sea hardware o software, se quede sin datos durante una
transferencia.
Un buffer es como tener dinero en el banco (buffer), un trabajo
(entrada) y unos gastos fijos (salida). Si tienes un trabajo inestable,
mientras tengas ciertos ahorros, puedes mantener tus gastos fijos sin
problemas, e ir ingresando dinero cuando puedas según vas
trabajando. Si los ahorros son pequeños, en seguida que no tengas
trabajo, no vas a poder acometer los gastos fijos. De la misma forma si
escuchas música en Internet y tu programa de audio usa un buffer
pequeño, en cuanto que haya alguna interrupción en la descarga
(porque las descargas nunca tienen una velocidad constante), notarás
cortes de sonido, ya que faltará información.
El buffer de teclado es una memoria intermedia en la que se van
almacenando los caracteres que un usuario teclea, los cuales son
28
tratados por el computador a penas se libere un recurso.
¿Por qué este código
aparentemente
correcto no funciona?
Se presionó 20 (ENTER) y nada más.
El programa no me preguntó el nombre y terminó
29
Aquí el primer printf() pregunta la edad. Se escribe "20"
y se presiona ENTER. El buffer del teclado contiene:
2 0 \n
El scanf() lee el %d, es decir el 20 y lo guarda en la
variable edad; sin embargo deja el '\n' en el buffer del
teclado; ahora entra el fscanf() lee el '\n' y no alcanza a
leer el nombre. El problema es que scanf() dejó basura
en el buffer del teclado (concretamente el \n).
Según http://c-faq.com/stdio/gets_flush2.html la solución
es vaciar el buffer del teclado lo cual se puede hacer
con alguno de los siguientes comandos:
●
●
while((c = getchar()) != '\n' && c != EOF); //un ciclo vacío
__fpurge(stdin); //solo funciona con gcc/Linux (stdio_ext.h)
30
31
Nota con respecto a la entrada de
datos desde el teclado
scanf() no es muy versátil que digamos y tiene problemas
como el anteriormente mostrado. La mejor opción que se
tiene si se requiere seguridad procesando la entrada es
utilizar fgets(), sscanf() y/o alguna librería de regular
expressions: http://en.wikipedia.org/wiki/Regular_expression
No existen librerías de expresiones regulares en el estándar
de C, pero si algunas para ciertos sistemas como regex.h o
PCRE para UNIX/Linux:
http://www.lemoda.net/c/unix-regex/index.html
http://www.pcre.org/
Se podría también utilizar una interface con el comando de
consola grep.
32
33
NOTA: lenguajes como
PERL, PYTHON,
MATLAB tienen un muy
buen soporte para
expresiones regulares.
Les aconsejo
sinceramente aprender
a manejar las
expresiones regulares
cuando tengan
problemas con validar
entradas de texto, o
procesar una gran
cantidad de datos en
archivos. Es una
herramienta que los
puede sacar de apuros
en más de una
ocasión.
34
Tomado de: http://xkcd.com/208/
Preferiblemente no use scanf()
http://c-faq.com/stdio/scanfprobs.html
Una buena interface debe permitir la posibilidad
que el usuario entre errores: por ejemplo letras en
un campo donde se piden números, más o menos
caracteres que los esperados, etc. scanf() no es
capaz de tratar este tipo de situaciones. Por lo
tanto, se sugiere mejor utilizar fgets() y luego
interpretar lo leído utilizando sscanf() y/o algunas
otras técnicas como expresiones regulares.
Funciones como strtol(), strtok(), y atoi() son
bastante útiles.
35
Funciones de salida/entrada de
datos básicas <ncurses.h>
●
●
●
curses.h es una biblioteca que provee rutinas
de entrada/salida avanzadas y que permite al
programador escribir interfaces basadas en
texto.
Fue creada por Ken Arnold para el sistema
UNIX
BSD.
Sin
embargo,
existen
implementaciones para Linux (ncurses.h) y
para Windows (pdcurses.h).
Permite manejar detalladamente la pantalla,
manejar el mouse, crear interfaces de texto
36
amigables.
Tomada de: http://dmcradio.sourceforge.net/
37
38
Instalación en Windows de
pdcurses
●
Descargue de: http://pdcurses.sourceforge.net/
●
Lea las instrucciones de instalación.
●
O si está utilizando el MinGW, simplemente en
la línea de comandos escriba:
mingw-get install mingw32-libpdcurses mingw32-pdcurses
39
En Linux
●
Instale la librería libncurses5-dev o similar, ej.:
$ sudo apt-get install libncurses5-dev
●
Verifique que los siguientes archivos existan:
●
●
●
●
●
Observe que en este caso ncurses.h y curses.h
son el mismo archivo
40
Un primer ejemplo
Si no se pone este comando, la consola se comportará
de modo extraño. En linux esto se arregla con el
comando de consola reset. De todos modos se debe
poner siempre endwin().
41
42
43
Otros comandos de curses.h
●
int addch(const chtype letra_char);
●
int mvaddch(int y, int x, const chtype letra_char);
●
int move(int y, int x);
●
chtype inch(void);
●
int mvprintw(int y, int x, char *format, ...);
●
int getstr(char* string);
44
Material basado en:
●
http://www.slideshare.net/amraldo/introduction-to-c-programming-7898353
●
http://www.slideshare.net/petdance/just-enough-c-for-open-source-program
●
http://www.cplusplus.com/reference/cstdio/printf/
●
http://www.cplusplus.com/reference/cstdio/scanf/
●
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1049157810&id
●
Wikipedia
Descargar