Herramientas de usuario

Herramientas del sitio


strings

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.

strings.txt · Última modificación: 2015/03/31 09:50 por lmateu