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
\0que 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.
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:
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:
char str[10] = "Hello";
str[5] até str[9] são todos \0.
'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
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
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:
s4[0] = 'A';
Isso é errado. Vetores de caracteres, no entanto, são modificáveis:
s1[0] = 'A';
Legal — o conteúdo de s1 torna-se "Abc".
const ao apontar um ponteiro para um literal de string; o compilador avisará se você tentar modificá-lo.
(3) Ponteiros vs vetores
char arr[] = "hello";
const char *ptr = "hello";
rré um vetor: memória é alocada na pilha, conteúdo pode ser modificado,sizeof(arr)é 6ptré um ponteiro: aponta para um literal de string em memória somente leitura,sizeof(ptr)é o tamanho do ponteiro (4 ou 8 bytes)
3. Entrada e saída de strings
(1) printf e scanf
Use o especificador de formato %s para entrada e saída de strings:
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:
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:
char msg[] = "Hello";
puts(msg);
Isso é equivalente a printf("%s\n", msg);.
gets lê uma linha inteira (incluindo espaços) até uma nova linha:
char line[100];
gets(line);
(3) fgets
gets é a substituição segura para gets:
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:
#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:
#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;
}
` 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):
#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:
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:
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:
ptr = "another string";
Legal. Mas:
arr = "another string";
Ilegal — um nome de vetor não pode ser atribuído.
Percorrendo uma string com ponteiro:
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:
#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;
}
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
sizeofestrlendão resultados diferentes para strings? R:sizeofretorna a memória total ocupada pelo vetor (incluindo \0);strlenretorna o número de caracteres antes de \0.
P: O que acontece quando
getslê uma nova linha? R:getsarmazena a nova linha no buffer. Tipicamente você precisa verificá-la manualmente e substituí-la por\0para 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
- Strings em C são vetores de caracteres terminados por
\0;\0é o que as funções de string usam para detectar o fim - Vetores de caracteres permitem modificação do conteúdo; ponteiros de caracteres apontando para literais não
- Use
getsem vez degetspara ler strings; sempre especifique o tamanho do buffer strlenretorna o número de caracteres efetivos;sizeofretorna o tamanho total do vetor- Ponteiros de caracteres podem percorrer uma string, movendo uma posição char por passo
📝 Exercícios
- Escreva um programa que use
getspara ler uma linha de texto e conte o número de letras, dígitos e outros caracteres. - Escreva uma função
oid str_replace_char(char *s, char old, char new_ch)que substitua todas as ocorrências deoldna stringsporew_ch. - Escreva uma função que calcule o comprimento de uma string usando ponteiros de caracteres, sem usar
strlen.