Anuncios

Bienvenidos sean a este post, hoy veremos otra forma de mostrar e ingresar datos.

Anuncios
Anuncios

Si bien hasta ahora hemos visto como mostrar y recibir informacion en nuestra terminal por medio printf y scanf, y sus respectivas derivadas, a los cuales podemos llamar entradas y salidas formateadas, por otro lado las funciones del titulo las podemos denominar como entradas y salidas sin formatear, dado que no necesitan que se le defina el tipo y la forma de como se ingresan o muestran sino que simplemente sera una linea y finalizar con el caracter de nueva lnea <newline>, veamos las siguientes tablas:

Funcion de salidaStream de salida
Consola E/Sputs()stdout
Stream de archivofputs()Archivo/Stream
Anuncios
Funcion de entradaStream de salida
Consola E/Sgets()stdin
Stream de archivofgets()Archivo/Stream
Anuncios
Anuncios

Tanto puts y fputs escriben la linea que recibieron y al final agregan el caracter de nueva linea para terminarlo, en cambio tanto gets como fgets leeran todo lo ingresado hasta encontrar a <eof> o un <newline>, y esto lo almacenara donde corresponda, la principal diferencia entre ambas es que gets no tiene un limite pero fgets nos permite establecer uno y el almacenamiento lo hara llegar al ultimo espacio o salvo que encuentre un <eof> o <newline>, para entender este concepto vamos a crear un ejemplo y para ello crearemos un nuevo archivo con el nombre ejemplo36.c y le agregaremos el siguiente codigo:

ejemplo36.c

#include <stdio.h>

const int tam_array=80;

int main()
{
	char cadena[tam_array];

	printf("Ingresa una cadena: ");
	gets(cadena);
	puts("Has escrito: ");
	puts(cadena);

	return 0;
}
Anuncios

Aqui tenemos un ejemplo simple donde definimos una constante que usaremos para el tamaño de nuestro array de tipo char, en el main primero declaramos este array y luego lo usamos por medio de gets para ingresar informacion, luego por medio de puts mostraremos un texto y lo ingresado en el array, compilemos y veamos como trabaja

tinchicus@dbn001vrt:~/lenguajes/C$ gcc fuente/ejemplo36.c -o prog/ejemplo36 
fuente/ejemplo36.c: In function ‘main’:
fuente/ejemplo36.c:10:2: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
   10 |  gets(cadena);
      |  ^~~~
      |  fgets
/usr/bin/ld: /tmp/cchhb5RW.o: en la función `main':
ejemplo36.c:(.text+0x8d): aviso: the `gets' function is dangerous and should not be used.
tinchicus@dbn001vrt:~/lenguajes/C$
Anuncios

Ups, que paso? un inconveniente que mencionamos pero no tomamos dimension, la funcion gets no tiene limite por lo tanto podriamos ingresar demasada informacion la cual podria sobrepasar el tamaño que tiene reservado el stream, esto puede generar como minimo que el programa de una excepcion y se termine pero en el peor de los casos podemos crear nna vulnerabilidad en el S.O y a partir de ahi se puede ingresar codigo malicioso y tener serios problemas, por esta razon no se puede utilizar, para ello debemos modificar el codigo de la siguiente manera:

ejemplo36.c

#include <stdio.h>

const int tam_array=255;

int main()
{
	char cadena[tam_array];

	printf("Ingresa una cadena: ");
	fgets(cadena, tam_array, stdin);
	puts("Has escrito: ");
	puts(cadena);

	return 0;
}
Anuncios

Observen que la unica diferencia es que sacamos el gets y agregamos un fgets, esto es principalmennte asi porque fgets al tener un limite de caracteres se convierte en mas segura que gets, el resto sigue siendo el mismo codigo, compilemos y veamos como trabaja mediante el siguiente video

Anuncios

Como pueden ver ahora si funciono nuestro codigo, observen el detalle del puts, automaticamente nos agrego el caracter de nueva linea por lo tanto cada linea quedo en su respectivo renglon a diferencia del printf, antes de continuar vamos a ver como es la sintaxis de fgets:

fgets(array_char, limite, stream)
Anuncios

El primero sera la variable que almacenara nuesstra cadena, luego tenemos el valor que establece el limite o la cantidad de caracteres que podemos ingresar y por ultimo tenemos el stream que utilizaremos, veamos el utilizdo en el codigo:

fgets(cadena, tam_array, stdin);
Anuncios

Ahora vamos a hacer un codigo un poco mas complejo para poder implementar a fgets y fputs juntos y poder hacer la diferencia con los anteriores, en este caso tomaremos el codigo anterior y lo modificaremos de la siguiente manera:

