CARACTERES Y CADENAS EN C.



El tipo Carácter en C El nombre del tipo carácter en C es char. Este tipo ocupa un byte (ocho bits) de extensión, y puede interpretarse con y sin signo. La tabla de tipos de datos de carácter en C es como sigue:

Nombre Extensión Alcance
 char  8 bits Cualquier código ASCII
 signed char  8 bits desde -128 hasta +127
 unsigned char  8 bits desde 0 hasta 255


Véase a continuación un ejemplo de utilización de variables de los tipos anteriores:
#include<stdio.h>

char letra;
signed char letraconsigno;
unsigned char letrasinsigno;

int main(int argc, char * argv[])
{
	letra = 'A';
	printf("La letra es %c y su valor decimal es %d.\n\n",
				letra,letra);
	
	letraconsigno = -65;
	printf("Letraconsigno es %d y su valor decimal es %d.\n\n",
				letraconsigno,letraconsigno);
	
	letrasinsigno = 165;
	printf("Letrasinsigno es %u y su valor decimal es %d.\n\n",
				letrasinsigno,letrasinsigno);
	return 0;
}

Y el resultado de ejecutar este programa es:

La letra es A y su valor decimal es 65.

Letraconsigno es -65 y su valor decimal es -65.

Letrasinsigno es 165 y su valor decimal es 165.

Como puede apreciarse, el descriptor empleado para la lectura y escritur de variables de tipo char es %c.

Nota.- La lectura de caracteres individuales plantea una insospechada dificultad, debida a que C es literal, y cuando se le pide que lea un caracter, obedece sin rechistar. Pero no hemos pulsado un carácter, sino dos, ¿verdad? Véase el siguiente

Ejemplo
#include<stdio.h>

/* Este programa muestra los peligros que acechan
        al incauto lector de caracteres */

char unaletra, otraletra;

void main(void)
{
        printf("Escriba una letra y pulse intro, por favor: ");
        scanf("%c", &unaletra);
        
        printf("La letra que ha pulsado era %c y su valor decimal es %d\n", unaletra, unaletra);
        
        printf("Ahora escriba otra letra, por favor: ");
        scanf("%c", &otraletra);
        
        printf("La letra que ha pulsado era %c y su valor decimal es %d\n", otraletra, otraletra);

        printf("\n\nTerminación normal del programa.\n\n");
}
/*
        El resultado de la ejecución de este programa es:
Escriba una letra y pulse intro, por favor: a
La letra que ha pulsado era a y su valor decimal es 97
Ahora escriba otra letra, por favor: La letra que ha pulsado era 
 y su valor decimal es 10


Terminación normal del programa.

¿Qué ha pasado?
*/


