03 - Entrada y salida en lenguaje C

Post on 15-Jun-2015

192 views 1 download

description

Si quiere descargar la presentación y los códigos fuente, dirijase a: http://programaciondecomputadoresunalmzl.wikispaces.com/codigos_y_diapositivas Le agradecería si me reporta los errores que encuentre en la diapositiva (daalvarez arroba unal punto edu punto co)

Transcript of 03 - Entrada y salida en lenguaje C

1

03 – Entrada y salida en lenguaje C

Diego Andrés Alvarez MarínProfesor Asociado

Universidad Nacional de ColombiaSede Manizales

2

Temario

● Buffer de memoria● Entrada/salida básica (stdio.h)● Entrada/salida avanzada (ncurses.h)

3

BufferUn 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 tratados por el computador apenas se libere un recurso.

4

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

5

Funciones básicas de salida a pantalla (stdout)

● Sin formato:– putchar() escribe un carácter a stdout

– puts() escribe una cadena de caracteres a stdout

● Con formato:– printf() escribe una cadena de caracteres con

formato a stdout

6

int putchar(int ch);● Escribe un carácter en la pantalla (stdout)● Retorna ch

\a \rBackspace \b \f

\t \”Escape (solo GNU) \e \n

\o \xBackslash \\ \'

\0 \?

Alerta (audible) Retorno de carroFormfeed

Tabulador horizontal ComillasCambio de linea=\r\f

Número octal (ej: \o32) Número hex (ej: \xF3)Apóstrofe

Nulo Pregunta

Algunos caracteres especiales

9

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 carácter “\0”. El “\0” no se copia a stdout

10

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

11

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/functions/fprintf.html

http://en.cppreference.com/w/cpp/io/c/fprintf

http://en.wikipedia.org/wiki/Format_string_attack

12

%[banderas][ancho][.precisión][longitud]especificador

Introducido en C99

Introducido en C99Introducido en C99

13

%[banderas][ancho][.precisión][longitud]especificador%[flags][width][.precision][length]specifier

14

%[banderas][ancho][.precisión][longitud]especificador

Introducido en C99Introducido en C99Introducido en C99Introducido en C99

Introducido en C99

15

16

Un bug en MinGWEn Windows existe un bug en las funciones printf() y scanf() con el formato tipo long o long long; por ejemplo:

scanf ("%llu \n", &x); o printf("%llu \n", x);

Generan el warning:warning: unknown conversion type character 'l' in format [-Wformat]

La solución es usar #include<inttypes.h> y scanf("%"SCNu64"",&x); // entre comillasprintf("%"PRIu64"",UINT64_MAX);

Más información en:http://stackoverflow.com/questions/10763854/printf-and-llx-in-gcc-under-windows-64x

17Observe que el \b no borró el guión -

18

Imprimir tildes en C

#include<locale.h>

setlocale(LC_ALL, “spanish”);

El estándar de codificación de caracteres UNICODE

Se diseñó para facilitar el tratamiento informático, transmisión y visualización de textos de múltiples lenguajes y disciplinas técnicas, además de textos clásicos de lenguas muertas. Unicode incluye sistemas de escritura modernos como: árabe, braille, copto, cirílico, griego, sinogramas (hanja coreano, hanzi chino y kanji japonés), silabarios japoneses (hiragana y katakana), hebreo y latino; escrituras históricas extintas, para propósitos académicos, como por ejemplo: cuneiforme, griego antiguo, fenicio y rúnico. Entre los caracteres no alfabéticos incluidos en Unicode se encuentran símbolos musicales y matemáticos, fichas de juegos como el dominó, flechas, iconos etc.

El estándar de codificación de caracteres UNICODE

● Se adoptó como norma ISO en 1993, como una extensión de los códigos ASCII.

● Se tiene espacio para 1'114.112 símbolos posibles (del 0x000000 al 0x10FFFF). Actualmente se usa la versión 6.3 (Septiembre de 2013). Esta versión define más de 110.000 símbolos.

● Los puntos de código se representan utilizando notación hexadecimal agregando el prefijo U+. El valor hexadecimal se completa con ceros hasta 4 dígitos hexadecimales cuando es necesario; si es de longitud mayor que 4 dígitos no se agregan ceros.

Los símbolos UNICODEhttp://www.unicode.org/charts/

● Se escriben como U+XXXXXX donde X es un hexadecimal (esto se llama el code point).

● En C se representa tal Unicode como \uXXXX (hasta 4 hexadecimales) o como \UXXXXXX (hasta 6 hexadecimales)

● En GNU/Linux se escribe con Ctrl+Shift+u+codepoint ENTER. Cuando esto se hace la letra u aparece subrayada. Se debe tener una fuente apropiada instalada.