ejemplo36.c

#include <stdio.h>

#include <string.h>
#include <stdbool.h>
#define cadena_max 80

const int max_lista = 100;

typedef char cadena[ cadena_max ];

void agregarNombre(cadena *nombre, cadena nuevo, int *tamLista);
void mostrarNombres(cadena *nombre, int tamLista);

void removerNuevaLinea(cadena c)
{
	int largo=strlen(c);
	c[largo-1]='\0';
}

int main(void)
{
	cadena nuevoNombre;
	cadena lista_nombres[max_lista];
	int numNombres = 0;

	while(printf("Nombre %d: ", numNombres + 1),
		fgets(nuevoNombre, cadena_max, stdin),
		removerNuevaLinea(nuevoNombre),
		strlen(nuevoNombre) > 0)
	{
		agregarNombre(lista_nombres, nuevoNombre, &numNombres);
	}

	mostrarNombres(lista_nombres, numNombres);
}
Anuncios
Anuncios

Este va a ser un codigo mas complejo pero mas divertido de trabajar, primero utilizaremos tres librerias conocidas que en un momento veremos cuales son las herramientas que usaremos de ellas, despues definimos una variable por medio de define, en este caso para limitar el maximo de una cadena (string), si se preguntan porque lo hicimos asi y no por medio de const, la respuesta es simple porque const no es una constante de verdad, en cambio define si y cuando la usemos veremos porque, despues definimos una variable para establecer el maximo de nombres de una lista, ahora viene el qui de la cuestion, usamos un typedef para crear un alias de char llamado cadena y le estableceremos un limite para almacenar mas de un caracter, y aqui implementamos la constante de define, esto debemos hacerlo asi porque de lo contrario nos devolvera un error, como es el siguiente:

error: variably modified ‘cadena’ at file scope
Anuncios
Anuncios

Esta es la razon por la que tuvimos que definirla de esta manera, despues tenemos el prototipo de dos funciones, la primera sera para agregar nombres y la segunda para mostrar todos los almacenados, despues tenemos una funcion para remover la nueva linea, ya veremos porque, en ella tomaremos la longitud de la cadena pasada como argumento y en ella retrocederemos un casillero y le agregaremos el caracter que representa el final de la linea, esto es para eliminar el caaracter de nueva linea que se agrega automaticamente por medio de fgets, ya veremos porque, despues tenemos el main donde definiremos dos variables del alias que definimos anteriormente, la primera sera para cada nuevo nombre que agreguemos y la segunda almacenara cada uno de los nombres que agreguemos, despues tenemos una variable para almacenar la cantidad de nombres que vayamos agregando, despues tenemos un while donde haremos varias cosas en el condicional, primero usamos un printf para mostrar cual es nombre que estamos ingresando, despues usamos un fgets donde almacenaremos el nombre que ingresemos, tal como vimos en el ejemplo anterior, luego llamaremos a removerNuevaLinea simplemente y le pasamos el nombre que ingresamos simplemente para hacer lo que comentamos annteriormente.

Anuncios

Por ultimo verificamos que el nombre ingresado sea mayor a cero, y este sera el verdadero condicional que se encarga de repetir el bucle, es decir mientras haya al menos un caracter seguira haciendo el loop, y dentro del bloque agregaremos un nuevo nombre, observen que pasamos el listado de nombres, el nuevo nombre y la cantidad que tenemos cargadas, por ultimo una vez que salgamos del bucle llamaremos a la funcion para mostrar los nombres, observen que le pasamo el listado y la cantidad, hasta aqui el codigo que tenemos pero aun no funciona porque no definimos los prototipos, pasemos a agregar el siguiente bloque de codigo despues del main:

void agregarNombre(cadena *nombres, cadena nuevo, int *aNumEntradas)
{
	if (*aNumEntradas >= max_lista)
	{
		puts("Lista completa!");
		return;
	} else {
		int k = 0;
		bool estuvo = false;

		while(!estuvo && k < *aNumEntradas)
			estuvo=(strcmp(nuevo, nombres[ k++ ]) < 0);

		if (estuvo)
		{
			k--;
			for(int j=*aNumEntradas; j > k; j--)
			{
				strcpy(nombres[j], nombres[j-1]);
			}
		}
		strcpy(nombres[k], nuevo);
		(*aNumEntradas)++;
	}
	return;
}
Anuncios
Anuncios