Existen varias posibilidades para descartar el carácter sobrante. Una de ellas es emplear un descriptor que ignora el carácter siguiente al leído: %c%*c en lugar de %c. También se puede recurrir a las funciones gets() y fgets(), que ofrece stdio.h, y que sirven para leer cadenas. La primera, gets() lee del teclado hasta que encuentra el retorno de carro; ése retorno no se incluye en la cadena proporcionada y gets() podría servir muy bien para vaciar el búfer si no fuera peligrosa: es responsabilidad del usuario reservar espacio suficiente para la cadena leída. Dado que no es posible anticipar con seguridad lo que hará el usuario, resulta más prudente emplear fgets(). Esta función si permite determinar el número máximo de caracteres leídos, y devuelve un puntero nulo cuando el búfer está vacío. Una tercera solución, finalmente, consiste en invocar a la función fpurge(stdin) inmediatamente después de leer el carácter. De este modo se descarta directamente el contenido restante en el búfer de teclado. Sólo hay un problema: es propia de Unix, y los entornos que no están basados en este estándar suelen carecer de ella. El tipo Cadena en C Una cadena es una sucesión de caracteres, cuyo final está marcado mediante el carácter '\0', que se emplea como marcador de fin de cadena. Obsérvese que se ha encerrado la expresión \0 entre comillas sencillas y no dobles. Esto denota que se trata de un carácter; si se hubiera encerrado entre comillas dobles se trataría de la cadena formada por este carácter... y tendría dos bytes de longitud, siendo el último, precisamente, '\0'. La adición de este carácter de finalización es imprescindible, toda vez que será empleado por todas las funciones de tratamiento de cadenas. Las cadenas de C se declaran como listas de caracteres. El carácter de terminación también cuenta, y ocupa un byte igual que cualquier otro. Por tanto, una cadena para la cual se reserven 80 caracteres podrá contener un máximo de 79 caracteres del usuario, más el carácter de terminación. Esto no implica, desde luego, que sea obligatorio emplear siempre todos los caracteres reservados... con el consiguiente desperdicio de espacio en la mayoría de las ocasiones. La función strlen(),que pertenece a string.h, permite determinar el número exacto de caracteres de la cadena utilizados realmente. El operador sizeof() proporciona el número total de caracteres reservados para la cadena. Consúltense las páginas man. Las cadenas se declaran mediante expresiones de la forma siguiente:
char cadena[numero_total_de_bytes_reservados];
o bien char cadena[] = "Algún valor"; o bien, incluso, char cadena[] = {    'U', 'n', 'o', 's', ' ',
                    'c', 'u', 'a', 'n', 't', 'o', 's', ' ',
                    'c', 'a', 'r', 'c', 't', 'e', 'r', 'e', 's', '\0'}; Obsérvese que el compilador reserva, en los dos últimos casos, el espacio necesario para almacenar la cadena deseada. El compilador, en el caso de dar valor inicial a la cadena, incluyen el marcador de fin de cadena '\0' aún cuando éste no se indique explícitamente. No sucede lo mismo cuando se omite el carácter '\0' en la última declaración. Véase el siguiente ejemplo: #include<stdio.h> int main(int arcg, char* argv[]) {
    char c1[8];
    char c2[] = "Hola";
    char c3[] = {    'U', 'n', 'o', 's', ' ',
                     'c', 'u', 'a', 'n', 't', 'o', 's', ' ',
                     'c', 'a', 'r', 'a', 'c', 't', 'e', 'r', 'e', 's', '\0'};
    strcpy(c1,"hola");
    printf("Esto es c1 %s\n", c1);
    printf("Esto es c2 %s\n", c2);
    printf("Esto es c3 %s\n", c3);
    return 0;
} Obsérvese la necesidad de emplear la función strcpy() para dar valor a c1, que inicialmente no había recibido valor alguno. El compilador no admite el operador de asignación como método para dar valor a esta cadena, porque intentaría interpretar esa expresión empleando la lógica de punteros. En efecto: intente cambiar la expresión strcpy(c1, "Hola") por c1 = "Hola" y compile el programa.
Obsérvese también que aparecen caracteres adicionales al imprimir si se suprime el último carácter (el '\0') al declarar c3. Esto se debe a que printf() sigue imprimiendo caracteres en pantalla hasta llegar (casualmente) a un byte de valor 0.

E/S de Caracteres y Cadenas - Problemas derivados del uso de la memoria intermedia de teclado. Las cadenas pueden leerse y escribirse mediante el uso de scanf() y printf() respectivamente. Es preciso tener en cuenta que scanf() detiene la lectura de caracteres en cuanto encuentra un espacio en blanco o tabulador. Véase un ejemplo Ejemplo
#include<stdio.h>

/* Este programa muestra la utilización de cadenas en C */

char cadena[8], resto[80];

void main(void)
{
        printf("Escriba una cadena: ");
        scanf("%s", cadena); /* Las cadenas NO llevan & */
        
        printf("\n\nLa cadena leída era %s\n\n", cadena);
        
        printf("Y el resto era");
        gets(resto);
        puts(resto);
        printf("Terminación normal del programa.\n\n");
}
Es interesante recordar que todo lo que "sobra", esto es, lo que está más allá del primer espacio en blanco, queda almacenado y disponible para la siguiente sentencia de lectura. La función gets() captura todo lo restante, y después se imprime mediante puts(). Hay que ser precavidos a la hora de "dejar" restos en el tampón. Lo mejor es eliminar posibles restos antes de pasar a la lectura siguiente, empleando fflush(stdin) o bien fpurge(stdin).

Funciones de tratamiento de cadenas

El archivo de encabezado string.h contiene numerosas funciones relacionadas con el tratamiento de caracteres. Véase a continuación una tabla de funciones útiles:
/*
 *	Funciones de concatenación
 */
