|
|
![]()
Vamos ahora a ver c�mo manejar texto con C. Para empezar, es preciso decir que existe un tipo string como en otros lenguajes, pero no existe un tipo de datos espec�fico para almacenar texto, sino que se utilizan arrays de char. Funcionan igual que los dem�s arrays con la diferencia de que ahora se manejan letras en vez de n�meros. Se les llama cadenas, strings o tiras de caracteres y a partir de ahora les llamaremos cadenas.
Para declarar una cadena se hace como en el caso de un array. Por ejemplo, si queremos declarar una cadena de longitud 20 caracteres se har�a:
char texto[20];
Al igual que en los arrays, no podemos entonces introducir m�s de 20 elementos en la cadena. Vamos a ver un ejemplo para mostrar el nombre del usuario en pantalla:
#include <stdio.h>
main()
{
char nombre[20];
printf( "Introduzca su nombre (20 letras m�ximo): " );
scanf( "%s", nombre );
printf( "\nEl nombre que ha escrito es: %s\n", nombre );
}
|
Obs�rvese que en la sentencia scanf no se usa el s�mbolo & delante de nombre. No hace falta porque se trata de un array, de modo que escribir el nombre del array es equivalente a poner &nombre[0].
Tambi�n puede llamar la atenci�n sobre la forma de imprimir el array. Con s�lo usar %s ya se imprime su totalidad. Ya veremos esto m�s adelante.
Por si alguien est� acostumbrado a programar en otro lenguaje es preciso hacer notar que en C no se puede hacer esto:
#include <stdio.h>
main()
{
char texto[20];
texto = "Hola";
}
|
Es interesante saber c�mo funciona una cadena por dentro, por eso vamos a ver primero c�mo se inicializa:
#include <stdio.h>
main()
{
char nombre[] = "Gandalf";
printf( "Texto: %s\n", nombre );
printf( "Tama�o de la cadena: %i bytes\n", sizeof nombre );
}
|
Resultado al ejecutar:
Texto: Gandalf Tama�o de la cadena: 8 bytes |
Curiosamente la respuesta nos dice que "Gandalf" ocupa 8 bytes. Como cada elemento char ocupa un byte eso quiere decir que la cadena tiene 8 elementos, a pesar de que "Gandalf" s�lo cuenta con 7 letras. La raz�n de esta aparente paradoja estriba en que la cadena tiene como car�cter final el s�mbolo '\0', cuyo significado es "fin de cadena". De esta forma, cuando queremos escribir la cadena basta con usar %s y el compilador sabe cu�ntos elementos debe escribir: hasta que encuentre '\0'.
El programa anterior ser�a equivalente a:
#include <stdio.h>
main()
{
char nombre[] = { 'G', 'a', 'n', 'd', 'a', 'l', 'f', '\0' };
printf( "Texto: %s\n", nombre );
printf( "Tama�o de la cadena: %i bytes\n", sizeof nombre );
}
|
Aqu� ya se observa claramente que nombre tiene 8 elementos. Pero, �qu� pasar�a si no pusi�ramos '\0' al final?
#include <stdio.h>
main()
{
char nombre[] = { 'G', 'a', 'n', 'd', 'a', 'l', 'f' };
printf( "Texto: %s\n", nombre );
printf( "Tama�o de la cadena: %i bytes\n", sizeof nombre );
}
|
En mi ordenador se obtiene:
Texto: Gandalf- Tama�o de la cadena: 7 bytes |
Pero en otro despu�s de "Gandalf" puede aparecer cualquier cosa. Lo que aqu� sucede es que printf no encuentra el s�mbolo '\0' y no sabe cu�ndo dejar de imprimir. Afortunadamente, cuando introducimos una cadena se hace de la primera forma y el C se encarga de poner el s�mbolo al final.
Es importante no olvidar que la longitud de una cadena es la longitud del texto m�s el s�mbolo de fin de cadena. Por eso cuando definamos una cadena tenemos que reservarle un espacio adicional. Por ejemplo:
char nombre[8] = "Gandalf";
Existen unas cuantas funciones el la biblioteca est�ndar de C para el manejo de cadenas:
Para usar estas funciones en nuestro programa hay que a�adir la directiva:
#include <string.h> |
strlen |
size_t *strlen(const char *cadena);
Esta funci�n devuelve el n�mero de caracteres que tiene la cadena (sin contar el '\0').
#include <stdio.h>
#include <string.h>
main()
{
char texto[]="Gandalf";
int longitud;
longitud = strlen(texto); printf( "La cadena \"%s\" tiene %i caracteres.\n", texto, longitud ); } |
Como ejemplo, vamos a ver c�mo se programar�a esta funci�n si no dispusi�ramos de ella. Hay m�s informaci�n en Recorrido de cadenas con punteros.
#include <stdio.h>
#include <string.h>
main()
{
char texto[]="Gandalf";
char *p;
int longitud=0;
p = texto;
while (*p != '\0') {
longitud++;
printf( "%c\n", *p ); /* Mostramos la letra actual */
p++; /* Vamos a la siguiente letra */
}
printf( "La cadena \"%s\" tiene %i caracteres.\n", texto, longitud );
}
|
Para medir la longitud de la cadena usamos un puntero para recorrerla (el puntero p). Hacemos que p apunte a texto. Luego entramos en un bucle while. La condici�n del bucle comprueba si se ha llegado al fin de cadena ('\0'). Si no es as�, suma 1 a longitud, muestra la letra por pantalla e incrementa el puntero en 1 (con lo que pasamos a la siguiente letra).
strcpy |
char *strcpy(char *cadena1, const char *cadena2);
Copia el contenido de cadena2 en cadena1. cadena2 puede ser una variable o una cadena directa (por ejemplo, "hola"). Debemos tener cuidado de que la cadena destino (cadena1) tenga espacio suficiente para albergar a la cadena origen (cadena2).
#include <stdio.h>
#include <string.h>
main()
{
char texto[] = "�ste es un curso de C.";
char destino[50];
strcpy( destino, texto );
printf( "Valor final: %s\n", destino );
}
|
Vamos a ver otro ejemplo en el que la cadena destino es una cadena constante ("�ste es un curso de C.") y no una variable. Adem�s, en este ejemplo vemos que la cadena origen es sustituida por la cadena destino totalmente. Si la cadena origen es m�s larga que la destino, se eliminan las letras adicionales.
#include <stdio.h>
#include <string.h>
main()
{
char destino[50]="�ste no es un curso de HTML, sino de C.";
printf( "%s\n", destino );
strcpy( destino, "�ste es un curso de C." );
printf( "%s\n", destino );
}
|
strcat |
char *strcat(char *cadena1, const char *cadena2);
A�ade la cadena2 al final de la cadena1 (concatena).
#include <stdio.h>
#include <string.h>
main()
{
char nombre_completo[50];
char nombre[]="Gandalf";
char apellido[]="el Gris";
strcpy( nombre_completo, nombre );
strcat( nombre_completo, " " );
strcat( nombre_completo, apellido );
printf( "El nombre completo es: %s.\n", nombre_completo );
}
|
Como siempre, tenemos asegurar que la variable en la que a�adimos las dem�s cadenas tenga el tama�o suficiente. Con la primera l�nea de este programa introducimos el nombre en nombre_completo. Usamos strcpy para asegurarnos de que queda borrado cualquier dato anterior. Luego usamos un strcat para a�adir un espacio y, finalmente, introducimos el apellido.
sprintf |
int sprintf(char *destino, const char *format, ...);
Funciona de manera similar a printf pero, en vez de mostrar el texto en la pantalla, lo guarda en una variable (destino). El valor que devuelve (int) es el n�mero de caracteres guardados en la variable destino.
Con sprintf podemos repetir el ejemplo de strcat de manera m�s sencilla:
#include <stdio.h>
#include <string.h>
main()
{
char nombre_completo[50];
char nombre[]="Gandalf";
char apellido[]="el Gris";
sprintf( nombre_completo, "%s %s", nombre, apellido );
printf( "El nombre completo es: %s.\n", nombre_completo );
}
|
Se puede aplicar a sprintf todo lo indicado para printf.
strcmp |
int strcmp(const char *cadena1, const char *cadena2);
Compara cadena1 y cadena2. Si son iguales, devuelve 0. Un n�mero negativo si cadena1 "va" antes que cadena2, y un n�mero positivo si es al contrario:
- < 0 si cadena1 < cadena2
- ==0 si cadena1 == cadena2
- > 0 si cadena1 > cadena2
#include <stdio.h>
#include <string.h>
main()
{
char nombre1[]="Gandalf";
char nombre2[]="Frodo";
printf( "Comparaci�n con strcmp: %i\n", strcmp(nombre1,nombre2));
}
|
El resultado es:
Comparaci�n con strcmp : 1 |
Un array de cadenas puede servirnos para agrupar una serie de mensajes. Por ejemplo, todos los mensajes de error de un programa. Luego, para acceder a cada mensaje, basta con usar su n�mero.
#include <stdio.h>
#include <string.h>
int error( int num_err )
{
char *errores[] = {
"No se ha producido ning�n error",
"No hay suficiente memoria",
"No hay espacio en disco",
"Me he cansado de trabajar"
};
printf( "Error n�mero %i: %s.\n", num_err, errores[num_err] );
exit( -1 );
}
main()
{
error( 2 );
}
|
El resultado ser�:
Error n�mero 2: No hay espacio en disco. |
Un array de cadenas es en realidad un array de punteros a cadenas. El primer elemento de la cadena ("No se ha producido ning�n error") tiene un espacio reservado en memoria y errores[0] apunta a ese espacio.
Vamos a ver un sencillo ejemplo de ordenaci�n de cadenas. En el ejemplo siguiente tenemos que ordenar una serie de dichos populares:
#include <stdio.h>
#include <string.h>
#define ELEMENTOS 5
main()
{
char *dichos[ELEMENTOS] = {
"La avaricia rompe el saco",
"M�s vale p�jaro en mano que ciento volando",
"No por mucho madrugar amanece m�s temprano",
"A�o de nieves, a�o de bienes",
"A caballo regalado no le mires el diente"
};
char *temp;
int i, j;
printf( "Lista desordenada:\n" );
for( i=0; i<ELEMENTOS; i++ )
printf( " %s.\n", dichos[i] );
for( i=0; i<ELEMENTOS-1; i++ )
for( j=i+1; j<ELEMENTOS; j++ )
if ( strcmp(dichos[i], dichos[j]) > 0 ) {
temp = dichos[i];
dichos[i] = dichos[j];
dichos[j] = temp;
}
printf( "Lista ordenada:\n" );
for( i=0; i<ELEMENTOS; i++ )
printf( " %s.\n", dichos[i] );
}
|
C�mo funciona el programa:
Para ver con mayor claridad el resultado a partir del desarrollo del proceso, se va a sustituir cada cadena por su primera letra (menos la de "A�o de nieves..." que se sustituir� por A�). As�, el proceso queda:
0 1 2 3 3' 4 4' 5 6 6' 7 7' 8 8' 9 9' 10 10' 1 L L L L A� A� A 2 M M M M M M M M M L L A� 3 N N N N N N N N N N N N N M M L 4 A� A� A� A� L L L L L M M M M N N N N M 5 A A A A A A A� A� A� A� A� L L L L M M N
Las cadenas se pueden recorrer de igual forma que se hace con los arrays, usando punteros. Vamos a ver un ejemplo: el siguiente sencillo programa cuenta los espacios y las letras e (min�sculas) que hay en una cadena.
#include <stdio.h>
#include <string.h>
main()
{
char cadena[]="El puerto paralelo del PC";
char *p;
int espacios = 0, letras_e = 0;
p = cadena;
while (*p != '\0') {
if (*p == ' ') espacios++;
if (*p == 'e') letras_e++;
p++;
}
printf( "En la cadena \"%s\" hay:\n", cadena );
printf( " %i espacios\n", espacios );
printf( " %i letras e\n", letras_e );
}
|
El resultado es:
En la cadena "El puerto paralelo del PC" hay: 4 espacios 3 letras e |
Para recorrer la cadena necesitamos un puntero p que sea de tipo char. Debemos hacer que p apunte a la cadena (p=cadena). As�, p apunta a la direcci�n del primer elemento de la misma. El valor de *p ser�a, por tanto, 'E'. Comenzamos el bucle. La condici�n comprueba que no se ha llegado al final de la cadena (*p != '\0'). Entonces se comprueba si en la direcci�n a la que apunta p hay un espacio o una letra e. Si es as�, se incrementan las variables correspondientes. Una vez comprobado esto se pasa a la siguiente letra (p++).
En este otro ejemplo substituimos los espacios por guiones:
#include <stdio.h>
#include <string.h>
main()
{
char cadena[]="El puerto paralelo del PC";
char *p;
p = cadena;
while (*p != '\0') {
if (*p == ' ') *p = '-';
p++;
}
printf( "La cadena queda: \"%s\" \n", cadena );
}
|
y se obtiene:
La cadena queda: "El-puerto-paralelo-del-PC" |