Entrada de datos con fgets()

Iniciado por David8, 2 Abril 2014, 18:23 PM

0 Miembros y 1 Visitante están viendo este tema.

David8

Imaginemos que tenemos un un array como:

   char cadena[10];

Entonces usamos la función fgets para leer una cadena de caracteres como:

   fgets(cadena, 10, stdin);

E introducimos menos de 9 caracteres por lo que automáticamente se nos pone un '\n' al final del array, en la posición cadena[9] en el ejemplo.
Entonces si usamos:

   if(cadena[strlen(cadena)-1] == '\n'{
      cadena[strlen(cadena)-1] = '\0'
   }

obtenemos la cadena sin la impresión de una nueva línea (es decir que el cursor se situa justo después del último caracter.

Lo que no entiendo de todo es es que si introducimos por ejemplo HOLA el array quedaría como:

   H O L A  \0 _ _ _ _ \n

y al usar la anterior instrucción para quitar el '\n' tendríamos:
   
   H O L A  \0 _ _ _ _ \0

¿Cómo es posible tener dos '\0'?

Muchas gracias.

rir3760

El detalle es: los caracteres '\n' y '\0' no se almacenan en las ultimas posiciones del array sino justo después del texto ingresado. Siguiendo tu ejemplo al introducir "Hola" los caracteres en el array son:
0  1  2  3  4  5  6  7  8  9
H  o  l  a \n \0

A continuación strlen te devuelve el numero de caracteres sin contar el '\0', en este caso son cinco y la asignación sobrescribe el carácter '\n' con un '\0' resultando en:
0  1  2  3  4  5  6  7  8  9
H  o  l  a \0 \0

Con ello el primer '\0' marca el final de la cadena.

Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

noele1995

Cita de: David8 en  2 Abril 2014, 18:23 PM
¿Cómo es posible tener dos '\0'?

Un array de tipo char en realidad no es mas que un array de bytes, pero para el uso de cadenas de texto el primer \0 es lo que marca el final de la cadena, no influye en que en otra posicion del array haya otro.

Yoel Alejandro

#3
No es que la cadena posea dos '\0', pues sólo el primero cuenta. Para poner un ejemplo imagínate que tienes:

'h' 'o' 'l' 'a' '\0' '\0' '\0' '\0' '\0'

entonces el primer '\0' encontrado marca el fin de la cadena, que es "hola" y su longitud es 4.

En el ejemplo que dices, si conviertes

'h' 'o' 'l' 'a' '\n' '\0'

en

'h' 'o' 'l' 'a' '\0' '\0'

entonces haces una cadena "más corta", y pasa de tener 5 caracteres a tener 4.

==========================
EDITO

Sólo por comentar, aunque no se si me estoy extendiendo en el tema. El código que propones se puede optimizar eliminando la sobrecarga por llamar dos veces a la función strlen() (aunque un usuario me dijo que los compiladores modernos saben cómo evitar este problema). Una manera es por supuesto depositar el valor de la longitud de la cadena en una variable intermedia:

int len = strlen(cadena);
if(cadena[len-1] == '\n'{
   cadena[len-1] = '\0'
}

O incluso otra forma "autoconstruida", donde no se llama a ninguna función de biblioteca:

for ( i = 0; cadena[i] != '\0'; i++ )
   if ( cadena[i] == '\n' ) cadena[i] = '\0';

o:

char c;
int i = 0;
while ( (c = cadena[i]) != '\n' && c != '\0' )
   i++;
if ( c == '\n' ) cadena[i] = '\0';
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)

David8

Muchas gracias a todos, se resolvió notablemente mi duda  :D