Encabezado Descripción
char *strcat (char *s1, const char *s2); Esta función añade s2 a s1 y pone un '\0' al final del resultado; se supone que s1 contiene espacio suficiente para el total de caracteres (los de s1, los de s2 y el '\0'). Proporciona como resultado un puntero de s1
char *strncat (char *s1, const char *s2, size_t n); Análoga a la anterior, pero añade a s1 un máximo de n caracteres de s2. Proporciona como resultado un puntero de s1
/*
 *	Funciones de comparación
 */
Encabezado Descripción
int memcmp (const void *s1, const void *s2, size_t n); Compara byte por byte las dos cadenas cuya dirección se proporciona, suponiendo que ambas tuvieran n bytes de longitud. Si ambas series de bytes son iguales, la función proporciona el valor 0. Si no son iguales, la función devuelve la diferencia entre los dos primeros bytes distintos. La comparación es numérica, sin tener en cuenta el orden alfabético internacional, lo cual produce resultados extraños cuando las cadenas contienen signos diacríticos.
int strcmp (const char *s1, const char *s2); Esta función compara byte por byte las cadenas de caracteres señaladas por s1 y s2. El resultado es:
  • negativo si s1 es menor que s2
  • nulo si s1 y s2 son iguales
  • positivo si s1 es mayor que s2
int strcoll (const char *s1, const char *s2); Esta función sirve para comparar dos cadenas, y hace uso de la secuencia lexicográfica (locale) definida en el momento de su ejecución. Produce valores numéricos análogos a los de strcmp()
int strncmp (const char *s1, const char *s2, size_t n); Esta función es una variante de strcmp() que compara únicamente los n primeros caracteres de ambas cadenas.
size_t strxfrm (char *s1, const char *s2, size_t n); Almacena en s1 la traducción de la cadena s2 a la configuración de locale definida en el momento de la ejecución. Esta función puede no estar presente en todas las implementaciones de la biblioteca de C; consúltense las páginas man de la máquina utilizada.
/*
 *	Funciones de búsqueda
 */
Encabezado Descripción
void *memchr (const void *s, int c, size_t n); Determina la posición de la primera aparición de c (que se interpreta como carácter sin signo) dentro de los n primeros bytes de la cadena s. Si c forma parte de s, se proporciona como resultado un puntero de c. Si c no forma parte de s, se proporciona el puntero nulo.
char *strchr (const char *s, int c); Análoga a la anterior, salvo que se explora toda la cadena, incluyendo el marcador final '\0'. Por tanto, si se busca '\0', se encontrará el marcador de fin de cadena.
size_t strcspn (const char *s1, const char *s2); Esta función calcula la longitud del segmento máximo de s1 que está formado por caracteres que no están presentes en s2. Dicho en pocas palabras, sirve para calcular la longitud de la subcadena complementaria.
char * strpbrk (const char *s1, const char *s2); Esta función busca en s1 la primera aparición de cualquier carácter de los contenidos en s2 y proporciona su dirección (mediante un puntero de carácter). Si s1 no contiene ningún carácter de s2, se proporciona el puntero nulo.
char *strrchr (const char *s, int c); Esta función busca un carácter c dentro de la cadena s, empezando por el final. Si lo encuentra, proporciona su dirección mediante un puntero. Si no lo encuentra, proporciona el puntero nulo. Dicho de otro modo, strrchr() busca la última aparición de c en s.
size_t strspn (const char *s1, const char *s2); Esta función calcula la longitud del máximo segmento inicial de s1 que está formado completamente por caracteres presentes en s2.
char *strstr (const char *s1, const char *s2); Esta función busca la primera aparición de s2 dentro de s1, sin tener en cuenta el carácter de fin de cadena. Si s2 se encuentra en s1, la función proporciona un un puntero del primer byte de s2 dentro de s1. Si no se encuentra s2 dentro de s1, se proporciona el puntero nulo.
char *strtok (char *s1, const char *s2); Esta función extrae subcadenas (tokens) de s1. Los separadores de subcadenas son los caracteres que contenga s2. La primera subcadena se proporciona (mediante un puntero) cuando se llama a strtok() empleando s1 y s2 como parámetros. La segunda subcadena (y siguientes) se obtienen mediante llamadas a strtok() con el puntero nulo como primer argumento, y con la cadena de separadores como segundo argumento (ésta se puede modificar en las distintas llamadas). Cuando ya no quedan más subcadenas, la función proporciona el puntero nulo. Obsérvese la notable utilidad de esta función para la lectura de archivos de texto con formato delimitado. Obsérvese también que, una vez invocada la cadena por primera vez, se admiten cambios en el delimitador especificado (¡que es una cadena! Se pueden emplear delimitadores "complejos", formados por múltiples caracteres.)
/*
 *	Varios
 */
