C: Strings — Básico

Uma string em C é como um colar terminado com uma conta transparente — cada conta é um caractere, e a última é o terminador invisível \0 que sinaliza "o colar termina aqui".

1. Vetores de caracteres e strings

C não tem um tipo string dedicado. Uma string é essencialmente um vetor de caracteres terminado por \0 (o caractere nulo). O valor ASCII de \0 é 0, e ele marca o fim da string.

C
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

Este vetor tem 6 elementos: 5 caracteres visíveis mais 1 \0. Sem \0, é apenas um vetor de caracteres comum e não pode ser usado como string.

Literais de string (aspas duplas) adicionam \0 automaticamente no final:

C
char str[] = "Hello";

O comprimento do vetor é 6 (5 caracteres + 1 \0); o compilador calcula automaticamente. Você também pode especificar um comprimento maior; as posições extras são preenchidas com \0:

C
char str[10] = "Hello";

str[5] até str[9] são todos \0.

💡 Dica: Aspas simples 'H' denotam um caractere (1 byte); aspas duplas "Hello" denotam uma string (com um \0 implícito). Eles não são a mesma coisa.


2. Declaração e inicialização de strings

(1) Estilo de vetor de caracteres

C
char s1[] = "abc";
char s2[10] = "abc";
char s3[] = {'a', 'b', 'c', '\0'};

Todos os três são equivalentes à string "abc". Note que s3 requer um \0 adicionado manualmente.

(2) Estilo de ponteiro de caractere

C
const char *s4 = "abc";

s4 aponta para o primeiro caractere de um literal de string. Literais de string são armazenados em uma região somente leitura; tentar modificá-los é comportamento indefinido:

C
s4[0] = 'A';

Isso é errado. Vetores de caracteres, no entanto, são modificáveis:

TEXT 📖 Somente leitura
s1[0] = 'A';

Legal — o conteúdo de s1 torna-se "Abc".

⚠️ Atenção: Use const ao apontar um ponteiro para um literal de string; o compilador avisará se você tentar modificá-lo.

(3) Ponteiros vs vetores

C
char arr[] = "hello";
const char *ptr = "hello";

3. Entrada e saída de strings

(1) printf e scanf

Use o especificador de formato %s para entrada e saída de strings:

C
char name[20];
scanf("%s", name);
printf("Hello, %s!\n", name);

scanf para de ler ao encontrar espaços em branco (espaço, nova linha, tabulação), então não consegue ler uma linha inteira contendo espaços.

scanf não verifica o tamanho do buffer; entrada que excede o comprimento do vetor causa estouro. Você pode limitar o comprimento de leitura:

C
scanf("%19s", name);

Isso lê no máximo 19 caracteres, deixando 1 posição para \0.

(2) puts e gets

puts imprime uma string e adiciona automaticamente uma nova linha:

C
char msg[] = "Hello";
puts(msg);

Isso é equivalente a printf("%s\n", msg);.

gets lê uma linha inteira (incluindo espaços) até uma nova linha:

C
char line[100];
gets(line);
🔥 Erro Comum: Nunca use gets! Ele não verifica o tamanho do buffer — se a entrada exceder a capacidade do vetor, ele escreve fora dos limites. É uma das funções C mais perigosas e foi completamente removida em C11.

(3) fgets

gets é a substituição segura para gets:

TEXT 📖 Somente leitura
char line[100];
fgets(line, sizeof(line), stdin);

Os parâmetros são: o buffer de armazenamento, o número máximo de bytes a ler (incluindo \0), e o fluxo de entrada. gets retém a nova linha no final da string (se uma nova linha foi lida e ainda há espaço).

Padrão comum para remover a nova linha final:

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

int main(void) {
    char line[100];
    fgets(line, sizeof(line), stdin);

    int len = strlen(line);
    if (len > 0 && line[len - 1] == '\n') {
        line[len - 1] = '\0';
    }

    printf("[%s]\n", line);
    return 0;
}

▶ Exemplo

Leia o nome do usuário e uma linha de autoapresentação:

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

void trim_newline(char *s) {
    int len = strlen(s);
    if (len > 0 && s[len - 1] == '\n') {
        s[len - 1] = '\0';
    }
}

