C string.h

Esta é a página de consulta rápida do <string.h>, a biblioteca de funções para texto (as str…) e para blocos de memória (as mem…). Aqui estão todas, em tabelas: o que cada uma faz, o que devolve, um exemplo com a saída real e a aula onde ela é explicada. Para aprender com calma, veja as aulas Strings, Funções de String e Ponteiros e Strings.

Todas as saídas foram produzidas de verdade: no gcc 15.2 da máquina da Ana (Linux de 64 bits, pasta ~/c/ref, comando gcc -std=c23 -Wall -Wextra) e no editor do guia (Clang em WebAssembly). Quando os dois diferem, a tabela diz.

Atalhos: Antes de tudo · Tamanho, cópia e junção · Comparar · Procurar e dividir · Blocos de memória · strerror · Qual usar · Editor × gcc · Erros comuns · Experimente


Antes de tudo: três regras

Uma string é um array de char que termina em '\0'
Toda função str… anda pelo texto até achar o '\0' (o caractere de código zero). Sem ele, a função continua lendo a memória que vem depois. Aula: Strings.
Nenhuma função sabe o tamanho do seu array
Elas recebem só um ponteiro para o primeiro caractere (aula Ponteiros e Strings). Quem garante que cabe é você. Um strcpy que não cabe escreve além do fim do array, sem erro nenhum na hora.
size_t
É o tipo dos tamanhos (um inteiro sem sinal). Mostre com %zu: printf("%zu", strlen(nome)). Aula: sizeof.

Nas tabelas, d é o destino (onde a função escreve), o é a origem (de onde ela lê), s é uma string e n é um número de bytes.

Tamanho, cópia e junção

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

