Guión 5: Cadenas de caracteres

Introducción


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

“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


Las cadenas de caracteres se almacenan en vectores de caracteres (arrays unidimensionales de tipo char).

Ejemplos de inicialización de cadenas de caracteres:

char texto[] = “hola”;

La variable texto tiene una longitud de 5 caracteres:

0

1

2

3

4

h

o

l

a

\0

char texto[] = {‘h’, ‘o’, ‘l’, ‘a’, ‘\0’};
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

h

o

l

a

\0











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:

char cadenas[5][19] = { 
     "Sumo con precisión",
     "Almaceno datos",
     "Dibujo gráficos",
     "Ejecuto programas",
     "Domino el C" };


0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

cadenas[0]

S

u

m

o


c

o

n


p

r

e

c

i

s

i

o

n

\0

cadenas[1]

A

l

m

a

c

e

n

o


d

a

t

o

s

\0





cadenas[2]

D

i

b

u

j

o


g

r

a

f

i

c

o

s

\0




cadenas[3]

E

j

e

c

u

t

o


p

r

o

g

r

a

m

a

s

\0


cadenas[4]

D

o

m

i

n

o


e

l


C

\0









cadenas[2]
char *cadenas[5] = { 
     "Sumo con precisión",
     "Almaceno datos",
     "Dibujo gráficos",
     "Ejecuto programas",
     "Domino el C" };
cadenas[0]

Funciones de Entrada/Salida de cadenas de caracteres

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:

#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;
}
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:

#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;
}
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.

#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;
}

Manipulación de cadenas de caracteres utilizando la biblioteca string

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 );
#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 );
#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;
}
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 );
int main() {
    char resultado[80] = “otorrino”;
    strcat( resultado, “laringólogo” );
    printf( “%s\n”, resultado );
}
#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;
}
int main() {
    char nombre_completo[100];
    genera_nombre( “Juan”, “Fuentes”, “Soleadas”, nombre_completo );
    printf( “%s\n”, nombre_completo );
    system( “pause” );
    return 0;
}

Comparación de cadenas:

int strcmp( char *cad1, char *cad2 );

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

#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;
}

Manipulación de cadenas carácter a carácter

Recorrido secuencial de los caracteres de una cadena:

unsigned int long_cad( char cadena[] ) {
    unsigned int i = 0;
    while (cadena[i] != '\0')
        i++;
    return i;
}
int main() {
    printf( "La frase tiene %u caracteres.\n",
        long_cad( "Dábale arroz a la zorra el abad" ) );
    system( “pause” );
    return 0;
}
int main() {
    char mensaje[] = "Hola mundo";
    escribe_cad( mensaje );
    escribe_cad( "Hasta luego mundo" );
    system( "pause" );
    return 0;
}

Construcción de cadenas:

#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;
}

Concatenación de cadenas:

#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;
}

Ejercicios de afianzamiento

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”.

  1. 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”.

  2. Repita el apartado anterior considerando que la cadena puede contener espacios. Por ejemplo: “dabale arroz a la zorra el abad”.

  3. 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.