Encabezado Descripción
void *memset (void *s, int c, size_t n); Sirve para rellenar la cadena señalada por s, copiando en sus bytes el valor de c, interpretado como carácter sin signo. Se escribe un máximo de n bytes.
char *strerror (int errnum); Esta función recibe como argumento un número de error y proporciona como resultado el mensaje de error correspondiente. Los números y mensajes de error dependen por completo del compilador (y de la plataforma).
size_t strlen (const char *s); Proporciona la longitud de la cadena señalada por s.





Un ejemplo
Construir un programa que muestre la forma de utilizar las principales funciones de tratamiento de cadenas en C. El programa debe mostrar procedimientos de lectura, escritura, comparación, concatenación y búsqueda de fragmentos.
funciones.h
/*
 *  funciones.h
 *  cadenas
 *
 *  Created by coti on 28/08/09.
 *  Copyright 2009 Tests by Coti. All rights reserved.
 *
 */
#include <stdio.h>
/* aquí vive strlen() */
#include <string.h>

/* CONSTANTES */

#define NUM_BYTES 128
#define LONGITUD_1 64
#define LONGITUD_2 64


void leer(char * p1, char * p2);
void mostrar(char * p1, char * p2);
void recorrer(char * p1, char * p2);
void comparar(char * p1, char * p2);
void concatenar(char * p1, char * p2, char * pc);
void buscar(char * p1, char * p2, char * pc);
funciones.c
/*
 *  funciones.c
 *  cadenas
 *
 *  Created by coti on 28/08/09.
 *  Copyright 2009 Tests by Coti. All rights reserved.
 *
 */

#include "funciones.h"

void leer(char * p1, char * p2)
{
	printf("\nEscriba la primera palabra: ");
	fgets(p1, LONGITUD_1, stdin);
	p1[strlen(p1)-1] = '\0';
	printf("\nEscriba la segunda palabra: ");
	fgets(p2, LONGITUD_2, stdin);
	p2[strlen(p2)-1] = '\0';
	printf("\n");
}
void mostrar(char * p1, char * p2)
{
	printf("\nLa primera palabra es %s y la segunda es %s\n\n", p1, p2);
}
void recorrer(char * p1, char * p2)
{
	int i;
	printf("\nLos caracteres de la palabra %s son:\n\n",p1);
	for (i=0; i<strlen(p1); i++) {
		printf("%3d %c\n", (unsigned char)p1[i], p1[i]);
	}
	printf("\nLos caracteres de la palabra %s son:\n\n",p2);
	for (i=0; i<strlen(p2); i++) {
		printf("%3d %c\n", (unsigned char)p2[i], p2[i]);
	}
	printf("\n");
}
void comparar(char * p1, char * p2)
{
	int resultado = strcmp(p1, p2);
	/* convertimos el resultado en un valor q es 1, 0 o -1 */
	resultado = resultado > 0 ? 1 : (resultado < 0 ? -1 : 0);
	switch (resultado) {
		case -1:
			printf("\n%s es menor que %s\n",p1,p2);
			break;
		case 0:
			printf("\n%s es igual que %s\n",p1,p2);
			break;
		case 1:
			printf("\n%s es mayor que %s\n",p1,p2);
			break;
		default:
			break;
	}
	printf("\n");
}
void concatenar(char * p1, char * p2, char * pc)
{
	strcpy(pc, "");
	strcat(pc, p1);
	strcat(pc, " ");
	strcat(pc, p2);
	printf("\nLa concatenación de %s y %s es %s\n\n",p1, p2, pc);
}
void buscar(char * p1, char * p2, char * pc)
{
	char * resultado = NULL;
	printf("\nEscriba la palabra que busca: ");
	fgets(pc, NUM_BYTES, stdin);
	pc[strlen(pc)-1] = '\0';
	resultado =  strstr(p1, pc);
	if (NULL == resultado)
		printf("\n%s no contiene a %s\n",p1,pc);
	else {
		printf("\n%s contiene a %s\n",p1,pc);
	}
	resultado =  strstr(p2, pc);
	if (NULL == resultado)
		printf("\n%s no contiene a %s\n",p2,pc);
	else {
		printf("\n%s contiene a %s\n",p2,pc);
	}
	printf("\n");
}
main.c
#include <stdio.h>
/* malloc() vive aquí */
#include <stdlib.h>
/* toupper() vive aquí */
#include <ctype.h>
/* Las funciones viven aquí */
#include "funciones.h"