int main(void) {
    char nome[20] = "Ana";
    printf("strlen=%zu sizeof=%zu\n", strlen(nome), sizeof nome);
    char copia[20];
    strcpy(copia, nome);
    printf("strcpy:  [%s]\n", copia);
    strcat(copia, " Souza");
    printf("strcat:  [%s]\n", copia);
    char curto[5];
    strncpy(curto, "Banana", sizeof curto - 1);
    curto[sizeof curto - 1] = '\0';
    printf("strncpy: [%s]\n", curto);
    char frase[20] = "Oi";
    strncat(frase, ", Ana Souza", 5);
    printf("strncat: [%s]\n", frase);
    char *dup = strdup("Caderno");
    char *pedaco = strndup("Caderno", 4);
    printf("strdup:  [%s] strndup: [%s]\n", dup, pedaco);
    free(dup);
    free(pedaco);
    char destino[20] = "";
    char *fim = memccpy(destino, "maçã;pera", ';', sizeof destino);
    printf("memccpy: [%.*s] copiou %td bytes\n", (int)(fim - destino), destino, fim - destino);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra copiar.c -o copiar
$ ./copiar
strlen=3 sizeof=20
strcpy:  [Ana]
strcat:  [Ana Souza]
strncpy: [Bana]
strncat: [Oi, Ana]
strdup:  [Caderno] strndup: [Cade]
memccpy: [maçã;] copiou 7 bytes

No editor, este programa não compila: a biblioteca C do editor só mostra o strndup e o memccpy com um #define _DEFAULT_SOURCE antes dos #include (veja Editor × gcc). Com essa linha, a saída é idêntica.

FunçãoO que fazDevolveExemplo → resultadoAula
strlen(s)
"string length"
Conta os bytes até o '\0' (sem contar o '\0').size_tstrlen("Ana") → 3; strlen("maçã") → 6 (o ç e o ã têm 2 bytes cada)Funções de String
strcpy(d, o)
"string copy"
Copia o para d, com o '\0'. Não confere se cabe.dstrcpy(copia, "Ana") → [Ana]Funções de String
strncpy(d, o, n)Copia no máximo n bytes. Se o é mais curta, completa com '\0' até n; se é mais longa, não põe o '\0'.dstrncpy(curto, "Banana", 4) + curto[4] = '\0' → [Bana]Segurança
strcat(d, o)
"concatenate", juntar
Acrescenta o no fim de d. d já tem de ser uma string (com '\0') e ter espaço.d"Ana" + " Souza" → [Ana Souza]Funções de String
strncat(d, o, n)Acrescenta no máximo n bytes de o e sempre põe o '\0' (por isso d precisa de strlen(d) + n + 1 bytes).dstrncat(frase, ", Ana Souza", 5) → [Oi, Ana]Funções de String
strdup(s) C23Faz uma cópia de s numa memória nova, reservada com malloc. Você dá o free.a cópia, ou NULL se faltou memóriastrdup("Caderno") → [Caderno]Strings Dinâmicas
strndup(s, n) C23Como strdup, mas copia no máximo n bytes e sempre põe o '\0'.a cópia, ou NULLstrndup("Caderno", 4) → [Cade]Strings Dinâmicas
memccpy(d, o, c, n) C23Copia bytes de o até copiar o caractere c (inclusive) ou até n bytes.o ponteiro logo depois do c em d, ou NULL se não achou cmemccpy(d, "maçã;pera", ';', 20) → copia maçã; (7 bytes)Funções de String
  • strlen × sizeof: strlen(nome) é o tamanho do texto (3); sizeof nome é o tamanho do array (20). Dentro de uma função que recebeu char *s, sizeof s é o tamanho do ponteiro (8 no gcc, 4 no editor), não do array. Aula: sizeof.
  • strlen conta bytes, não letras. Em UTF-8, cada letra acentuada ocupa 2 bytes. Aula: Acentos e UTF-8.
  • strdup e strndup existem há décadas no Linux (POSIX), mas só entraram no C padrão no C23.

Comparar

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

int main(void) {
    printf("strcmp(\"Ana\", \"Bia\") = %d\n", strcmp("Ana", "Bia"));
    printf("strcmp(\"Bia\", \"Ana\") = %d\n", strcmp("Bia", "Ana"));
    printf("strcmp(\"Ana\", \"Ana\") = %d\n", strcmp("Ana", "Ana"));
    printf("strcmp(\"ana\", \"Ana\") = %d\n", strcmp("ana", "Ana"));
    printf("strcmp(\"Ana\", \"Ana Souza\") = %d\n", strcmp("Ana", "Ana Souza"));
    printf("strncmp(\"Banana\", \"Bando\", 3) = %d\n", strncmp("Banana", "Bando", 3));
    printf("strncmp(\"Banana\", \"Bando\", 4) = %d\n", strncmp("Banana", "Bando", 4));
    int a[3] = {1, 2, 3}, b[3] = {1, 2, 4};
    printf("memcmp(a, b, sizeof a) = %d\n", memcmp(a, b, sizeof a));
    printf("strcoll(\"abacate\", \"Banana\") = %d\n", strcoll("abacate", "Banana"));
    return 0;
}
$ gcc -std=c23 -Wall -Wextra comparar.c -o comparar
$ ./comparar
strcmp("Ana", "Bia") = -1
strcmp("Bia", "Ana") = 1
strcmp("Ana", "Ana") = 0
strcmp("ana", "Ana") = 1
strcmp("Ana", "Ana Souza") = -1
strncmp("Banana", "Bando", 3) = 0
strncmp("Banana", "Bando", 4) = -3                « no editor: -1
memcmp(a, b, sizeof a) = -1
strcoll("abacate", "Banana") = 31
FunçãoO que fazDevolveExemplo → resultadoAula
strcmp(a, b)
"string compare"
Compara as duas strings, letra por letra, pelo código de cada byte (tabela ASCII).0 se iguais; negativo se a vem antes; positivo se vem depoisstrcmp("Ana", "Bia") → negativo; strcmp("ana", "Ana") → positivo ('a' = 97 vem depois de 'A' = 65)Funções de String
strncmp(a, b, n)Como strcmp, mas olha só os n primeiros bytes.idemstrncmp("Banana", "Bando", 3) → 0 (Ban = Ban)Funções de String
memcmp(a, b, n)Compara n bytes de dois blocos quaisquer (não para no '\0').idemdois arrays {1,2,3} e {1,2,4} → negativoArrays
strcoll(a, b)
"collate", ordenar
Compara seguindo as regras do idioma escolhido com setlocale. Sem setlocale, é igual ao strcmp.idemstrcoll("abacate", "Banana") → positivo (sem setlocale, minúscula vem depois)Acentos e UTF-8
strxfrm(d, o, n)Transforma o numa string que, comparada com strcmp, dá o mesmo resultado do strcoll. Raro.o tamanho que a transformação precisa(útil para ordenar muitas vezes a mesma lista)Ordenação
Teste o sinal, nunca o número

O C só garante o sinal do resultado. O número em si muda de biblioteca para biblioteca: strncmp("Banana", "Bando", 4) deu -3 no gcc ('a' − 'd') e -1 no editor. Escreva if (strcmp(a, b) < 0), nunca if (strcmp(a, b) == -1). E, para saber se são iguais, strcmp(a, b) == 0; o == entre duas strings compara endereços (veja Erros comuns).

Procurar e dividir

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

int main(void) {
    const char *email = "ana.souza@exemplo.com";
    const char *arroba = strchr(email, '@');
    printf("strchr:  [%s] posição %td\n", arroba, arroba - email);
    printf("strrchr: [%s]\n", strrchr(email, '.'));
    printf("strstr:  [%s]\n", strstr(email, "souza"));
    printf("strchr não achou: %s\n", strchr(email, '#') == NULL ? "NULL" : "achou");
    printf("strpbrk: [%s]\n", strpbrk("R$ 12,90", "0123456789"));
    printf("strspn:  %zu\n", strspn("2026-10-17", "0123456789"));
    printf("strcspn: %zu\n", strcspn("Ana\n", "\n"));
    char linha[] = "Ana\n";
    linha[strcspn(linha, "\n")] = '\0';
    printf("sem Enter: [%s]\n", linha);
    char *p = memchr("abc\0def", 'e', 7);
    printf("memchr:  [%s]\n", p);
    char lista[] = "arroz,feijão,,café";
    for (char *item = strtok(lista, ","); item != NULL; item = strtok(NULL, ",")) {
        printf("strtok:  [%s]\n", item);
    }
    printf("depois do strtok: [%s]\n", lista);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra procurar.c -o procurar
$ ./procurar
strchr:  [@exemplo.com] posição 9
strrchr: [.com]
strstr:  [souza@exemplo.com]
strchr não achou: NULL
strpbrk: [12,90]
strspn:  4
strcspn: 3
sem Enter: [Ana]
memchr:  [ef]
strtok:  [arroz]
strtok:  [feijão]
strtok:  [café]
depois do strtok: [arroz]

A saída do editor é idêntica.

FunçãoO que fazDevolveExemplo → resultadoAula
strchr(s, c)
"string character"
Procura a primeira vez que o caractere c aparece.ponteiro para ele, ou NULLstrchr(email, '@') → @exemplo.com; a posição é p - email = 9Ponteiros e Strings
strrchr(s, c)
"reverse"
Procura a última vez.ponteiro, ou NULLstrrchr(email, '.') → .comPonteiros e Strings
strstr(s, t)
"string in string"
Procura o texto t dentro de s.ponteiro para o começo do achado, ou NULLstrstr(email, "souza") → souza@exemplo.comFunções de String
strpbrk(s, lista)
"pointer break"
Procura o primeiro caractere de s que esteja na lista.ponteiro, ou NULLstrpbrk("R$ 12,90", "0123456789") → 12,90Funções de String
strspn(s, lista)
"span", extensão
Conta quantos caracteres do começo de s estão na lista.size_tstrspn("2026-10-17", "0123456789") → 4Validar a Entrada
strcspn(s, lista)
"complement span"
Conta quantos caracteres do começo de s não estão na lista.size_tstrcspn("Ana\n", "\n") → 3. O uso clássico: linha[strcspn(linha, "\n")] = '\0'; tira o Enter que o fgets deixafgets
memchr(m, c, n)Como strchr, mas olha n bytes e não para no '\0'.ponteiro, ou NULLmemchr("abc\0def", 'e', 7) → ef (passou pelo '\0')Arrays
strtok(s, seps)
"tokenize", picar em pedaços
Divide s em pedaços separados por qualquer caractere de seps. Na 1ª chamada, passe a string; nas outras, NULL. Estraga a string original (troca cada separador por '\0') e pula pedaços vazios.o próximo pedaço, ou NULL no fim"arroz,feijão,,café" → arroz, feijão, café (o vazio sumiu); depois, lista vale só arrozContador de Palavras
  • Sempre teste o NULL antes de usar o resultado de strchr, strstr etc.: printf("%s", strchr(email, '#')) com um resultado NULL é comportamento indefinido. Aula: Ponteiro Nulo.
  • strtok não funciona numa string literal (char *lista = "a,b"), porque escreve nela; use um array (char lista[] = "a,b"). Ela também guarda a posição numa variável escondida: não dá para usar strtok em duas strings ao mesmo tempo. A versão que resolve isso é a strtok_r, do POSIX: funciona direto no gcc e, no editor, com #define _DEFAULT_SOURCE antes dos #include.
Novidade do C23: strchr respeita o const

No C23, strchr, strrchr, strstr, strpbrk e memchr devolvem const char * quando recebem uma string const. Por isso, no programa acima, o resultado vai para const char *arroba. Com char *arroba = strchr(email, '@');, o gcc 15 avisa:

procurar.c:6:20: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
    6 |     char *arroba = strchr(email, '@');
      |                    ^~~~~~

O Clang do editor ainda não avisa. Aula: const e Ponteiros.

Blocos de memória: as funções mem…

As mem… trabalham com bytes, não com texto: recebem um void * (qualquer endereço; aula void*) e um número de bytes, e não ligam para o '\0'. Servem para arrays de qualquer tipo e para structs.

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

int main(void) {
    int notas[5];
    memset(notas, 0, sizeof notas);
    printf("memset 0: %d %d %d %d %d\n", notas[0], notas[1], notas[2], notas[3], notas[4]);
    memset(notas, 1, sizeof notas);
    printf("memset 1: %d\n", notas[0]);
    char senha[8] = "segredo";
    memset(senha, '*', strlen(senha));
    printf("memset '*': [%s]\n", senha);
    int origem[3] = {7, 8, 9}, copia[3];
    memcpy(copia, origem, sizeof origem);
    printf("memcpy: %d %d %d\n", copia[0], copia[1], copia[2]);
    char texto[20] = "abcdef";
    memmove(texto + 2, texto, 4);
    printf("memmove: [%s]\n", texto);
    memset_explicit(senha, 0, sizeof senha);
    printf("memset_explicit: strlen=%zu\n", strlen(senha));
    printf("strerror(ENOENT): %s\n", strerror(ENOENT));
    printf("strerror(EACCES): %s\n", strerror(EACCES));
    printf("strerror(0): %s\n", strerror(0));
    return 0;
}
$ gcc -std=c23 -Wall -Wextra memoria.c -o memoria
$ ./memoria
memset 0: 0 0 0 0 0
memset 1: 16843009
memset '*': [*******]
memcpy: 7 8 9
memmove: [ababcd]
memset_explicit: strlen=0
strerror(ENOENT): No such file or directory
strerror(EACCES): Permission denied
strerror(0): Success

No editor, o memset_explicit não existe (error: use of undeclared identifier 'memset_explicit'). Sem essa linha, o resto sai igual.

FunçãoO que fazDevolveExemplo → resultadoAula
memset(m, c, n)
"memory set"
Põe o byte c em cada um dos n bytes.mmemset(notas, 0, sizeof notas) → tudo 0. Com 1, cada int vira 16843009 (os 4 bytes valem 1: 0x01010101), não 1!Arrays
memcpy(d, o, n)
"memory copy"
Copia n bytes. Os dois blocos não podem se sobrepor.dcopia um int[3] inteiro: 7 8 9Arrays
memmove(d, o, n)
"memory move"
Como memcpy, mas funciona mesmo se os blocos se sobrepõem (copia como se usasse uma área temporária).dmemmove(texto + 2, texto, 4) em "abcdef" → ababcdArray que Cresce
memcmp(a, b, n)Compara n bytes (veja Comparar).negativo, 0 ou positivo(acima)Arrays
memchr(m, c, n)Procura um byte (veja Procurar).ponteiro, ou NULL(acima)Arrays
memset_explicit(m, c, n) C23Como memset, mas o compilador é proibido de apagá-lo na otimização. Para limpar senhas e chaves da memória.mmemset_explicit(senha, 0, sizeof senha) → strlen = 0 (só no gcc)Segurança

Por que memset_explicit? Com otimização (-O2), o compilador pode apagar um memset(senha, 0, …) feito logo antes de a variável deixar de existir, já que "ninguém mais vai ler". A senha fica na memória. O memset_explicit não pode ser apagado.

strerror: a mensagem de um erro

FunçãoO que fazDevolveExemplo → resultadoAula
strerror(num)
"string error"
Traduz o número de um erro do sistema (o errno) num texto em inglês.a mensagem (não mexa nela)strerror(ENOENT) → No such file or directory; strerror(EACCES) → Permission deniederrno e perror

O uso típico: fprintf(stderr, "Não abri %s: %s\n", nome, strerror(errno)); logo depois de um fopen que devolveu NULL. É o mesmo texto que o perror mostra.


Qual usar?

Para…EviteUsePor quê
copiar para um arraystrcpy(d, o)snprintf(d, sizeof d, "%s", o)nunca passa do tamanho e sempre põe o '\0'; o retorno diz se cortou (aula Texto ↔ Número)
copiar só uma partestrncpy sem o '\0' manualstrncpy(d, o, sizeof d - 1); d[sizeof d - 1] = '\0';o strncpy sozinho deixa a string sem fim se a origem for longa
juntar textosstrcat em sequênciasnprintf(d, sizeof d, "%s %s", nome, sobrenome)uma linha, com o tamanho conferido
comparar textosa == bstrcmp(a, b) == 0== compara endereços, não letras
copiar para memória novamalloc(strlen(s)) + strcpystrdup(s)o malloc à mão costuma esquecer o + 1 do '\0'
blocos que se sobrepõemmemcpymemmovecom sobreposição, memcpy é comportamento indefinido
dividir com campos vaziosstrtokstrchr num laçostrtok pula o campo vazio de "a,,c", e num CSV isso desloca as colunas

Editor × gcc

O que muda no <string.h> entre o editor (Clang + wasi-libc) e o gcc 15 (glibc), conferido com os programas desta página:

AssuntoEditorgcc 15 (glibc)
strndup e memccpy (C23), strtok_r (POSIX)só com #define _DEFAULT_SOURCE antes dos #include; sem isso, error: use of undeclared identifier 'strndup'; did you mean 'strdup'?funcionam direto
memset_explicit (C23)não existe (use of undeclared identifier)funciona
Valor de strncmp("Banana", "Bando", 4)-1-3 (o sinal é o mesmo)
char *p = strchr(texto_const, …)sem avisoaviso discards ‘const’ qualifier (C23)
Mudar uma string literal (char *s = "ana"; s[0] = 'A';)funciona, calado (mostra Ana)Falha de segmentação (139): as literais ficam numa memória só de leitura
String sem '\0' no printf("%s")mostra lixo depois do texto (SPX9)também é lixo; nesta execução, saiu só SPX
strlen(NULL)devolve 0, caladoFalha de segmentação (139)

Iguais nos dois: todos os outros resultados desta página, os sinais de strcmp/strncmp/memcmp e os textos do strerror (também strerror(0) = Success).


Erros comuns

Este programa junta os enganos mais frequentes com strings. O -Wall pega todos, mas o programa compila e roda:

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

void limpar(char *s) {
    memset(s, 0, sizeof s);
}

int main(void) {
    char nome[4];
    strcpy(nome, "Ana Souza");
    char a[] = "Ana", b[] = "Ana";
    if (a == b) printf("iguais\n");
    const char *c = "Ana";
    if (c == "Ana") printf("igual ao literal\n");
    char sigla[3];
    strncpy(sigla, "SPX", sizeof sigla);
    limpar(nome);
    printf("%s %s\n", nome, sigla);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra errostr.c -o errostr
errostr.c: In function ‘limpar’:
errostr.c:5:25: warning: argument to ‘sizeof’ in ‘memset’ call is the same expression as the destination; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]
    5 |     memset(s, 0, sizeof s);
      |                         ^
errostr.c: In function ‘main’:
errostr.c:12:11: warning: comparison between two arrays [-Warray-compare]
   12 |     if (a == b) printf("iguais\n");
      |           ^~
errostr.c:12:11: note: use ‘&a[0] == &b[0]’ to compare the addresses
errostr.c:14:11: warning: comparison with string literal results in unspecified behavior [-Waddress]
   14 |     if (c == "Ana") printf("igual ao literal\n");
      |           ^~
errostr.c:16:5: warning: ‘strncpy’ output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation]
   16 |     strncpy(sigla, "SPX", sizeof sigla);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
errostr.c:10:5: warning: ‘__builtin_memcpy’ writing 10 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]
   10 |     strcpy(nome, "Ana Souza");
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~
errostr.c:9:10: note: destination object ‘nome’ of size 4
    9 |     char nome[4];
      |          ^~~~
