string.h
).
char * p;Los punteros de carácter se utilizan normalmente para acceder a cadenas de caracteres, puesto que éstas están construídas tomando como base una dirección (la del primer carácter) y un marcador de fin de cadena (el carácter '\0'). La declaración de un puntero de caracter sigue las reglas habituales:
char * puntero_caracter;En este momento puntero_caracter no tiene un valor utilizable. Será precisor dárselo; esto podría hacerse en la forma siguiente:
char letra; char * puntero; puntero = &letra;y se tendrá un alias.
char cadena[LONGITUD];Así se reserva espacio para una cadena de
LONGITUD
caracteres. En C, el nombre de las listas monodimensionales equivale a la dirección del primer elemento de las mismas. Una vez que se dispone de espacio reservado para la cadena, se puede construir un puntero de la cadena empleando las sentencias siguientes:
char * p; char cadena[LONGITUD]; p = cadena;/* Esto equivale, desde luego, a poner: */ p = &cadena[0];Esto dará lugar a que en
p
se almacene la dirección de
cadena
; no es un error de asignación, por cuanto no se intenta almacenar una cadena en un carácter, sino que se asigna el valor de la dirección de un carácer a una variable de tipo puntero de
char
. Esto no pasaría de ser un alias de la cadena... pero suceden cosas interesantes, como puede verse a continuación. Tipo_base lista[NUMERO_DE_ELEMENTOS]; Tipo_base *p, *q; p = lista;y veamos a continuación la forma en que funciona la aritmética de punteros. Se admite la suma de números enteros (positivos o negativos) a un puntero. esto es, se admiten expresiones de la forma
q = p + 1;El resultado de estas operaciones es otro puntero de igual tipo. La dirección almacenada en el puntero nuevo es, como siempre, un número. Podría pensarse que al sumar 1 a un puntero se consigue otro puntero tal que el valor numérico del mismo es igual al valor numérico de la primera dirección incrementado en una unidad. Y de hecho, así sucede cuando se trata de un puntero de char, o de algún tipo base cuya extensión sea de un byte.
sizeof(Tipo_base)
. Entonces, al sumar
i
a un puntero se tiene que la dirección obtenida al calcular
p+i
tiene el valor
direccion_de_p + i*sizeof(Tipo_base)
. Se ha obtenido un nuevo puntero, que señala una posición de memoria que correspondería a un elemento de una lista situado
i
posiciones más alla del elemento señalado por
p
.
char
entonces al sumar 1 a
p
se obtiene una dirección cuyo valor aumenta en 1 ( =
sizeof(char)
) respecto a la dirección de
p
. En general, comprobar que al sumar
i
a
p
(al calcular
p+i
) se incrementa el valor de
p
en
i*sizeof(char)
. #include<stdio.h> int main(int argc, char * argv[]) { char letra; char * p = &letra, *q; int i; unsigned long base; printf("La dirección de letra es %u\n", (unsigned int)p); q = p + 1; printf("La dirección dada por q = p + 1 es %u\n", (unsigned int)q); q = p + 2; printf("La dirección dada por q = p + 2 es %u\n", (unsigned int)q); q = p + 3; printf("La dirección dada por q = p + 3 es %u\n", (unsigned int)q); q = p + 4; printf("La dirección dada por q = p + 4 es %u\n", (unsigned int)q); printf("Escriba el valor de i: "); scanf("%d", &i); q = p + i; printf("q = p + %d vale %u\n", i, (unsigned int)q); base = (unsigned long)p; printf("El valor calculado es: %u\n",base + i*sizeof(char)); return 0; } /* La dirección de letra es 3221224104 La dirección dada por q = p + 1 es 3221224105 La dirección dada por q = p + 2 es 3221224106 La dirección dada por q = p + 3 es 3221224107 La dirección dada por q = p + 4 es 3221224108 Escriba el valor de i: 5 q = p + 5 vale 3221224108 */
doble
almacenada en
p
, y luego los valores de las direcciones obtenidas al calcular
p+1
,
p+2
, etc., se observa que difieren 1 entre sí. Esto es precisamente lo que se quería poner de manifiesto: si se suma 1 al puntero, se obtiene una dirección situada 1 bytes más allá, porque el tamaño de la variable señalada (
char
) es 1. En otras palabras, el puntero p se comporta como si señalara el primer elemento de una lista de
char
.
p
es un puntero de
double
entonces al sumar 1 a
p
se obtiene una dirección cuyo valor aumenta en 8 ( =
sizeof(double)
) respecto a la dirección de
p
. En general, comprobar que al sumar
i
a
p
(al calcular
p+i
) se incrementa el valor de
p
en
i*sizeof(double)
. #include<stdio.h> int main(int argc, double * argv[]) { double doble; double * p = &doble, *q; int i; unsigned long base; printf("La dirección de doble es %u\n", (unsigned int)p); q = p + 1; printf("La dirección dada por q = p + 1 es %u\n", (unsigned int)q); q = p + 2; printf("La dirección dada por q = p + 2 es %u\n", (unsigned int)q); q = p + 3; printf("La dirección dada por q = p + 3 es %u\n", (unsigned int)q); q = p + 4; printf("La dirección dada por q = p + 4 es %u\n", (unsigned int)q); printf("Escriba el valor de i: "); scanf("%d", &i); q = p + i; printf("q = p + %d vale %u\n", i, (unsigned int)q); base = (unsigned long)p; printf("El valor calculado es: %u\n",base + i*sizeof(double)); return 0; } /* La dirección de doble es 3221224104 La dirección dada por q = p + 1 es 3221224112 La dirección dada por q = p + 2 es 3221224120 La dirección dada por q = p + 3 es 3221224128 La dirección dada por q = p + 4 es 3221224136 Escriba el valor de i: 5 q = p + 5 vale 3221224136 */
doble
almacenada en
p
, y luego los valores de las direcciones obtenidas al calcular
p+1
,
p+2
, etc., se observa que difieren 8 entre sí. Esto es precisamente lo que se quería poner de manifiesto: si se suma 1 al puntero, se obtiene una dirección situada 8 bytes más allá, y no 1. En otras palabras, el puntero p se comporta como si señalara el primer elemento de una lista de números
double
. Al incrementar el puntero, éste hace las veces de índice de la lista. No acaba aquí la cosa. Considérense las declaraciones siguientes
Tipo_base lista[NUMERO_DE_ELEMENTOS]; Tipo_base *p, *q; p = lista;Acabamos de observar que p+i es la dirección de un elemento situado i posiciones más allá de p, donde el tamaño de las posiciones es, a efectos prácticos, el tamaño del Tipo_base medido en bytes. Entonces, a la vista de las declaraciones anteriores, se tiene que ocurre lo siguiente:
p tiene el valor &lista[0]; p + 1 tiene el valor &lista[1]; p + 2 tiene el valor &lista[2];y, en general
p + i tiene el valor &lista[i];Dicho con palabras, dado un puntero de Tipo_base cuyo valor es la dirección del primer elemento de una lista, al sumar i al puntero se obtiene la dirección del elemento i-ésimo de la lista. Ahora, bien, según se recordará, el asterisco puede hacer las veces de operador de indirección, esto es, se puede anteponer un asterisco a un puntero, y el resultado es la variable señalada. Entonces, aplicando el operador asterisco, se obtiene lo siguiente:
*p tiene el valor lista[0]; *(p + 1) tiene el valor lista[1]; *(p + 2) tiene el valor lista[2];y, en general
*(p + i) tiene el valor lista[i];en donde
*(p+i) equivale a lista[i]. Esto significa que diponer de una lista y disponer de un puntero de su primer elemento es completamente equivalente, porque nos permite acceder indistintamente a los elementos de la lista empleando el nombre de ésta o el puntero.
[]
es otra forma de aplicar un índice y deshacer una indirección, esto es, se tiene la siguiente equivalencia:
p[i] equivale a *(p+i)Entonces podemos escribir lo siguiente, para cualquier valor de i:
p[i] equivale a lista[i]
El resultado final es que si se tiene un puntero de una lista entonces es posible acceder a los elementos de la lista empleando el puntero con un índice, y esto equivale a usar la aritmética de punteros mencionada. |
int * p;entonces se puede aplicar al puntero el operador corchetes con un índice, y efectuar operaciones con
p
como si se tratase de una lista, en la forma
p[i] = 33;Hasta aquí, todo bien. Pero hay un problema: nada garantiza que un puntero (sea cual fuere su tipo) señala un bloque de memoria correspondiente a una lista. Podría muy bien ser, en este caso, que se tuviera
int q; p = &q;
p[i]
, que sintácticamente es correcta y admisible totalmente por el compilador, carecería por completo de sentido, sin ser detectada. La expresión
p[i]
denotaría un
inexistente
entero situado
i
posiciones más allá de
p
. Esto es una catástrofe en potencia y renovamos nuestra indicación, hecha anteriormente: siempre que se declara un puntero, conviene asignarle el valor
NULL
. De este modo, todo intento de acceder a la(s) variable(s) que señala se detectará de inmediato.
string.h
).
string.h
contiene las descripciones de toda una gama de funciones adecuadas para la manipulación de cadenas. Véase a continuación una breve descripción de estas funciones (se hallará un listado menos extenso
aquí
.
void bcopy(const void *src, void *destino, size_t num)
|
Sirve para copiar
num
bytes de la cadena señalada por
src
en la cadena señalada por
destino
. Se admite el solapamiento de la cadena de origen y de destino.
|
void * memchr(const void *b, int c, size_t num)
|
Esta función busca el
unsigned char
que se le proporciona en
c
dentro de la cadena señalada por
b
. Si el carácter aparece entre los
num
primeros, se devuelve un puntero del carácter en cuestión. Si no consta entre ellos, se devuele el puntero
NULL
.
|
int memcmp(const void *b1, const void *b2, size_t num)
|
Esta función sirve para comparar cadenas, suponiendo que ambas tienen
num
bytes de longitud. Si las cadenas son iguales byte por byte, la función proporciona el valor cero. En caso contrario, se devuelve la diferencia entre los dos primeros bytes que sean distintos (tomados como
unsigned char
). Dos cadenas nulas son siempre idénticas.
|
void * memcpy(void *destino, const void *src, size_t num)
|
Sirve para copiar
num
bytes de la cadena señalada por
src
en la cadena señalada por
destino
. Si las cadenas se solapan puede haber problemas, así que es preferible utilizar
bcopy()
.
|
void * memmove(void *destino, const void *src, size_t num)
|
Sirve para copiar
num
bytes de la cadena señalada por
src
en la cadena señalada por
destino
. Se admite el solapamiento de la cadena de src y de destino. La función proporciona el valor original de
destino
.
|
void * memset(void *b, int c, size_t num)
|
Esta función escribe el
unsigned char
dado en
c
en la cadena señalada por
b
;
c
se repite tantas veces como se indique en
num
|
char * strcat(char *primera, const char *segunda)
|
Esta función añade la cadena señalada por
segunda
al final de la cadena señalada por
primera
, y después añade un '\0' para marcar el fin de cadena. La cadena señalada por
primera
debe disponer de espacio suficiente para almacenar el resultado de la concatenación.
|
char * strchr(const char *s, int c)
|
Esta función busca la primera aparición del carácter c en la cadena
s
. Si lo encuentra, proporciona un puntero del carácter; en caso contrario, proporciona el puntero nulo. Se considera que el '\0' final forma parte de la cadena, y es posible buscarlo dando a
c
el valor '\0'.
|
int strcmp(const char *s1, const char *s2)
|
Esta función efectúa una comparación lexicográfica de las cadenas
s1
y
s2
, que se suponen dotadas de la marca de fin de cadena '\0'. La función proporciona un valor entero mayor, igual o menor que cero según
s1
sea mayor, igual o menor que
s2
.
|
int strncmp(const char *s1, const char *s2, size_t num)
|
Esta función efectúa una comparación lexicográfica de las cadenas
s1
y
s2
, que se suponen dotadas de la marca de fin de cadena '\0'. La función proporciona un valor entero mayor, igual o menor que cero según
s1
sea mayor, igual o menor que
s2
. La función compara un máximo de
num
caracteres.
|
char * strcpy(char *destino, const char *src)
|
Esta función copia la cadena
src
en la cadena
destino
, incluyendo el marcador de fin de cadena '\0'.
|
char * strncpy(char *destino, const char *src, size_t num)
|
Esta función copia la cadena
src
en la cadena
destino
, incluyendo el marcador de fin de cadena '\0' si la cadena src contiene menos de
num
caracteres. Si hay más de
num
caracteres, no se añade el marcador de fin de cadena.
|
int strcoll(const char *s1, const char *s2)
|
Esta función proporciona un número positivo, nulo o negativo según
s1
sea lexicográficamente manor, igual o menor que
s2
. Se respeta la secuencia de clasificación impuesta por el
locale
aplicado.
|
size_t strcspn(const char *s, const char *conjunto)
|
Esta función indica la posición del primer carácter de
s
que no consta en la cadena señalada por
conjunto
. Se proporciona como resultado el número de caracteres de
s
, empezando por el principio, que hay que saltar hasta llegar a un carácter que no esté en
conjunto
.
|
size_t strlen(const char *s)
|
Esta función proporciona el número de caracteres de que consta la cadena señalada por
s
.
|
char * strncat(char *s, const char *append, size_t num)
|
Esta función añade la cadena señalada por
segunda
al final de la cadena señalada por
primera
, y después añade un '\0' para marcar el fin de cadena. La cadena señalada por
primera
debe disponer de espacio suficiente para almacenar el resultado de la concatenación. Como máximo, se añaden
num
caracteres.
|
char * strpbrk(const char *s, const char *conjunto)
|
Esta función busca en la cadena señalada por
s
, que se suponer dotada del carácter de terminación '\0', la primera aparición de un carácter presente en
conjunto
. Si encuentra uno de estos caracteres, proporciona su puntero; si no lo encuentra, proporciona el puntero
NULL
.
|
char * strchr(const char *s, int c)
|
Esta función busca el carácter dado en c en la cadena señalada por
s
. Si existe, proporciona su puntero; si no existe, proporciona el puntero
NULL
.
|
size_t strspn(const char *s, const char *conjunto)
|
Esta función proporciona el número de caracteres, contados desde el principio de
s
, que se encuentran entre los caracteres indicados en
conjunto
. Se supone que
s
está dotada del marcador de fin de cadena, '\0'.
|
char * strstr(const char *grande, const char *pequeña)
|
Esta función busca la cadena
pequeña
en la cadena
grande
. Si la encuentra, proporciona el puntero de
pequeña
dentro de
grande
. Si no la encuentra, proporciona el puntero
NULL
. Si la cadena
pequeña
está vacía, la función proporciona el puntero
grande
.
|
char * strtok(char *str, const char *sep)
|
Esta función va proporcionando uno tras otro los grupos de caracteres separados por algún carácter de los indicados por sep. La primera llamada a
strtok()
debe aportar la cadena estudiada en el primer argumento; las siguientes deben tener el valor
NULL
en ese argumento. Cuando no quedan ya más grupos de caracteres,
strtok()
proporciona el valor
NULL
. Esta función es ideal para analizar archivos de texto de formato delimitado. Véase también
strsep()
.
|
size_t strxfrm(char *destino, const char *src, size_t n)
|
Esta función sirve para transformar la cadena dada por
src
en una cadena tal que la comparación de esta nueva cadena mediante
strcmp()
produciría los mismos efectos que
strcoll()
, respetando por tanto los valores de de
LC_COLLATE
proporcionados por el
locale
en vigor.
|
/* Este programa muestra el uso de punteros elementales de cadenas. */ #include <stdio.h> #include <stdlib.h> #include <string.h> char cadena[80] = "Un ejemplo de cadena."; char * puntero_cadena = cadena; int i; int main(void) { printf("Cadenas de caracteres.\n\n"); printf("Espacio reservado para cadena : %d\n",sizeof(cadena)); printf("Espacio ocupado dentro de cadena : %d\n",strlen(cadena)); printf("La dirección de cadena es : %u\n",(unsigned int)cadena); printf("El valor de puntero_cadena es : %u\n",(unsigned int)puntero_cadena); printf("El contenido de cadena es : %s\n",cadena); printf("La cadena que señala puntero_cadena es : %s\n", puntero_cadena); printf("El cuarto elemento es : %c\n", *(cadena+3)); printf("El cuarto elemento es : %c\n", *(puntero_cadena+3)); printf("El cuarto elemento es : %c\n", cadena[3]); printf("El cuarto elemento es : %c\n", puntero_cadena[3]); printf("La cadena contiene : %s\n",cadena); printf("La cadena contiene : "); while(*puntero_cadena) printf("%c",*puntero_cadena++); printf("\n"); printf("La cadena contiene : "); for(i=0;i<strlen(cadena);i++) printf("%c",cadena[i]); printf("\n"); puntero_cadena = cadena; /* Esencial! */ printf("La cadena contiene : "); for(i=0;i<strlen(cadena);i++) printf("%c",*(puntero_cadena+i)); printf("\n"); printf("\n\nTerminación normal de programa.\n"); return 0; } /* RESULTADO Cadenas de caracteres. Espacio reservado para cadena : 80 Espacio ocupado dentro de cadena : 21 La dirección de cadena es : 97292840 El valor de puntero_cadena es : 97292840 El contenido de cadena es : Un ejemplo de cadena. La cadena que señala puntero_cadena es : Un ejemplo de cadena. El cuarto elemento es : e El cuarto elemento es : e El cuarto elemento es : e El cuarto elemento es : e La cadena contiene : Un ejemplo de cadena. La cadena contiene : Un ejemplo de cadena. La cadena contiene : Un ejemplo de cadena. La cadena contiene : Un ejemplo de cadena. Terminación normal de programa. */
int
).