CADENA DE CARACTERES
Cuando se estudió los tipos de datos definidos en C, se pudo observar que el lenguaje C sólo define datos de tipo entero y de punto flotante. Se puede apreciar que existe un tipo de dato denominado char, sin embargo una variable definida de este tipo alberga números enteros entre -128 y 127 y no caracteres como lo hacen otros lenguajes como el Pascal.
También se pudo apreciar que un valor constante de tipo entero se puede expresar de diferentes formas, por jemplo como un número entre tradicional (123, 5, 796, 114567, etc), como un número en base 8, anteponiendo un cero al número (0173, 05, 01434, 337607, etc.) o como números hexadecimales, anteponiéndoles 0x (0x7B, 0x5, 0x31C, 0x1BF87, etc.), pero también se puede expresar un número entero empleando una notación de caracteres, es decir escribiendo un caracter entre apóstrofos simples ('A', '?', 'h' '%', etc.). Esto se da porque un pograma en C/C++ (o en cualquier otro lnguaje de programación) se redacta en un editor de palabras, por lo tanto todo lo que se escribe en el editor son secuencias de caracteres. Es el compilador el que interpreta estos caracteres y los almacena en la memoria como representaciones binarias. Es lo mismo para el compilador haber escrito int a = 65; que escribir int a = 'A'; o escribir int a = 0x41; en la dirección de memoria dada para la variable a se almacena la misma representación binaria (0100 0001). Es por esta razón que una expreción puede darse de esta manera a = 'A' + 32;, no es que se pretenda sumar el valor de 32 a la letra A, si no qe se esta sumando 32 al valor numérico que este caracter represanta.
En este sentido podemos definir una cadena de caracteres en C como un arreglo en el que en cada elemento es de tipo char. Los caracteres de una cadena se colocarán uno a continuación del otro en los elementos del arreglo, a partir del primero. Para poder saber donde terminan los caraceres válidos en el arreglo, se debe colocar un valor de terminación al final de la secuencia de caracteres, este valor es cero, que representa al caractere cuyo código ASCII es cero. Este valor se le puede proporcionar al arreglo simplemente como 0 ó mediante su representación como caractere: '\0'.
Esta forma de manipular las cadenas de caracteres trae muchas ventajas en comparación de la forma en que lo hacen otros lenguajes de programación. Por ejemplo en Pascal, la longitud de las cadenas de caracteres se almacena en la misma representación, al inicio de la secuencia de caracteres. Como cada elemento de la cadena se almacena en un byte, y la longitud no es una excepción, las cadenas en Pascal no pueden tener más de 255 caracteres. Las cadenas en C, al no almacenar el tamaño, permite manejar cadenas sin límite de tamaño.
DECLARACIÓN:
Una cadena de caracteres es un arreglo de tipo char, por lo tanto una cadena de caraceres se declara de la siguiente manera:
char identificador [límite];
Por ejemplo:
char nombre[20];INICIALIZACIÓN:
ð donde "nombre" es una cadena de caracteres que puede albergar hasta 19 caracteres, no olvidar que se requiere un espacio para el delimitador de la cadena (cero o '\0'). por eso no se pueden albergar en ella 20 caracteres.
char nomb1[10] = { 72, 111, 108, 97, 0, 43, 9, 123, 10, 45}; óSi recordamos de los arreglos, si se colocan menos valores de inicialización que la capacidad del arreglo, el resto de elementos del arreglo se inicializa en cero. Entonces, si realizamos la siguinte operación:
char nomb2[10] = {'H', 'o', 'l', 'a', '\0', '+', '\t', '{', '\n', 'A'};
En ambos casos se asigna a los elemntos del arreglo la misma información (los números en en nomb1 equivalen a los códigos ASCCI de los caracteres que aparecen en nomb2).
Observe que, según lo expuesto anteriormente, sólo los primeros cuatro datos corresponden a caracteres válidos en las cadenas, ya que el quinto elemento es un 0 (cero) o un '\0', delimitadores de la cadena.
char nomb3[10] = {'H', 'o', 'l', 'a'};Otra opción que nos da el compilador para inicializar una cadena de caracteres es haciendo uso de una secuencia de caracteres encerrados entre comillas ("..."), como se muestra a continuación:
Esto signfica que: nomb3[0] ï 'H', nomb3[1] ï 'o', nomb3[2] ï 'l', nomb3[3] ï 'a', nomb3[4] ï 0 ó '\0', nomb3[5] ï 0 ó '\0', etc., lo que significa que la cadena está perfectamente delimitada.
char nomb4[10] = "Hola";LECTURA Y ESCRITURA DE CADENAS DE CARACTERES
Esto es equivalente a la inicialización de la variable nomb3. Incluso se le ha colocado el delimitador en la quinta posición.
char nombre[20];
scanf("%s", nombre);
Primero observe que, en la funcion scanf, a la variable nombre no se le antepone el & como a las variables enteras o de punto flotante, esto se debe a que la variable nombre es un arreglo y por lo tanto un puntero que contiene la dirección de inicio del arreglo.
La función scanf irá tomando uno a uno los caracteres del buffer de entrada, y los irá colocando consecutivamente en el arreglo a partir del primer elemento. Al fnal colocará el delimitador 0 ó '\0' en el siguiente elemento, imediatamente después del último caracter ingresado.
La imagen siguiente muestra cómo se realiza este proceso:
char nombre[20];Un aspecto que se debe tomar en cuenta, cuando se quiere leer una cadena de caracteres empleando scanf es que, al igual con la lectura de números, la exploración de un dato se realiza hasta encontrar un "espacio" (entiéndase por "espacio", un caracter blanco, un caracter de tabulación o un caracter de cambio de línea). Es por esta razón que empleando el especificador de acceso %s en la función scanf sólo se podrán leer palabras sueltas y no frases completas.
char *c1, *c2;
scanf("%s", c1); // Esto es un error lógico, ya que c1 no apunta a una dirección válida.
c2 = nombre;
scanf("%s", c2); // Esto es correcto.
char * gets(char *);La función gets recibe como parámetro un arreglo de tipo char, en él se almacenará los caracteres provenientes de la consola. A difierencia de prints la lectura con gets no se detendrá cuando se encuentre un espacio en blanco sino hasta encontrar un caracter de cambio de línea. La función devuelve un puntero de tipo char que apunta al argumento, si se pretende leer al final del archivo la función devuelve NULL.
int puts (char *);
Por ejemplo:
cin.getline(cad, n);
ð donde "cad" es una cadena de caracteres y n es la cantidad máxima de caracteres menos uno, que se podrá leer desde el buffer de entrada. Alfinal coloca el caracter de terminación.
int a, b, c;En el caso de las cadenas de caracteres, no se puede asignar valores como se hacen con las variables numéricas. La razón de esto es la forma como se definen las cadenas en C., mediante arreglos. Si definimos dos cadenas como char a[20], b[2]; y queremos asignar una a la otra escribiendo la instrucción a = b; se producirá un error de compilación, esto debido a que, como dijimos en el capítulo de arreglos, cuando en un programa se empele el identificador del arreglo sin colocar un índice entre corchetes, se estará haciendo referencia a la dirección de memoria del inicio del área de datos del arreglo. En el caso de la instrucción anterior se estará tratando de asignar la dirección de memoria del área asignada a b a la variable a. Esto es un absurdo, ya que una variable definida como arreglo apunta de manera constante a un área de datos y por lo tanto no se le puede hacer apuntar a otra área de datos.
a = 234; // asignación de un valor constante.
b = a; // asignación de una variable.
c = a + b; // asignación de una expresión.
char nombre[50];Esto no se debe confundir con la inicialización de una cadena de caracteres como vimos al inicio de este capítulo, en estos caso el valor constante es ubicado por el compilador en el espacio asignado al arreglo.
nombre = "Paula Valentina"; // esto es un ERROR de compilación.
char *nombre;esto se debe a que un puntero puede apuntar a cualquier área de datos, en particular a la asignada al valor constante.
nombre = "Naomi Alexandra"; // esto SI es correcto.
#include <stdio.h>Otra versión de esta misma rutina, que aprovecha más las propiedades del lenguaje C en cuanto a punteros se trata, puede ser la siguiente:
void copiar (char [], char []);
int main (void)
{ char nomb1[30], nomb2[30];
gets(nomb1);
copiar (nomb2, nomb1); // se lee: copiar en nomb2 los caracters de nomb1
···
}
void copiar (char destino[], char origen[])
{ int i=0;
while (origen[i]!= 0)
{ destino[i] = origen[i]; // copiamos caracter a caracter
i++;
}
destino[i] = 0; // no se debe olvidar de colocar el caracter de terminación
}
#include <stdio.h>Esta rutina, ahora más pequeña que la anterior, lo que hace es lo siguinte: Los punteros destino y origen apuntan inicialmente al primer elemento del arreglo respectivo. Como la condición del while tiene un = (asignación) y no un == (comparación), la orden *destino = *origen coloca el primer caracter de la cadena origen en el primer caracter de la cadena destino. Luego se aplica el operador ++, que está como sufijo, a destino y a origen (no se aplica a *destino ni a *origen por la forma como se agrupa el operador), por lo que cada puntero termina apuntando al siguiente caracter de la cadena. Finalmente el resultado de la asignación es el valor que se emplea para verificar el final de while, si es un caracter cualquiera el que se asignó, el ciclo continua, pero si se asignó el caracter de terminación, que es un valor cero, el ciclo se detiene. Esto último quiere decir que no se necesita dar una orden adicional para asignar el caracter de terminación a la cadena destino. Se debe tener en cuenta que destino y origen son dos parámetros por valor, por lo que no importa que se alteren los lugares a donde apuntan, esto no afecta a los punteros o arreglos de la función que llamó a la rutina copiar.
void copiar (char *, char *);
int main (void)
{ char nomb1[30], nomb2[30];
gets(nomb1);
copiar (nomb2, nomb1); // se lee: copiar en nomb2 los caracters de nomb1
···
}
void copiar (char *destino, char *origen)
{ while (*destino++ = *origen++);
}
int cad1[30], cad2[30];El compilador no detectará errores, sin embargo al ejecutarlo se imprimirá siempre el mensaje Diferentes, sin importar qué valores asignemos a las cadenas. Esto se debe a que lo que se está comparando no son los contenidos de las cadenas, sino las direcciones donde apuntan; al ser arreglos en este caso apuntarán a direcciones diferentes.
gets(cad1);
gets(cad2);
if (cad1 == cad2) printf("Iguales\n");
else printf("Diferentes");
#include <stdio.h>Otra versión de esta misma rutina empleando punteros puede ser la siguiente:
int comparar (char [], char []);
int main (void)
{ char nomb1[30], nomb2[30];
int resultado;
gets(nomb1); gets(nomb2);
resultado = comparar (nomb1, nomb21);
if (resultado == 0) printf("Las cadnas son iguales\n");
else
if (resultado < 0) printf("La primera cadena es menor que la segunda\n");
else printf("La primera cadena es mayor que la segunda\n");
···
}
int comparar (char c1[], char c2[])
{ int i;
for (i=0; c1[i] == c2[i]; i++)
if (c1[i]==0) return 0; // si son iguales y su valor es cero entonces
// las cadenas son iguales
return c1[i]-c2[i]; // si son diferentes, termina el for y se devuelve
// la diferencia de los caractres desiguales
}
#include <stdio.h>En esta rutina los punteros c1 y c2 apuntan inicialmente al primer elemento del arreglo respectivo. Si los valores referenciados por c1 y c2 son iguales, se verifica si este valor es cero (0 ó '\0'), si es así se da por teminada la función y se retorna cero. Luego se desplaza los punteros c1 y c2 de modo que apunten al siguiente caracter respectivamente y el ciclo continua. En el momento que se detecte que los valores referenciados son diferentes, se corta el for y se devuelve la diferencia de los valores referenciados.
int comparar (char *, char *);
int main (void)
{ char nomb1[30], nomb2[30];
int resultado;
···
}
int comparar (char *c1, char *c2)
{ for ( ; *c1 == *c2; c1++, c2++) if (!*c1) return 0;
return *c1 - *c2;
}
BIBLIOTECA DE FUNCIONES string.h
Todos los compiladores de C implementan una biblioteca de funciones que permite, de una manera sencila, la manipulación de cadanas de caracteres. Estas funciones trabajan con las cadenas de la misma manera que lo hemos hecho en este capítulo, es decir manipulando caracter por caracter cada uno de los elementos del arreglo. A continuación se muestran algunas de las funciones más comunes:Función |
Prototipo |
Significado |
strlen |
int strlen(const char *cad); |
Devuelve el número de caracteres de la cadena "cad". No cuenta el caracteres de terminación. |
strcpy |
char *strcpy(char *destino, const char *origen); |
Copia todos los caracteres de la cadena origen en la cadena destino, incluso el caracter de terminación. |
strcmp |
int strcmp(const char *cad1, const char *cad2); |
Compara uno a uno los caracteres de ambas cadenas hasta completarlos todos o hasta encontrar una diferencia. |
strcat |
char *strcat(char *destino, const char *origen); |
Agrega una copia de la cadena origen al final de la cadena destino. |
strstr |
char *strstr(const char *cad1, const char *cad2); |
Busca la primera ocurrencia de la cadena "cad2" en la cadena "cad1". |
strchr |
char *strchr(char *cad, char c); |
Busca la primera ocurrencia del ccaracter contenido en la variable "c". |
strrchr |
char *strrchr(char *cad, char c); |
Busca la última ocurrencia del ccaracter contenido en la variable "c". |
strpbrk |
char *strpbrk(const char *cad1, const char *cad2); |
Busca la primera ocurrencia de cualquier caracter de la cadena "cad2" en la cadena "cad1". |
strupr |
char *strupr(char *cad); |
Convierte las letras contenidas en la cadena "cad" en mayúsculas. |
strlwr |
char *strlwr(char *cad); |
Convierte las letras contenidas en la cadena "cad" en minúsculas. |
strrev |
char *strrev(char *cad); |
Invierte los caracteres contenidos en la cadena "cad". |
Ejemplo:
El siguiente ejemplo muestra cómo se manejan algunas de estas funciones:
/* Este programa pretende realizar las operaciones de "buscar y reeeplazar" que tienen los procesadores de palabras. El programa lee de la entrada estándar una cadena a buscar y una cadena que va a reemplazar, luego lee un texto, una línea por vez, si la cadena buscada se encuentra en la línea, se reemplaza por segunda cadena tantas veces como se encuentre. Suponer que las líneas nunca superarán los 100 caracteres. */ #include<stdio.h> #include<string.h> void reemplazar(char *, char *, char *); void main (void) { char cadBusc[20], cadReem[20]; char linea[100]; printf("Ingrese la cadena buscada : "); gets(cadBusc); printf("Ingrese la cadena de reemplazo: "); gets(cadReem); // Buscamos y reemplazamos en el texto while (gets(linea)) // sale cuando encuentra el final del archivo { reemplazar(linea, cadBusc, cadReem); puts(linea); } } void reemplazar(char *linea, char *cadBus, char *cadReem) { char *ptLinea=linea, *pos, aux[100]; // el puntero ptLinea servirá para buscar varias ocurrencias // en la cadena. Indica el punto de partida de la búsqueda while (1) { pos = strstr(ptLinea,cadBus); if (pos==NULL) return; *pos=0; //pongo un caracter de terminación al inicio de la cadena encontrada strcpy(aux,linea); // copio sólo la parte izquierda de la cadena strcat(aux,cadReem); // agrega a "aux" la cadena de reeplazo strcat(aux,pos+strlen(cadBus)); // copio la parte derecha de la cadena strcpy(linea,aux); // copio en "linea" la cadena modificada ptLinea= pos+strlen(cadReem); // desplazo el puntero para permitir ubicar una // nueva ocurrencia } }
![]() |
![]() ![]() |