$ ./errostr
igual ao literal
 SPX
Linhagcc 15Clang (editor)O que acontece e como consertar
strcpy(nome, "Ana Souza"); num char nome[4]‘__builtin_memcpy’ writing 10 bytes into a region of size 4 overflows the destination [-Wstringop-overflow=]'strcpy' will always overflow; destination buffer has size 4, but the source string has length 10 (including NUL byte) [-Wfortify-source]Escreve 6 bytes além do fim do array, por cima de outras variáveis. Aqui passou calado; em outros programas, estraga valores ou derruba o programa. Use um array maior ou snprintf. Aula: Segurança.
if (a == b) com dois arrayscomparison between two arrays [-Warray-compare]array comparison always evaluates to false [-Wtautological-compare]Compara os endereços dos dois arrays, que nunca são iguais: o iguais não saiu, mesmo com o mesmo texto. Use strcmp(a, b) == 0.
if (c == "Ana")comparison with string literal results in unspecified behavior [-Waddress]result of comparison against a string literal is unspecified (use an explicit string comparison function instead) [-Wstring-compare]Aqui deu "igual" porque o compilador guardou as duas "Ana" no mesmo lugar, mas isso não é garantido. Use strcmp(c, "Ana") == 0.
strncpy(sigla, "SPX", sizeof sigla);‘strncpy’ output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation](nenhum aviso)Os 3 bytes encheram o array e não sobrou lugar para o '\0': o printf continua lendo a memória seguinte (no editor saiu SPX9). Reserve um byte a mais: char sigla[4].
memset(s, 0, sizeof s); com char *sargument to ‘sizeof’ in ‘memset’ call is the same expression as the destination; did you mean to provide an explicit length? [-Wsizeof-pointer-memaccess]'memset' call operates on objects of type 'char' while the size is based on a different type 'char *' [-Wsizeof-pointer-memaccess]sizeof s é o tamanho do ponteiro (8 no gcc), não do array. Passe o tamanho como parâmetro: void limpar(char *s, size_t tam). Aula: Ponteiros e Arrays.
Mudar uma string literal
#include <stdio.h>

