Em C, strings são arrays de caracteres terminados por '\0'. A biblioteca <string.h> oferece funções para manipular essas sequências de forma eficiente. Nesta aula, estudaremos as mais comuns: strlen, strcpy, strcat, strcmp e suas versões com limite de tamanho (strncpy, strncat, strncmp). Também veremos os riscos de buffer overflow e como evitá-los.

Dominar essas funções é essencial para programar em C com segurança e eficiência, especialmente em sistemas embarcados e software de baixo nível.

strlen, strcpy, strcat

strlen retorna o comprimento de uma string (sem contar o '\0'). strcpy copia uma string para outra, e strcat concatena (anexa) uma string ao final de outra. Todas esperam que o destino tenha espaço suficiente.

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello";
    char dest[20];
    
    size_t len = strlen(src); // len = 5
    printf("Comprimento: %zu\n", len);
    
    strcpy(dest, src); // dest = "Hello"
    printf("Cópia: %s\n", dest);
    
    strcat(dest, " World"); // dest = "Hello World"
    printf("Concatenação: %s\n", dest);
    
    return 0;
}

No exemplo, dest tem 20 bytes, o suficiente para a concatenação. Se fosse menor, ocorreria buffer overflow.

strcmp

strcmp compara duas strings lexicograficamente (valor ASCII). Retorna 0 se iguais, negativo se a primeira é menor, positivo se maior.

#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple";
    char str2[] = "banana";
    int result = strcmp(str1, str2);
    if (result < 0) printf("%s vem antes de %s\n", str1, str2);
    else if (result > 0) printf("%s vem depois de %s\n", str1, str2);
    else printf("Iguais\n");
    return 0;
}

Para comparação parcial ou insensível a maiúsculas, use strncmp ou strcasecmp (POSIX).

strncpy e segurança

As funções strncpy, strncat e strncmp recebem um parâmetro de tamanho máximo para evitar estouro de buffer. strncpy copia no máximo n caracteres; se a origem for menor, preenche o resto com '\0'. Se for maior, não adiciona o terminador nulo — cuidado!

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, world!";
    char dest[6];
    strncpy(dest, src, 5);
    dest[5] = '\0'; // necessário!
    printf("%s\n", dest); // "Hello"
    
    // strncat
    char dest2[20] = "Hello";
    strncat(dest2, " World", 10);
    printf("%s\n", dest2);
    
    // strncmp
    int cmp = strncmp("abcde", "abcxy", 3); // compara 3 chars: 0
    printf("%d\n", cmp);
    return 0;
}

Boa prática: sempre garantir que a string destino seja terminada em nulo após strncpy. Prefira snprintf para cópia segura.

Buffer overflow

Buffer overflow ocorre quando se escreve além do limite de um array. As funções strcpy e strcat são vulneráveis. Exemplo clássico:

char buffer[10];
strcpy(buffer, "Esta string é muito longa!"); // overflow!

Isso corrompe a memória adjacente, podendo causar falhas ou brechas de segurança (como em ataques de injeção). Para evitar:

  • Use strncpy e strncat com o tamanho correto.
  • Use snprintf para formatar strings com limite.
  • Em C moderno, considere funções como strlcpy (não padrão, mas disponível em alguns sistemas).
  • Sempre verifique o espaço disponível antes de copiar.

Boas práticas

  • Sempre inicializar buffers com char buffer[100] = {0}; ou usar memset.
  • Preferir funções com limite de tamanho (n versões).
  • Usar sizeof para obter o tamanho do array (quando aplicável).
  • Evitar gets (obsoleto); usar fgets.

Referências

Exercícios

  1. Escreva uma função que receba duas strings e retorne 1 se a primeira contém a segunda (substring), 0 caso contrário. Use apenas funções de string.h.
  2. ✓ Resposta:
    #include <string.h>
    int contains(const char *str, const char *sub) {
        return strstr(str, sub) != NULL;
    }
  3. Dado char s1[20] = "Hello"; e char s2[20] = "World";, use strncpy e strncat para obter "HelloWorld" em s1. Garanta que não haja overflow.
  4. ✓ Resposta:
    char s1[20] = "Hello";
    char s2[20] = "World";
    // s1 já tem "Hello", queremos concatenar "World"
    // strncat já cuida do terminador
    strncat(s1, s2, sizeof(s1) - strlen(s1) - 1);
    // ou, se quiser copiar primeiro:
    // char temp[20];
    // strncpy(temp, s1, sizeof(temp)-1);
    // temp[sizeof(temp)-1]='\0';
    // strncat(temp, s2, sizeof(temp)-strlen(temp)-1);
    // mas o exercício pede em s1, então concatenar diretamente é válido.
  5. Explique por que strncpy(dest, src, n) pode não terminar a string com '\0'. Dê um exemplo.
  6. ✓ Resposta: strncpy copia no máximo n caracteres. Se a string origem for maior ou igual a n, ela não adiciona o '\0' no final, pois já usou todos os n bytes. Exemplo: char src[]="abcde"; char dest[3]; strncpy(dest, src, 3); → dest contém 'a','b','c' sem '\0'. Isso pode causar comportamento indefinido se dest for usada como string.
  7. Qual a diferença entre strcmp e strncmp? Mostre com um exemplo.
  8. ✓ Resposta: strcmp compara toda a string até o '\0', enquanto strncmp compara apenas os primeiros n caracteres. Exemplo: strcmp("abcde", "abcxy") retorna negativo (pois 'd' < 'x'), mas strncmp("abcde", "abcxy", 3) retorna 0 (os 3 primeiros são iguais).
  9. Escreva um programa que leia uma string do usuário (use fgets) e a imprima de trás para frente usando apenas funções de string.h.
  10. ✓ Resposta:
    #include <stdio.h>
    #include <string.h>
    
    int main() {
        char str[100];
        printf("Digite uma string: ");
        fgets(str, sizeof(str), stdin);
        str[strcspn(str, "\n")] = '\0'; // remove newline
        size_t len = strlen(str);
        for (size_t i = len; i > 0; i--) {
            putchar(str[i-1]);
        }
        putchar('\n');
        return 0;
    }