● En MS Windows: ver la utilidad "charmap". Se debe tener una fuente apropiada instalada.

http://unicode-table.com/en/sections/miscellaneous-symbols/

0 1 2 3 4 5 6 7 8 9 A B C D E F

23

Unicode(no funciona en Windows)

Nota: estos caracteres especiales requiren más de un byte para su almacenamiento

24

Funciones básicas de entrada desde el teclado (stdin)

● Sin formato:– getchar() lee un carácter 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

25

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.

26

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

27

%[*][ancho][longitud]especificador

C99

C99

C99

28

%[*][width][length]specifier

(asteriscos porque la función scanf() espera punteros como argumentos)

29

Observe este comportamiento inesperado!!

30

|

31

int getchar(void);

Lee un caracter desde el teclado (mostrándolo).

A pesar de todo estoy leyendo en un char

32

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

33

char* gets (char* str);

Buffer overflow!!

Dirección char hex0xbfd8935b 1 E 450xbfd8935c 2 j 6A0xbfd8935d 3 e 650xbfd8935e 4 m 6D0xbfd8935f 5 p 70

0xbfd89360 6 l 6C0xbfd89361 7 o 6F0xbfd89362 8 s 730xbfd89363 9 \0 00

7565164 = 0x00736F6C

m.buf

m.i

CodificaciónLittle-endiandel númeroentero m.i

34

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, porque este aún no incorpora los cambios sugeridos en el C11

35

Otro reemplazo de gets(): fgets()

strchr() busca desde la dirección buf hasta que encuentra la primera aparición de un \n. Se retorna dicha dirección de memoria

36

¿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ó

37

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 fgets() 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)● flushinp(); // si está manejando la librería curses.h

38

39

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.htmlhttp://www.pcre.org/

Se podría también utilizar una interface con el comando de consola grep.

40

41

Tomado de: http://xkcd.com/208/

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.

42

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.

43

La librería inttypes.h

Cuando se quieren imprimir (printf())o leer (scanf()) el tipo de números definidos en stdint.h, se deben ajustar las cadenas de texto con los formatos, para que funcionen con estos tipos de datos. inttypes.h se encarga de esto.

Tenga en cuenta que la librería inttypes.h llama automáticamente a stdint.h

44

Los símbolos de printf() y scanf() definidos por inttypes.h

El N en cursiva es 8, 16, 32 o 64 bits

45

Ejemplo con inttypes.h

Desde este punto de vista PRIx8 es un formato que se le agrega a printf() para que este muestre hexadecimales de 8 bits.

Observe que se utilizó implícitamente la concatenación de cadenas.

46

Funciones de salida/entrada de datos básicas <curses.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 amigables.

47Tomada de: http://dmcradio.sourceforge.net/

48

49

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

50

Configuración del PDCURSES en Codeblocks para Windows

51

Configuración del PDCURSES en Codeblocks para Windows

52

Configuración del PDCURSES en Codeblocks para Windows

53

Configuración del PDCURSES en Codeblocks para Windows

54

Configuración del PDCURSES en Codeblocks para Windows

Si le aparece este error copie el archivo libpdcurses.dll en la misma carpeta donde está el archivo .exe de su proyecto.

55

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

56

Tutorial de ncurses.h

● Se sugiere mirar el siguiente tutorial:http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/

● Los siguientes programas están basados en dicho tutorial.

57

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().

ncurses.h en linuxcurses.h en windows -lncurses en linux

-lpdcurses en windows

58

sin tener que dar ENTER

59

60

Colores con ncurses

61

Caracteresespeciales

62

Teclas no alfanuméricas

63

Uso del mouse con ncurses.h

Ver el código:http://programaciondecomputadoresunalmzl.wikispaces.com/file/detail/03_mouse_curses.c

64

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);

65

Programación de juegos

Existen varias librerías especialmente diseñadas para programar juegos. Estas librerías contienen funciones para el manejo de gráficos 2D y 3D, sonidos, joystick, etc. Algunas de las más populares son:

Allegro: http://alleg.sourceforge.net/

ClanLib: http://clanlib.org/wiki/Main_Page

OpenGL: http://www.opengl.org/

SDL: http://www.libsdl.org/

SFML: http://www.sfml-dev.org/

Material basado en:

● http://www.slideshare.net/amraldo/introduction-to-c-programming-7898353

● http://www.slideshare.net/petdance/just-enough-c-for-open-source-programmers

● 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=1043284351

● http://www.tldp.org/HOWTO/NCURSES-Programming-HOWTO/

● Wikipedia