int main(void) {
    char *nome = "ana";
    printf("Antes: %s\n", nome);
    nome[0] = 'A';
    printf("Depois: %s\n", nome);
    return 0;
}
$ gcc -std=c23 -Wall -Wextra literal.c -o literal
$ ./literal
Antes: ana
Falha de segmentação     (imagem do núcleo gravada) ./literal
$ echo $?
139

O que significa: "ana" é uma string literal, e o gcc a guarda numa parte da memória que só pode ser lida. O char *nome só aponta para ela; escrever ali derruba o programa. Nenhum aviso, nem com -Wall. No editor, o programa mostra Depois: Ana sem erro, mas continua errado.

Como consertar: para um texto que muda, use um array, que é uma cópia sua: char nome[] = "ana";. Para um texto que não muda, deixe claro com const char *nome = "ana";: aí o compilador dá erro se você tentar escrever. Aula: Ponteiros e Strings.

O strcat num array sem valor inicial

char frase[50]; strcat(frase, "Oi"); procura o '\0' do fim de frase, mas o array tem lixo: o texto vai parar num lugar qualquer. Como consertar: comece com uma string vazia, char frase[50] = "";. Aula: Strings.

O fgets deixou o Enter

Depois de fgets(nome, sizeof nome, stdin), o nome termina em '\n': um strcmp(nome, "Ana") dá diferente e um printf("[%s]", nome) pula linha antes do ]. Como consertar: nome[strcspn(nome, "\n")] = '\0'; (é a missão abaixo). Aula: fgets.