Como dijimos recibe tres argumentos, el primero es el listado de nombres, luego el nombre que debemos agregar y por ultimo la cantidad de nombres cargados, lo primero que tenemos es un condicional donde verifica que los nombres cargados sean mayor o igual al limite de la lista (max_lista) y en caso de ser verdadero nos muestra un mensaje que la lista esta completa y salimos de la funcion, de lo contrario define una nueva variable con un valor inicial, despues definimos una variable llamado estuvo de tipo bool con un valor inicial de false, lo siguiente sera un bucle while donde verificamos que estuvo es distinto de false y la variable k sea menor a las entradas ingresadas, en el bloque tenemos a la variable estuvo donde usamos strcmp (de la libreria string.h) donde compararemos al nuevo nombre ingresado con los ya existentes y en caso de que este sea menor a cero almacenara un true, despues tenemos un condicional donde si estuvo es true procede a restar la variable en uno, despues por medio de un bucle for haremos una cuenta regresiva, ya que no comenzaremos desde cero como hacemos habitualmente sino del total de nombres ingresados, esto lo haremos mientras j sea mayor a k e iremos restando unu valor a j, observen que usamos a strcpy donde la posicion de j le copiaremos el valor de la posicion anterior.

Anuncios

Una vez que salimos del bucle el valor de k lo usaremos de posicion y le copiaremos el valor con el nuevo nombre para finalmente incrementar el total de entradas, para finalmente salir de la funcion, nuestro siguiente paso sera agregar el siguiente bloque de codigo para definir al otro prototipo:

void mostrarNombres(cadena *nombres, int numEntradas)
{
	printf("\nNumero de entradas: %d\n\n", numEntradas);
	for(int i=0; i < numEntradas; i++)
	{
		fputs(nombres[i], stdout);
		fputc('\n', stdout);
	}
}
Anuncios

En este caso tomaremos la lista de nombres y el total de entradas que pasaremos como argumentos, despues en el bloque mostraremos cuantos nombres fueron ingresados, y despues or medio de un bucle for pasaremos por toda la lista, observen que al fputs le debimos agregar la funcion fputc para que pase a la nueva linea, fputc es similar a las anteriores pero en lugar de usar cadenas (string) lo hace con un caracter, con todo esto comentado veamos como quedo nuestro codigo final:

ejemplo36.c

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define cadena_max 80

const int max_lista = 100;

typedef char cadena[ cadena_max ];

void agregarNombre(cadena *nombre, cadena nuevo, int *tamLista);
void mostrarNombres(cadena *nombre, int tamLista);

void removerNuevaLinea(cadena c)
{
	int largo=strlen(c);
	c[largo-1]='\0';
}

int main(void)
{
	cadena nuevoNombre;
	cadena lista_nombres[max_lista];
	int numNombres = 0;

	while(printf("Nombre %d: ", numNombres + 1),
		fgets(nuevoNombre, cadena_max, stdin),
		removerNuevaLinea(nuevoNombre),
		strlen(nuevoNombre) > 0)
	{
		agregarNombre(lista_nombres, nuevoNombre, &numNombres);
	}

	mostrarNombres(lista_nombres, numNombres);
}

void agregarNombre(cadena *nombres, cadena nuevo, int *aNumEntradas)
{
	if (*aNumEntradas >= max_lista)
	{
		puts("Lista completa!");
		return;
	} else {
		int k = 0;
		bool estuvo = false;

		while(!estuvo && k < *aNumEntradas)
			estuvo=(strcmp(nuevo, nombres[ k++ ]) < 0);

		if (estuvo)
		{
			k--;
			for(int j=*aNumEntradas; j > k; j--)
			{
				strcpy(nombres[j], nombres[j-1]);
			}
		}
		strcpy(nombres[k], nuevo);
		(*aNumEntradas)++;
	}
	return;
}

void mostrarNombres(cadena *nombres, int numEntradas)
{
	printf("\nNumero de entradas: %d\n\n", numEntradas);
	for(int i=0; i < numEntradas; i++)
	{
		fputs(nombres[i], stdout);
		fputc('\n', stdout);
	}
}
Anuncios

Con nuestro codigo final y ya todo comentado pasemos a ver como trabaja mediante el siguiente video

Anuncios

Para ir finalizando veamos las sintaxis de cada uno de las funciones de entrada y salida sin formateo y validos:

puts(array_char);
Anuncios
fgets(array_char, limite, stream)
Anuncios
fputs(array_char, stream)
Anuncios

En resumen, hoy hemos visto como trabajar con funciones de entrada y salida sin formateo, gets y puts, porque se considera perligrosa a gets y se inhabilito, despues vimos como trabajar primero fgets y puts para luego hacer un ejemplo mas complejo y poder trabajar con fgets y fputs, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50