Subsecciones

17. Manejo de cadenas <string.h>

Recordando la presentación de arreglos hecha (capítulo 5) en donde las cadenas están definidas como un arreglo de caracteres o un apuntador a una porción de memoria conteniendo caracteres ASCII. Una cadena en C es una secuencia de cero o más caracteres seguidas por un caracter NULL o \0:

Figura 17.1: Representación de un arreglo.
\includegraphics[width=3in, clip]{figuras/cadena.eps}

Es importante preservar el caracter de terminación NULL, ya que con éste es como C define y maneja las longitudes de las cadenas. Todas las funciones de la biblioteca estándar de C lo requieren para una operación satisfactoria.

En general, aparte de algunas funciones restringidas en longitud (strncat(), strncmp() y strncpy()), al menos que se creen cadenas a mano, no se deberán encontrar problemas. Se deberán usar las funciones para manejo de cadenas y no tratar de manipular las cadenas en forma manual desmantelando y ensamblando cadenas.

17.1 Funciones básicas para el manejo de cadenas

Todas las funciones para manejo de cadenas tienen su prototipo en:

#include <string.h>

Las funciones más comunes son descritas a continuación:

El uso de muchas funciones es directo, por ejemplo:

char *s1 = "Hola";
char *s2;
int longitud;

longitud = strlen("Hola");	/* long = 4 */
(void) strcpy(s2,s1);

Observar que tanto strcat() y strcopy() regresan una copia de su primer argumento, el cual es el arreglo destino. Observar también que orden de los argumentos es arreglo destino seguido por arreglo fuente lo cual a veces es una situación para hacerlo incorrectamente.

La función strcmp() compara lexicográficamente las dos cadenas y regresa:

Las funciones de copiado strncat(), strncmp() y strncpy() son versiones más restringidas que sus contrapartes más generales. Realizan una tarea similar, pero solamente para los primeros n caracteres. Observar que el caracter de terminación NULL podría ser violado cuando se usa estas funciones, por ejemplo:

char *s1 = "Hola";
char *s2 = 2;
int longitud = 2;

(void) strncpy(s2, s1, longitud); /* s2 = "Ho" */

donde s2 no tiene el terminador NULL.

17.1.1 Búsqueda en cadenas

La biblioteca también proporciona varias funciones de búsqueda en cadenas.

Las funciones strchr() y strrchr() son las más simples de usar, por ejemplo:

char *s1 = "Hola";
char *resp;

resp = strchr(s1,'l');

Después de la ejecución, resp apunta a la localidad s1 + 2.

La función strpbrk() es una función más general que busca la primera ocurrencia de cualquier grupo de caracteres, por ejemplo:

char *s1 = "Hola";
char *resp;

res = strpbrk(s1,"aeiou");

En este caso, resp apunta a la localidad s1 + 1, la localidad de la primera o.

La función strstr() regresa un apuntador a la cadena de búsqueda especificada o un apuntador nulo si la cadena no es encontrada. Si s2 apunta a una cadena de longitud cero (esto es, la cadena ""), la función regres s1. Por ejemplo:

char *s1 = "Hola";
char *resp;

resp = strstr(s1,"la");

la cual tendrá resp = s1 + 2.

La función strtok() es un poco más complicada en cuanto a operación. Si el primer argumento no es NULL entonces la función encuentra la posición de cualquiera de los caracteres del segundo argumento. Sin embargo, la posición es recordada y cualquir llamada subsecuente a strtok() iniciará en ésa posición si en estas subsecuentes llamadas el primer argumento no es NULL. Por ejemplo, si deseamos dividir la cadena s1 usando cada espacio e imprimir cada ``token'' en una nueva línea haríamos lo siguiente:

char s1[] = "Hola muchacho grande";
char *t1;

for ( t1 = strtok(s1," ");
      t1 != NULL;
      t1 = strtok(NULL, " ") )
	printf("%s\n",t1);

Se emplea un ciclo for en una forma no regular de conteo:

17.2 Prueba y conversión de caracteres <ctype.h>

Una biblioteca relacionada #include <ctype.h> la cual contiene muchas funciones útiles para convertir y probar caracteres individuales.

Las funciones más comunes para revisar caracteres tienen los siguientes prototipos:

Las funciones para conversión de caracteres son:

El uso de estas funciones es directo y por lo tanto, no se dan ejemplos.

17.3 Operaciones con la memoria <memory.h>

Finalmente se verá un resumen de algunas funciones básicas de memoria. Sin embargo, no son funciones estrictamente de cadenas, pero tienen su prototipo en #include <string.h>:

El uso de estas funciones es directo y parecido a las operaciones de comparación de caracteres (excepto que la longitud exacta (n) de todas las operaciones deberá ser indicada ya que no hay una forma propia de terminación).

Observar que en todos los casos bytes de memoria son copiados, por lo que la función sizeof() ayuda en estos casos, por ejemplo:

char fuente[TAM], dest[TAM];
int ifuente[TAM],idest[TAM];

memcpy(dest, fuente, TAM);  /* Copia chars (bytes) OK */
memcpy(idest,ifuente,TAM*sizeof(int));   /* Copia arreglo de enteros */

La función memmove() se comporta de la misma forma que memcpy() excepto que las localidades de la fuente y el destino podrían traslaparse.

La función memcmp() es similar a strcmp() excepto que unsigned bytes son comparados y se devuelve cero si s1 es menor que s2, etc.

17.4 Ejercicios

  1. Escribir una función similar a strlen que pueda manejar cadenas sin terminador. Tip: se necesitará conocer y pasar la longitud de la cadena.
  2. Escribir una función que regrese verdad, si una cadena de entrada es un palíndromo. Un palíndromo es una palabra que se lee igual de izquierda a derecha, o de derecha a izquierda. Por ejemplo, ANA.
  3. Sugerir una posible implementación de la función strtok():
    1. usando otras funciones de manejo de cadenas.
    2. desde los principios de apuntadores.
    ¿Cómo se logra el almacenamiento de una cadena separada?
  4. Escribir una función que convierta todos los caracteres de una cadena a mayúsculas.
  5. Escribir un programa que invierta el contenido de la memoria en bytes. Es decir, si se tienen n bytes, el byte de memoria n se invierte con el byte 0, el byte n-1 se intercambia con el byte 1, etc.