/*
 Este programa muestra ejemplos de las operaciones fundamentales con cadenas:
 
 - declaración (estática)
 - lectura
 - escritura
 - recorrido
 - comparación
 - concatenación
 - búsqueda de fragmentos
*/

int main (int argc, const char * argv[]) {
	/*
	 Las variables palabra_1 y palabra_2 son cadenas de LONGITUD_1 y LONGITUD_2
	 bytes respectivamente, y se declaran estáticamente.
	*/
	char palabra_1[LONGITUD_1], palabra_2[LONGITUD_2];
	/*
	 La variable pcadena señala un bloque de memoria de dimensiones
	 iguales a la suma de dimensiones de palabra_1 y palabra_2.
	 */
	char * pcadena = malloc((LONGITUD_1+LONGITUD_2)*sizeof(char));
	/*
	 Este es el menú q muestra la aplicación
	 */
	char menu[] = "1)Leer 2)Mostrar 3)Recorrer 4)Comparar\n5)\
Concatenar 6)Buscar fragmento Q) Salir";
	/*
	 Esta es la opción q escribe el usuario
	 */
	char opcion;
	/*
	 Esta es la condición de finalización del programa
	 */
	int terminar = 0;
	do {
		printf("%s ", menu);
		scanf("%c%*c",&opcion);
		opcion = toupper(opcion);
		switch (opcion) {
			case '1':
				printf("\nLectura de cadenas\n");
				leer(palabra_1, palabra_2);
				break;
			case '2':
				printf("\nEscritura de cadenas\n");
				mostrar(palabra_1, palabra_2);
				break;
			case '3':
				printf("\nRecorrido de cadenas\n");
				recorrer(palabra_1, palabra_2);
				break;
			case '4':
				printf("\nComparación de cadenas\n");
				comparar(palabra_1, palabra_2);
				break;
			case '5':
				printf("\nConcatenación de cadenas\n");
				concatenar(palabra_1, palabra_2, pcadena);
				break;
			case '6':
				printf("\nBuscar un fragmento\n");
				buscar(palabra_1, palabra_2, pcadena);
				break;
			case 'Q':
				printf("\nTerminación del programa\n");
				terminar = 1;
				break;
			default:
				break;
		}
	} while (!terminar);
    return 0;
}

Comentarios
Este programa consta de dos archivos, y se puede compilar desde la línea de órdenes, o empleando cualquier IDE. Véanse las páginas
man
correspondientes a las distintas funciones.
La arquitectura de programa es muy básica; si se añade una función más será preciso modificar el programa principal. Sería posible emplear otra arquitectura menos engorrosa?

