Una cadena de caracteres es una secuencia de caracteres que termina con un carácter especial, que indica el final de la cadena, llamado carácter fin de cadena o carácter nulo. Se utilizan en C para almacenar y manipular texto.
El
carácter fin de cadena tiene el código ASCII 0 (es el
primero de la tabla ASCII) y se representa por ‘\0’
.
Las
cadenas de caracteres se representan en C como un texto delimitado
por comillas dobles (“
).
Ejemplo:
“Cadena ejemplo”
Aunque el carácter fin de cadena no aparece entre las comillas, está presente al final de la cadena. Internamente la cadena anterior tiene 15 caracteres (los 14 caracteres visibles más el carácter fin de cadena):
C |
a |
d |
e |
n |
a |
|
e |
j |
e |
m |
p |
l |
o |
\0 |
Cuestión 1: ¿Cuántos
caracteres tiene una cadena vacía: “”
?
Las
cadenas de caracteres se almacenan en vectores de caracteres (arrays
unidimensionales de tipo char
).
Ejemplos de inicialización de cadenas de caracteres:
En el siguiente ejemplo se declara un vector
de caracteres y se inicializa con la cadena de caracteres “hola”
:
char texto[] = “hola”;
La variable texto
tiene una longitud de 5 caracteres:
|
|
|
|
|
h |
o |
l |
a |
\0 |
También podemos inicializar un vector de caracteres especificando todos los caracteres individualmente, en este caso es necesario escribir explícitamente el carácter fin de cadena:
char texto[] = {‘h’, ‘o’, ‘l’, ‘a’, ‘\0’};
En el siguiente ejemplo se inicializa un vector de 14 caracteres con una cadena de menor tamaño:
char texto[14] = “hola”;
Los 5 primeros elementos de la variable texto
se han inicializado con la cadena “hola”
,
el resto de elementos permanece sin inicializar. Puesto que el
carácter fin de cadena ocupa un elemento del vector, la
variable texto
puede contener como máximo cadenas de 13 caracteres más
el carácter fin de cadena.
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
También podemos inicializar un
puntero a char
con una cadena de caracteres:
char *p = "Cosa";
La variable p
apunta al primer carácter de la cadena “Cosa”
.
Arrays de cadenas de caracteres: Podemos definir los arrays de cadenas de caracteres de dos formas distintas:
Como una matriz
de caracteres (array bidimensional de tipo char
)
en la que cada fila contiene una cadena diferente. Por ejemplo:
char cadenas[5][19] = { "Sumo con precisión", "Almaceno datos", "Dibujo gráficos", "Ejecuto programas", "Domino el C" };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
S |
u |
m |
o |
|
c |
o |
n |
|
p |
r |
e |
c |
i |
s |
i |
o |
n |
\0 |
|
A |
l |
m |
a |
c |
e |
n |
o |
|
d |
a |
t |
o |
s |
\0 |
|
|
|
|
|
D |
i |
b |
u |
j |
o |
|
g |
r |
a |
f |
i |
c |
o |
s |
\0 |
|
|
|
|
E |
j |
e |
c |
u |
t |
o |
|
p |
r |
o |
g |
r |
a |
m |
a |
s |
\0 |
|
|
D |
o |
m |
i |
n |
o |
|
e |
l |
|
C |
\0 |
|
|
|
|
|
|
|
Podemos acceder a las cadenas del array utilizando el índice de filas. Por ejemplo, para acceder a la tercera cadena se utiliza la siguiente expresión:
cadenas[2]
Como un vector de punteros a caracteres en el que cada elemento es un puntero que apunta al inicio de una cadena diferente. Por ejemplo:
char *cadenas[5] = { "Sumo con precisión", "Almaceno datos", "Dibujo gráficos", "Ejecuto programas", "Domino el C" };
Podemos acceder a las cadenas del array utilizando el índice del vector. Por ejemplo, para acceder a la primera cadena se utiliza la siguiente expresión:
cadenas[0]
Están
definidas en la biblioteca de Entrada/Salida estándar stdio
y sus prototipos se encuentran en el fichero de encabezamiento
“stdio.h”
:
#include <stdio.h>
Salida o escritura de cadenas de caracteres:
Estudiaremos dos
funciones para la escritura de cadenas de caracteres por salida
estándar: printf
y puts
La función
printf
permite
escribir una cadena de caracteres mediante el especificador
de formato %s
.
#include <stdio.h> int main() { char nombre[20] = "Juan"; char saludo[20] = "Buenas tardes"; printf( "%s %s, hoy es tu %s.\n", saludo, nombre, "santo" ); system(“pause”); return 0; }
La función
puts
:
int puts( char *cadena );
Escribe el contenido del parámetro cadena
por la salida estándar seguido de un salto de línea.
#include <stdio.h> int main() { char mensaje[] = "Hola mundo"; puts( mensaje ); puts( "Hasta luego mundo" ); system( “pause” ); return 0; }
Entrada o lectura de cadenas de caracteres:
Estudiaremos dos
funciones para leer cadenas de caracteres de la entrada estándar:
gets
y scanf
La función
scanf
permite
leer una palabra (una secuencia de caracteres delimitada por
separadores) mediante el especificador
de formato %s
.
Ejemplo 5.3: Ejecuta el siguiente programa y prueba a teclear tu nombre completo, incluyendo los apellidos.
#include <stdio.h> int main() { char nombre[15]; /* Reservamos espacio para una cadena de 14 caracteres + el caracter nulo */ printf( "Escribe tu nombre: " ); scanf( "%s", nombre ); /* Leemos el nombre */ printf( "Hola %s.\n", nombre ); /* Escribimos la cadena */ system( “pause” ); return 0; }
La función
gets
:
char *gets( char *cadena );
Lee una cadena de caracteres de la entrada estándar del
sistema y la almacena en el parámetro cadena
.
Esta función lee caracteres hasta que encuentra un salto de
línea (‘\n’
)
y los almacena todos en la cadena excepto el propio salto de línea.
La
función gets
devuelve la dirección de la cadena que se le pasa como
parámetro si no hay errores, o NULL
en caso contrario.
Ejemplo 5.4: Ejecuta el siguiente programa y prueba a teclear tu nombre completo, incluyendo los apellidos. Compara el resultado obtenido con el del Ejemplo-5.3.
#include <stdio.h> int main() { char nombre[80] ; /* Reservamos espacio para cadena de 79 caracteres + el caracter nulo */ printf( "Escribe tu nombre: " ); gets( nombre ); /* Leemos una linea de texto */ printf( "Hola %s.\n", nombre ); /* Escribimos la cadena */ system( “pause” ); return 0; }
Los
prototipos de las funciones de la biblioteca string se
encuentran en el fichero de encabezamiento “string.h”
#include <string.h>
Longitud de una cadena:
unsigned int strlen( char *cad );
Devuelve la
longitud de la cadena de caracteres que se le pasa como parámetro,
excluyendo el carácter de fin de cadena (carácter
nulo '\0'
).
Ejemplo 5.5: Compila y ejecuta el siguiente programa.
#include <stdio.h> #include <string.h> int main() { char palabra[20]; printf( "Teclea una palabra: " ); scanf( "%s", palabra ); printf( "La longitud de %s es %u\n", palabra, strlen( palabra ) ); system( “pause” ); return 0; }
Copia de cadenas:
char *strcpy( char *destino, char *fuente );
La función
strcpy
copia
el contenido de fuente
en destino
(ambos parámetros son cadenas de caracteres).
El parámetro
destino
debe
tener espacio suficiente para almacenar la cadena fuente.
Ejemplo
5.6: Escribe una función llamada dia_semana
que calcule el día de la semana a partir de un valor
comprendido entre 1 y 7, donde el valor 1 corresponde al lunes y el
7 al domingo. La función recibe dos parámetros: un
valor de tipo entero sin signo y un vector de caracteres donde
almacenará el nombre del día de la semana. Si el
valor recibido no está comprendido entre 1 y 7, la función
almacenará la cadena “Dia
incorrecto”
en el vector de caracteres.
#include <string.h> void dia_semana( unsigned int dia, char nombre[] ) { char *nombre_dias[] = { "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado", "Domingo" }; if (dia >= 1 && dia <= 7) strcpy( nombre, nombre_dias[dia-1] ); else strcpy( nombre, "Dia incorrecto" ); }
int main() { char fecha[30]; dia_semana( 3, fecha ); printf( "El dia 3 es: %s\n", fecha ); dia_semana( 9, fecha ); printf( "El dia 9 es: %s\n", fecha ); system( “pause” ); return 0; }
Ejercicio: Escribe una función
llamada nombre_mes
que calcule el nombre del mes a partir de un valor entero
comprendido entre 1 y 12. El prototipo de la función es el
siguiente:
void nombre_mes( unsigned int mes, char merror[], char nombre[] );
La función debe almacenar en el parámetro nombre
el nombre del mes correspondiente al valor mes
.
En caso de que el valor de mes
sea incorrecto, la función debe copiar el contenido del
parámetro merror
en el parámetro nombre
.
Para probar tu función, utiliza la siguiente
función main
y prueba a introducir valores correctos e incorrectos cuando ejecutes
el programa:
int main() { char mes[30]; unsigned m; printf( “Escribe el número de mes: “ ); scanf( “%u”, &m ); nombre_mes( m, “Número incorrecto”, mes ); printf( “El mes %u es %s\n”, m, mes ); system( “pause” ); return 0; }
Concatenación de cadenas:
char *strcat( char *destino, char *fuente );
La función
strcat
concatena la cadena fuente con la cadena destino, es decir, copia
la cadena fuente al final de la cadena destino. Por ejemplo, en el
siguiente programa, la variable resultado
contiene inicialmente la cadena “otorrino”
;
sin embargo, después de ejecutar la función strcat
,
dicha variable contendrá la cadena “otorrinolaringólogo”
,
que se mostrará en la pantalla:
int main() { char resultado[80] = “otorrino”; strcat( resultado, “laringólogo” ); printf( “%s\n”, resultado ); }
El parámetro
destino
debe
tener espacio suficiente para almacenar la concatenación de
ambas cadenas.
Ejemplo
5.7: En Windows, la ubicación y el nombre de los
archivos se especifican mediante la unidad, la ruta de acceso, el
nombre y la extensión. Por ejemplo, el archivo
“d:\documentos\cartas\bienvenida.doc”
se encuentra en la unidad “d:”
,
en la ruta de acceso “\documentos\cartas”
,
su nombre es “bienvenida”
y su extensión “doc”
.
Escribe un programa que pida por teclado la unidad y el nombre base
de un archivo, y que le añada la ruta de acceso
“\Mis imagenes\”
y la extensión “.jpg”
.
El resultado debe imprimirse en pantalla y guardarse en una cadena
de caracteres. Debes tener en cuenta que, en C, el carácter
‘\’
se representa como una barra doble ‘\\’
.
#include <stdio.h> #include <string.h> #define MAX_LONG 100 int main() { char unidad[10]; char nombre[30]; char nombre_completo[MAX_LONG]; printf( "Escriba la letra de la unidad: " ); scanf( "%s", unidad ); printf( "Escriba el nombre del fichero: " ); scanf( "%s", nombre ); if (strlen(unidad) + strlen(nombre) + strlen(":\\Mis imagenes\\") + strlen(".jpg") + 1 <= MAX_LONG) { strcpy( nombre_completo, unidad ); strcat( nombre_completo, ":\\Mis imagenes\\" ); strcat( nombre_completo, nombre ); strcat( nombre_completo, ".jpg" ); printf( "El nombre completo es \"%s\"\n", nombre_completo ); }else puts( "No hay espacio suficiente." ); system( “pause” ); return 0; }
Ejercicio:
Escribe una función llamada genera_nombre
que, a partir de los dos apellidos y el nombre de una persona,
calcule el nombre completo con el siguiente formato: “apellido1
apellido2, nombre”
. La
función recibe tres parámetros de tipo cadena de
caracteres que contienen el nombre, el primer apellido y el segundo
apellido respectivamente. El resultado lo almacena en un cuarto
parámetro de tipo cadena de caracteres que tendrá una
lóngitud de 100 caracteres. Utiliza la siguiente
función main
para comprobar que tu función es correcta:
int main() { char nombre_completo[100]; genera_nombre( “Juan”, “Fuentes”, “Soleadas”, nombre_completo ); printf( “%s\n”, nombre_completo ); system( “pause” ); return 0; }
int strcmp( char *cad1, char *cad2 );
La función
strcmp
compara
alfabéticamente las dos cadenas que se le pasan como
parámetros. Devuelve un valor numérico que nos indica
el resultado de la comparación según la siguiente
tabla:
Valor devuelto |
Significado |
Menor que 0 |
cad1 es anterior que cad2 |
0 |
cad1 es igual que cad2 |
Mayor que 0 |
cad1 es posterior que cad2 |
Ejemplo 5.8: Escribe un programa que lea del teclado una palabra y muestre un mensaje por pantalla indicando si dicha palabra es anterior, igual o posterior que la palabra “universo”.
#include <string.h> int main() { char cad[80]; printf( "Escribe una palabra: " ); scanf( "%s", cad ); if (strcmp( cad, "universo" ) == 0) printf( "La palabra es \"universo\".\n" ); else if (strcmp( cad, "universo" ) < 0) printf( "La palabra %s es anterior que \"universo\".\n", cad ); else if (strcmp( cad, "universo" ) > 0) printf( "La palabra %s es posterior que \"universo\".\n", cad ); /* Nota: La última sentencia "if" no es necesaria puesto que llegados a ese punto ya sabemos que "strcmp" devuelve un valor mayor que cero. Se ha añadido simplemente para ilustrar el uso de strcmp. La forma más apropiada de escribir dichas sentencias "if" anidadas es la siguiente: if (strcmp( cad, "universo" ) == 0) printf( "La palabra es \"universo\".\n" ); else if (strcmp( cad, "universo" ) < 0) printf( "La palabra %s es anterior que \"universo\".\n", cad ); else printf( "La palabra %s es posterior que \"universo\".\n", cad ); */ system( “pause” ); return 0; }
Ejercicio: Escribe un programa que solicite por teclado dos cadenas de caracteres y las muestre por pantalla ordenadas alfabéticamente.
Recorrido secuencial de los caracteres de una cadena:
Para recorrer todos los caracteres de una cadena desde el principio hasta el final, debemos comenzar por el carácter de índice 0 e ir incrementando el índice hasta encontrar el carácter fin de cadena (carácter nulo).
Ejemplo 5.9: Escribe una función que cuente los caracteres de una cadena que se le pasa como parámetro y devuelva el número de caracteres que contiene excluyendo el carácter fin de cadena.
unsigned int long_cad( char cadena[] ) { unsigned int i = 0; while (cadena[i] != '\0') i++; return i; }
Ejemplo de uso de long_cad: Usando la función del ejemplo anterior, imprime el número de caracteres de la frase “Dábale arroz a la zorra el abad”.
int main() { printf( "La frase tiene %u caracteres.\n", long_cad( "Dábale arroz a la zorra el abad" ) ); system( “pause” ); return 0; }
Ejercicio: Escribe una función
llamada escribe_cad
que se comporte del modo similar que la función puts
.
Es decir, la función recibe una cadena de caracteres como
parámetro y la muestra por salida estándar seguida de
un salto de línea (carácter '\n'
).
Utilice la función
para escribir caracteres por salida estándar. Esta función
se encuentra definida en el fichero de encabezamiento putchar
“stdio.h”
y recibe como parámetro un carácter. Para
probar tu función puedes utilizar el Ejemplo
5.2, cambiando las llamadas a la función puts
por escribe_cad
,
tal como se muestra en el siguiente
código:
int main() { char mensaje[] = "Hola mundo"; escribe_cad( mensaje ); escribe_cad( "Hasta luego mundo" ); system( "pause" ); return 0; }
Construcción de cadenas:
Cuando
construimos una cadena carácter a carácter debemos
recordar que hay que marcar el final de cadena con el carácter
fin de cadena (carácter nulo '\0'
).
Ejemplo 5.10: Escribe una función que copie una cadena de caracteres en otra, transformando en mayúsculas las iniciales de cada palabra. El prototipo de la función es el siguiente:
void iniciales_may( char destino[], char fuente[] );
La función transforma la cadena que se
le pasa en el parámetro fuente
y la almacena en el parámetro destino
.
Para simplificar el problema, supondremos que las cadenas sólo
contienen letras y espacios.
Para convertir un carácter de
minúsculas a mayúsculas, puedes utilizar la función
toupper
que se
encuentra definida en el fichero de encabezamiento “ctype.h”
.
Esta función recibe como
parámetro un carácter y devuelve el carácter
correspondiente en mayúsculas.
#include <ctype.h> void iniciales_mays( char destino[], char fuente[] ) { char caracter_anterior = ' '; int i; for (i=0; fuente[i] != '\0'; i++) { if (caracter_anterior == ' ' && fuente[i] >= 'a' && fuente[i] <= 'z') destino[i] = toupper( fuente[i] ); else destino[i] = fuente[i]; caracter_anterior = fuente[i]; } destino[i] = '\0'; /* Marcamos el final de la cadena destino. */ }
void main() { char texto[200]; iniciales_mays( texto, "guiones de practicas" ); printf( "%s\n", texto ); system( “pause” ); return 0; }
Ejercicio: Modifique la función
anterior para que almacene en el parámetro destino
el acrónimo de la cadena que se le pasa en el parámetro
fuente
. Por
ejemplo, si la cadena fuente es “Sociedad
española de transportistas autónomos”
,
la función almacenará en la cadena destino “SEDTA”
.
Puede probar la función con el ejemplo de uso utilizado para
la función iniciales_mays
.
Concatenación de cadenas:
Para
añadir caracteres al final de una cadena debemos insertar
los nuevos caracteres a partir de la posición donde se
encuentre el carácter fin de cadena (carácter nulo
'\0'
).
Ejemplo
5.11: Escriba una función llamada strcat_mays
que se comporte de modo similar que la función strcat
pero convirtiendo a mayúsculas la cadena fuente. Para
convertir los caracteres de minúsculas a mayúsculas
puedes utilizar la función toupper descrita en el ejemplo
anterior.
#include <ctype.h> char *strcat_mays( char destino[], char fuente[] ) { int i = 0; int j; while (destino[i] != '\0') i++; for (j=0; fuente[j] != '\0'; j++) { if (fuente[j] >= 'a' && fuente[j] <= 'z') destino[i+j] = toupper(fuente[j]); else destino[i+j] = fuente[j]; } destino[i+j] = '\0'; return destino; }
int main() { char texto[100] = ""; strcat_mays( texto, "esto es " ); puts( texto ); strcat_mays( texto, "una PRUeba." ); puts( texto ); system( “pause” ); return 0; }
Escribe una función que cuente el número de veces que aparece un determinado carácter en una cadena de caracteres. La función recibirá como parámetros la cadena y el carácter que debe contar, y devolverá un valor de tipo entero que contiene el resultado de la cuenta.
Escribe una función que busque todas las apariciones de un carácter en una cadena de caracteres y lo sustituya por otro. La función recibirá como parámetros la cadena en la que realizará la búsqueda, el carácter a buscar, el carácter a sustituir y la cadena de caracteres donde debe almacenar el resultado.
Escribe
una función que compare alfabéticamente dos cadenas sin
distinguir entre mayúsculas o minúsculas. La función
recibe como parámetros las dos cadenas de caracteres que debe
comparar y devuelve un valor entero que indica el resultado de la
comparación siguiendo el mismo criterio que la función
strcmp
.
Escribe
un programa que implemente el juego que proponemos a continuación.
En el juego participan dos jugadores a los que llamaremos A y B. El
jugador A debe pensar una palabra y el jugador B debe adivinarla con
el menor número de jugadas posible, sabiendo en cada jugada si
la palabra buscada es anterior o posterior a la palabra propuesta. Al
comenzar el juego, el programa solicitará al jugador A que
escriba una palabra. Después de leer la palabra del teclado,
para evitar que ésta se vea en la pantalla, escribirá
25 saltos de línea (carácter '\n'
).
A continuación comienza el turno del jugador B. En cada
jugada, el jugador B debe escribir una palabra y el programa le
indicará si la palabra introducida es anterior, igual o
posterior a la palabra buscada. El juego termina cuando el jugador B
adivine la palabra o cuando teclee “.fin”
.
Finalmente, el programa debe mostrar un mensaje indicando si el
jugador B ha adivinado la palabra y el número de intentos.
Escribe
una función que reciba una cadena de caracteres como entrada e
indique si dicha cadena es un palíndromo (una cadena que se
lee igual hacia delante que hacia atrás). La función
debe devolver un valor distinto de cero si la cadena es un
palíndromo, o cero si no lo es. A continuación se
muestra un ejemplo de palíndromo: “Dábale
arroz a la zorra el abad”
.
Para
simplificar el problema, en este apartado supondremos que la cadena
no contiene espacios, mayúsculas ni tildes. Por ejemplo, el
palíndromo anterior sería:
“dabalearrozalazorraelabad”
.
Repita
el apartado anterior considerando que la cadena puede contener
espacios. Por ejemplo: “dabale
arroz a la zorra el abad”
.
Repita el apartado anterior considerando que la cadena puede contener espacios, tildes, mayúsculas y minúsculas. El programa debe ignorar las diferencias entre mayúsculas y minúsculas, así como entre las vocales con tilde y sin tilde.