int main(void) {
    char name[30];
    char intro[200];

    printf("Enter your name: ");
    fgets(name, sizeof(name), stdin);
    trim_newline(name);

    printf("Introduce yourself: ");
    fgets(intro, sizeof(intro), stdin);
    trim_newline(intro);

    printf("\n--- Personal Info ---\n");
    printf("Name: %s\n", name);
    printf("Intro: %s\n", intro);

    return 0;
}
▶ Experimente

` ext Enter your name: Alice Introduce yourself: I am a C beginner

--- Personal Info --- Name: Alice Intro: I am a C beginner `


4. A função strlen

strlen é declarada em <string.h> e retorna o comprimento da string (não incluindo \0):

C
#include <string.h>

char s[] = "Hello";
printf("%zu\n", strlen(s));

Saída: 5. Note que sizeof(s) é 6 (incluindo \0), enquanto strlen(s) é 5 (excluindo \0).

Como strlen funciona: conta caracteres do início até encontrar \0:

TEXT 📖 Somente leitura
size_t my_strlen(const char *s) {
    size_t len = 0;
    while (s[len] != '\0') {
        len++;
    }
    return len;
}

Se um vetor de caracteres não termina com \0, strlen continuará lendo até encontrar acidentalmente um byte zero, o que é muito perigoso.


5. Introdução a ponteiros de caracteres

Um ponteiro de caractere pode apontar tanto para um vetor de caracteres quanto para um literal de string:

C
char arr[] = "world";
const char *ptr = "world";

ptr = arr;
printf("%s\n", ptr);

Um ponteiro pode ser reatribuído para apontar para uma string diferente, mas um nome de vetor é uma constante e não pode ser modificado:

TEXT 📖 Somente leitura
ptr = "another string";

Legal. Mas:

C
arr = "another string";

Ilegal — um nome de vetor não pode ser atribuído.

Percorrendo uma string com ponteiro:

C
const char *p = "Hello";
while (*p != '\0') {
    printf("%c", *p);
    p++;
}
printf("\n");

*p desreferencia para obter o caractere atual; p++ move para a próxima posição de caractere. O passo do ponteiro é determinado pelo tipo apontado; char * move 1 byte por passo.

▶ Exemplo

Imprima uma string de trás para frente usando um ponteiro de caractere:

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

void print_reverse(const char *s) {
    const char *p = s + strlen(s) - 1;
    while (p >= s) {
        putchar(*p);
        p--;
    }
    putchar('\n');
}

int main(void) {
    print_reverse("Hello");
    print_reverse("ABCDEF");
    return 0;
}
▶ Experimente

ext olleH FEDCBA

Primeiro, mova o ponteiro p para o último caractere da string (uma posição antes de \0), depois imprima os caracteres de trás para frente.

❓ Perguntas Frequentes

P: Qual a diferença entre 'a' e "a"? R: 'a' é uma constante de caractere ocupando 1 byte; "a" é uma constante de string ocupando 2 bytes ('a' mais '\0'), e seu tipo é char[].

P: Por que sizeof e strlen dão resultados diferentes para strings? R: sizeof retorna a memória total ocupada pelo vetor (incluindo \0); strlen retorna o número de caracteres antes de \0.

P: O que acontece quando gets lê uma nova linha? R: gets armazena a nova linha no buffer. Tipicamente você precisa verificá-la manualmente e substituí-la por \0 para removê-la.

P: Posso modificar o conteúdo de um literal de string através de um ponteiro de caractere? R: Não. Literais de string são armazenados em um segmento somente leitura; modificação é comportamento indefinido. Use um vetor de caracteres se precisar modificar o conteúdo.

📖 Resumo

📝 Exercícios

  1. Escreva um programa que use gets para ler uma linha de texto e conte o número de letras, dígitos e outros caracteres.
  2. Escreva uma função oid str_replace_char(char *s, char old, char new_ch) que substitua todas as ocorrências de old na string s por ew_ch.
  3. Escreva uma função que calcule o comprimento de uma string usando ponteiros de caracteres, sem usar strlen.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%