Ejercicios resueltos y propuestos

  1. Ejercicio 0103r01.-Un programa recibe un nombre y un apellido a través del teclado, en la forma:

    Por favor, dígame el nombre : José
    Por favor, dígame el apellido : García

    Se pide construir y mostrar en pantalla una cadena de la forma:

    Titular: José García.

    Emplear las funciones de concatenación descritas. ¿Qué ocurre si la cadena formada es más larga que la cadena de nombre?
    
    
  2. Ejercicio 0103r02.-Repetir el ejercicio anterior impidiendo la formación de cadenas excesivamente largas. Si es necesario, se truncará la cadena y se avisará al usuario.
    #include<stdio.h>
    
    #define DIM_NOMBRE 12
    #define DIM_APELLIDOS 10
    
    int main(int argc, char *argv[])
    	{
    		char nombre[DIM_NOMBRE], apellido[DIM_APELLIDOS];
    		printf("\n\nPor favor, dígame el nombre  : ");
    		fgets(nombre,sizeof(nombre),stdin);
    		/* fgets() retiene el retorno de carro, lo descartamos */
    		nombre[strlen(nombre)-1] = '\0';
    		/* Descartamos el resto si lo hay */
    		fpurge(stdin);
    		printf("\n\nPor favor,dígame el apellido : ");
    		fgets(apellido,sizeof(apellido), stdin);
    		/* fgets() retiene el retorno de carro, lo descartamos */
    		apellido[strlen(apellido)-1] = '\0';
    		/* Si cabe en nombre el nombre, un espacio y el apellido, lo almacenamos */
    		if (strlen(nombre) + strlen(" ") + strlen(apellido) < sizeof(nombre) -1)
    			{
    				strcat(nombre, " ");
    				strcat(nombre, apellido);
    			}
    		else /* Si no cabe, intentamos añadir el blanco y lo que quepa de apellido.
    				Hay que tener en cuenta que en nombre sobran sólamente
    					sizeof(nombre) - strlen(nombre) - 1
    					caracteres. Por tanto, limitamos a éste número
    				los caracteres añadidos (mediante strncat).
    			*/
    			{
    				strncat(nombre, " ", sizeof(nombre) - strlen(nombre)-1);
    				strncat(nombre, apellido, sizeof(nombre) - strlen(nombre)-1);
    				printf("Resultado demasiado largo, se ha truncado a %d caracteres.\n",
    						sizeof(nombre)-1);
    			};
    		printf("\n\nTitular: %s\n", nombre);
    		printf("\n\nFin del programa.\n\n");
    		return 0;
    	}
    
  3. Ejercicio 0103r03.-Construir un programa que muestre mediante strerror() los mensajes asociados a diferentes códigos de error.
    #include<stdio.h>
    
    int main(int argc, char * argv[])
    	{
    		int i;
    		char * p;
    		for(i=0;i<sys_nerr;i++)
    			printf("%d.-%s\n", i, p);
    		return 0;
    	}

    Este programa producirá resultados distintos en diferentes plataformas; además, cada una de ellas proporciona un número diferente (sys_nerr) de mensajes de error.
  4. Ejercicio 0103r04.-Construir un programa que admita dos cadenas, las compare e indique su relación de orden: la primera es menor que la segunda, son iguales o la primera es mayor que la segunda (strcmp()).
    #include<stdio.h>
    
    #define DIM_primera 10
    #define DIM_segunda 15
    
    int main(int argc, char *argv[])
    	{
    		char primera[DIM_primera], segunda[DIM_segunda];
    		int relacion, relacion2;
    		
    		printf("\n\nPor favor, escriba la primera cadena  : ");
    		fgets(primera,sizeof(primera),stdin);
    		/* fgets() retiene el retorno de carro, lo descartamos */
    		primera[strlen(primera)-1] = '\0';
    		/* Descartamos el resto si lo hay */
    		fpurge(stdin);
    		
    		printf("\n\nPor favor,escriba la segunda cadena : ");
    		fgets(segunda,sizeof(segunda), stdin);
    		/* fgets() retiene el retorno de carro, lo descartamos */
    		segunda[strlen(segunda)-1] = '\0';
    
    		relacion = strcmp(primera, segunda);
    		
    		printf("\n\nRelación: ");
    		if (relacion > 0)
    			printf("%s es mayor que %s\n",primera, segunda);
    		else
    			if (relacion < 0)
    				printf("%s es menor que %s\n", primera, segunda);
    			else
    				printf("%s es igual a %s\n", primera, segunda);
    		/*
    			Pero probemos lo que sucede
    			si sólo se comparan 6 caracteres
    		*/
    		relacion2 = strncmp(primera, segunda, 6); 
    		
    		printf("\n\nRelación2: ");
    		if (relacion2 > 0)
    			printf("%s es mayor que %s\n",primera, segunda);
    		else
    			if (relacion2 < 0)
    				printf("%s es menor que %s\n", primera, segunda);
    			else
    				printf("%s es igual a %s\n", primera, segunda);
    		printf("\n\nFin del programa\n\n");
    		return 0;
    	}
    	
    	/*
    		El resultado de la ejecución es como sigue:
    		
    		Por favor, escriba la primera cadena  : abcdefppp
    		
    		
    		Por favor,escriba la segunda cadena : abcdefzzz 
    		
    		
    		Relación: abcdefpp es menor que abcdefzzz
    		
    		
    		Relación2: abcdefpp es igual a abcdefzzz
    		
    */
    
    Como puede observarse en el resultado de la ejecución, la función strncmp() permite limitar la comparación al principio de las cadenas, produciendo resultados aparentemente falsos, aunque realmente sean exactos.
  5. Ejercicio 0103r05.-Se dispone de una lista de nombres y apellidos. Se pide construir un programa que procese la lista y muestre todos los registros que contengan una cierta palabra, bien sea como nombre, como primer apellido o como segundo apellido (strstr()).
    #include<stdio.h>
    
    #define FILAS 5
    #define LONGITUD_CADENA 20
    int main(int argc, char * argv[])
    	{
    		char	nombre[FILAS][LONGITUD_CADENA] = { "Juan", "Martín", "Pedro", "Luis", "Alonso"};
    		char	apellido_1[FILAS][LONGITUD_CADENA] = {"Martin", "Perez", "Garcia", "Hernandez", "Lopez"};
    		char	apellido_2[FILAS][LONGITUD_CADENA] = {"Alonso", "Gonzalez", "Martin", "Luis", "Gomez"};
    		char palabra[LONGITUD_CADENA];
    		int i;
    		printf("\n\nBúsqueda de registros\n\n");
    		printf("La lista de registros es:\n\n");
    		for(i=0;i<FILAS;i++)
    			printf("%d: %s %s %s\n",
    						i,
    						nombre[i],
    						apellido_1[i],
    						apellido_2[i]);
    		printf("\n\nEscriba una palabra: ");
    		scanf("%s", palabra);
    		printf("\n\nPalabra buscada: %s\n\n", palabra);
    		for(i=0;i<FILAS;i++)
    			{
    				if(	strstr(palabra,nombre[i])!=NULL ||
    					strstr(palabra,apellido_1[i])!=NULL ||
    					strstr(palabra,apellido_2[i])!=NULL)
    				printf("%s figura en el registro %d: %s %s %s\n",
    						palabra,
    						i,
    						nombre[i],
    						apellido_1[i],
    						apellido_2[i]);
    			}
    		printf("\n\nFin del programa\n\n");
    		return 0;
    	}
    
  6. Ejercicio 0103r06.-Se dispone de una lista de registros de formato delimitado, esto es, cuyos campos están separados por un carácter que no puede formar parte del campo. Se pide construir una función que admita esos registros y los separe en campos, mostrando esos campos en pantalla una vez separados (strtok()).
    #include<stdio.h>
    
    #define FILAS 5
    #define COLUMNAS 40
    int main(int argc, char * argv[])
    	{
    		char registro[FILAS][COLUMNAS] = { "Ana*Perez*Lopez",
    									"Bernardo*Garcia*Gonzalez",
    									"Carlos*Martin*Martin",
    									"Damian*Garcia*Perez",
    									"Elena*Gonzalez*Martin"};
    		int i;
    		char * p;
    		for(i=0;i<FILAS;i++)
    			{
    				printf("\n\nLos campos del registro %s son:\n\n", registro[i]);
    				puts(strtok(registro[i], "*"));
    				while (p = strtok(NULL,"*"))
    					puts(p);
    			}
    		printf("\n\nFin del programa\n\n");
    		return 0;
    	}
    	
    
    El resultado de ejecutar este programa es precisamente el deseado:
    /*
    	Los campos del registro Ana*Perez*Lopez son:
    	
    	Ana
    	Perez
    	Lopez
    	
    	
    	Los campos del registro Bernardo*Garcia*Gonzalez son:
    	
    	Bernardo
    	Garcia
    	Gonzalez
    	
    	
    	Los campos del registro Carlos*Martin*Martin son:
    	
    	Carlos
    	Martin
    	Martin
    	
    	
    	Los campos del registro Damian*Garcia*Perez son:
    	
    	Damian
    	Garcia
    	Perez
    	
    	
    	Los campos del registro Elena*Gonzalez*Martin son:
    	
    	Elena
    	Gonzalez
    	Martin
    	
    	
    	Fin del programa
    */