Tabla de Contenidos
Strings
C no posee un tipo de datos para los strings como es el caso de String en Java. En C los strings corresponden a arreglos de caracteres o punteros a caracteres que por convención deben terminar con un byte en 0.
Por ejemplo:
char *s= "hola"; char r[]= {'h', 'o', 'l', 'a', 0}; char t[81]= { 0 };
Tanto r como s representan el mismo string. El diagrama es el siguiente:
La única diferencia es que el string “hola” queda almacenado en un área del proceso que no permite escribirla.
s[0]= 'H'; /* segmentation fault en muchas plataformas */ r[0]= 'H'; /* correcto! */
Funciones para manipular strings
Hay varias funciones que permiten manipular strings:
Nombre | Ejemplo | Descripción |
---|---|---|
strlen | int l= strlen(“hola”); | calcula el largo de un string |
strcmp | strcmp(fuente, “hola”); | compara 2 strings entregando < 0, 0 o > 0 |
strncmp | strncmp(fuente, “hola”, n); | compara hasta n caracteres |
strcpy | strcpy(dest, fuente); | copia el string fuente en dest |
strncpy | strncpy(dest, fuente, n); | copia a lo más n caracteres de fuente en dest |
strcat | strcat(dest, fuente); | agrega el string fuente al string dest |
- La función strcmp entrega < 0 si el primer argumento es lexicográficamente menor que el segundo, 0 si son iguales y > 0 si es mayor.
- La función strncmp es similar solo que compara hasta n caracteres.
- Antes de invocar strcpy y strcat se debe reservar suficiente memoria en dest para almacenar el resultado.
- En el caso de strncpy, se debe reservar exactamente n caracteres. Si
strlen(fuente)>=n
entonces dest no termina en 0. - Estas funciones retornan dest para que se puedan hacer varias invocaciones en una sola instrucción:
strcat( strcat ( strcpy (t, "hola"), " que"), " tal"); /* t queda en "hola que tal" */
Ejemplos
Las siguientes son implementaciones ultra compactas de strlen y strcpy:
int strlen(char *s) { char *r= s; while (*r++) ; return r-s-1; } char *strcpy(char *d, char *s) { char *t= d; while (*t++ = *s++) ; return d; }
Ejercicio 1
Resuelva la pregunta 1 del control 1 del semestre Otoño de 2014. Pruebe su solución con el archivo subst.zip. Implemente su solución en el archivo substituir.c. Compílelo con make y ejecútelo. El programa le dirá si su solución satisface todos los tests del enunciado.
Desplegar texto en la salida estándar
Una de las funciones más usadas en C es printf, que significa print formatted. Se usa de la siguiente forma: printf( formato, argumento1, argumento2, …). En donde formato es un string que incluye órdenes de reemplazo del estilo %d, %s, %c. Normalmente los caracteres del formato se copian literalmente en la salida estándar pero cuando se encuentra una orden de reemplazo entonces se estrae secuencialmente uno de los argumentos y se envía a la salida estándar. Por ejemplo:
int x= 5; char c= '*'; char *s= "hola"; printf("x= %d c= %c s= %s\n", x, c, s); /* envía: x= 5 c= * s= hola */
El caracter '\n' (léase backslash n) es un caracter de control que significa cambio de línea.
En Unix Ud. puede obtener una detallada documentación (aunque críptica) de una función en C mediante el comando man de Unix:
% man 3 printf
También existen estas variantes:
función | ejemplo | descripción |
---|---|---|
fprintf(file, formato, …) | fprintf(stderr, “error %d\n”, errno()); | envía al archivo file |
sprintf(string, formato, …) | char t[80]; sprintf(t, “%d\n”, i); | escribe en el string t |
- La variable stderr corresponde a la salida estándar de errores. stdin corresponde a la entrada estándar y stdout a la salida estándar.
- En el caso de escribir en un string, es reponsabilidad del progrador reservar suficiente espacio en el string.
Ejemplo
El siguiente programa convierte los números en hexadecimal de la línea de comandos a decimal:
#include <stdio.h> int hex2i(char *s) { int v= 0; while (*s) { switch (*s) { case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : v = v*16 + *s-'0'; break; case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' : v= v*16 + *s-'a'+10; break; default: printf("Error en el caracter %c\n", *s); } s++; } return v; } int main(int argc, char **argv) { int k; for (k= 1; k<argc; k++) { printf("%d\n", hex2i(argv[k])); } return 0; }
- Llame a su archivo hex.c
- Compile con: gcc hex.c -o hex
- Ejecute con: ./hex 5 a f 10 1ea
- o también: ./hex g
- Cuando se lanza un programa, los argumentos de la línea de comandos se reciben en argv.
- El número de argumentos se recibe en argc.
- argv[0] siempre corresponde al nombre del ejecutable.
Ejercicio 2
Programe la función que lleva un string a letras mayúsculas. Por ejemplo:
int main() { char str[80]; strcpy(str, "el numero pi es 3.14"); mayusculas(str); printf("%s\n", str); /* despliega EL NUMERO PI es 3.14 */ return 0; }
Leer de la entrada estándar
Se pueden usar estas funciones:
función | ejemplo | descripción |
---|---|---|
getchar() | char c= getchar(); | Lee un caracter |
gets(dest) | gets(t); | Lee una línea terminada en '\n' |
fgets(dest, max, file) | fgets(t, 80, stdin); | Lee una línea terminada en '\n' de file |
scanf(formato, arg1, …) | fscanf(“%d”, &i); | Lee datos de la entrada estándar |
Observación: gets
no recibe como parámetro el tamaño del arreglo de caracteres en donde se deja el resultado
y por lo tanto no se debe usar para leer datos de la red o de un archivo de origen desconocido porque puede
ser blanco de ataques de gusanos o virus. Consulte en la web por buffer overflow attack. En su lugar use fgets
.
Ejercicio 3
El siguiente programa despliega la línea más larga de la entrada estándar:
#include <stdio.h> #include <string.h> #define N 1000 int main() { char lin[N], larga[N]; int largo= 0; /* nunca while (gets(lin)!=NULL) pues sería una brecha de seguridad */ while (fgets(lin, N, stdin)!=NULL) { if (strlen(lin)>largo) { strcpy(larga, lin); largo= strlen(lin); } } printf("%s\n", larga); return 0; }
¡Cuidado! este código no funciona:
char *larga; ... if (...) { larga= lin; ... } ...
La asignación solo involucra punteros, no los contenidos.