DMarlon Studio

Lección 4 · 4 de 20

Cadenas a fondo · C

Trocee líneas con strtok, construya textos con snprintf sin desbordar el búfer y copie con strncpy de forma segura en C, con strchr y strstr.

C · Cadenas a fondo en DMarlon Studio: el código del ejemplo y su salida en la terminal

`strtok` parte una línea en campos. La primera llamada recibe la cadena y los separadores (";"); las siguientes reciben NULL para seguir donde se quedó, hasta que devuelve NULL. Funciona escribiendo '\0' encima de cada separador: por eso line es un array modificable y, al terminar, line solo contiene "Ana Lopez". Nunca la use sobre una cadena literal.

`snprintf` escribe con formato, como printf, pero en un búfer y sin pasar nunca de su tamaño: siempre termina el texto con '\0'. Devuelve cuántos caracteres habría necesitado; si ese número es mayor o igual que sizeof badge, el texto se ha cortado, como le pasa a "Maximiliano Fernandez".

`strncpy` copia como mucho n caracteres, pero si el origen es más largo no añade el `'\0'` final. La forma segura es copiar sizeof code - 1 caracteres y poner el terminador a mano en la última posición. Así code queda en "IB3170".

`strchr` busca un carácter y `strstr`, una subcadena; las dos devuelven un puntero a lo encontrado o NULL. dash + 1 es la cadena que empieza justo después del primer guion: la ruta MAD-BCN.

strtok guarda su posición en una variable interna, así que no se pueden trocear dos cadenas a la vez. Para eso existe strtok_r en POSIX y strtok_s en Windows.

Código · main.c

#include <stdio.h>#include <string.h>int main(void) {    // strtok splits a line into fields. It writes '\0' over each separator,    // so it needs a modifiable array, never a string literal.    char line[] = "Ana Lopez;Madrid;34;Engineer";    int i = 0;    for (char *field = strtok(line, ";"); field; field = strtok(NULL, ";"))        printf("Field %d: %s\n", i++, field);    printf("line is now just \"%s\"\n", line);    // snprintf never writes past the buffer and returns the length it needed.    const char *names[] = {"Ana", "Maximiliano Fernandez"};    for (int k = 0; k < 2; k++) {        char badge[16];        int needed = snprintf(badge, sizeof badge, "Hi, %s!", names[k]);        printf("Badge \"%s\" needed %d chars: %s\n", badge, needed,               needed < (int)sizeof badge ? "fits" : "truncated");    }    // strncpy does not add '\0' when the source is too long: add it yourself.    const char *flight = "IB3170-MAD-BCN";    char code[7];    strncpy(code, flight, sizeof code - 1);    code[sizeof code - 1] = '\0';    printf("Flight code: %s (%zu chars)\n", code, strlen(code));    // strchr and strstr search inside a string and return a pointer.    const char *dash = strchr(flight, '-');    printf("Route: %s, has MAD: %s\n", dash + 1, strstr(flight, "MAD") ? "yes" : "no");    return 0;}

Salida · cc main.c -o main && ./main

Field 0: Ana Lopez
Field 1: Madrid
Field 2: 34
Field 3: Engineer
line is now just "Ana Lopez"
Badge "Hi, Ana!" needed 8 chars: fits
Badge "Hi, Maximiliano" needed 26 chars: truncated
Flight code: IB3170 (6 chars)
Route: MAD-BCN, has MAD: yes

Para recordar

  • strtok modifica la cadena: use un array, no un literal.
  • snprintf nunca desborda y devuelve la longitud que necesitaba.
  • Tras strncpy, ponga usted el '\0' final.
  • strchr y strstr devuelven un puntero o NULL.

Ejercicio

Trocee la línea "Madrid,Sevilla,,Bilbao" con strtok y fíjese en qué pasa con el campo vacío; después construya con snprintf una lista "Madrid / Sevilla / Bilbao" en un búfer de 20 caracteres y diga si se ha cortado.