Experimente

Missão: o programa lê o nome da Ana com fgets (a entrada já vem preenchida com Ana Souza), mas o ] sai na linha de baixo e o tamanho conta um byte a mais. Use strcspn para tirar o Enter, de modo que a saída seja Olá, [Ana Souza]! Seu nome tem 9 bytes. Depois, teste outras funções da página na mesma caixa.

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

int main(void) {
    char nome[40];
    printf("Seu nome: ");
    if (fgets(nome, sizeof nome, stdin) == NULL) {
        return 1;
    }
    // tire o '\n' aqui

    printf("Olá, [%s]! Seu nome tem %zu bytes.\n", nome, strlen(nome));
    return 0;
}
#include <stdio.h>
#include <string.h>

int main(void) {
    char nome[40];
    printf("Seu nome: ");
    if (fgets(nome, sizeof nome, stdin) == NULL) {
        return 1;
    }
    nome[strcspn(nome, "\n")] = '\0';

    printf("Olá, [%s]! Seu nome tem %zu bytes.\n", nome, strlen(nome));
    return 0;
}

Resumo

  • Tamanho: strlen (bytes até o '\0'; não é o sizeof do array).
  • Cópia e junção: strcpy, strcat (não conferem o tamanho), strncpy (pode deixar sem '\0'), strncat, strdup/strndup (memória nova, com free). Prefira snprintf.
  • Comparação: strcmp, strncmp, memcmp, strcoll. Teste == 0, < 0 ou > 0, nunca == -1. Nunca == entre strings.
  • Busca: strchr, strrchr, strstr, strpbrk, memchr (devolvem ponteiro ou NULL), strspn, strcspn (devolvem contagens). strtok divide, mas estraga a string e pula campos vazios.
  • Memória: memset (byte a byte), memcpy (sem sobreposição), memmove (com sobreposição), memset_explicit (para senhas, C23).
  • strerror(errno) dá o texto do erro do sistema.