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)>=nentonces 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.
