- Aprender
- Computação e TI
- Programação
- Programação em C
- Arranjos e cadeias de caracteres em C
Arranjos e cadeias de caracteres em C
BásicoAula 3 de 8 do curso Curso de Programação em C
O que você vai aprender
- Declare arranjos de tamanho fixo, acesse cada elemento pelo índice, percorra-os com laços sem ultrapassar o fim e compartilhe-os com funções.
- Declare, inicialize e acesse um arranjo por índicesCrie arranjos com uma quantidade fixa de elementos, atribua-lhes valores iniciais e leia ou altere elementos individuais pelo índice.
- Percorra arranjos com laços sem ultrapassar seus limitesVisite cada elemento com um laço de contagem e use esse padrão para somar, encontrar o maior valor, buscar, contar e inverter.
- Passe arranjos para funçõesEscreva funções que recebam arranjos como parâmetros, passe o comprimento junto e saiba quando a função pode alterar os dados da função chamadora.
- Declare, inicialize e acesse um arranjo por índices
- Trate caracteres como pequenos códigos inteiros, armazene texto em arranjos de
charterminados por um caractere nulo, processe-o um caractere por vez e veja como o texto UTF-8 é armazenado em bytes.- Trate caracteres como códigos numéricosUse o tipo
chare constantes de caractere como números, converta algarismos e letras com operações aritméticas e classifique caracteres com<ctype.h>. - Armazene texto em cadeias terminadas em nuloExplique como uma cadeia de caracteres em C é disposta em um arranjo de
char, por que precisa de um caractere nulo no fim e como literais de cadeia e arranjos diferem. - Processe cadeias de caracteres um caractere por vezPercorra uma cadeia até seu terminador para contar, converter, inverter, filtrar e criptografar texto e termine cada nova cadeia com
'\0'. - Explique como o texto UTF-8 é armazenado em arranjos de charRelacione caracteres, pontos de código Unicode e bytes UTF-8 e preveja o que funções de C baseadas em bytes fazem com texto além de ASCII.
- Trate caracteres como códigos numéricos
- Meça, copie, concatene, compare e busque cadeias com
<string.h>e garanta que cada destino tenha espaço para o resultado e seu terminador.- Meça, copie e concatene cadeias de caracteresUse
strlen,strcpyestrcatcorretamente e calcule quanto espaço cada destino precisa. - Compare cadeias de caracteres e faça buscas nelasCompare cadeias com
strcmpestrncmp, encontre caracteres e subcadeias e divida texto em tokens. - Copie respeitando os limites e trabalhe diretamente com bytes de memóriaUse corretamente as funções com limite
strncpy,strncatesnprintf, detecte truncamento e copie, preencha e compare arranjos inteiros com as funções de memória.
- Meça, copie e concatene cadeias de caracteres
- Armazene tabelas e listas de cadeias de caracteres em arranjos com duas ou mais dimensões, percorra-os com laços aninhados e passe-os para funções.
- Declare e percorra matrizes bidimensionaisDeclare e inicialize tabelas de valores, explique como suas linhas são dispostas na memória e processe linhas e colunas com laços aninhados.
- Passe tabelas para funções e armazene listas de cadeias de caracteresEscreva funções que recebam matrizes bidimensionais e mantenha várias cadeias em um arranjo 2D de
charou em um arranjo de ponteiros para cadeias.
- Declare e percorra matrizes bidimensionais
- Leia as palavras digitadas após o nome de um programa por meio de
argceargv, verifique quantas são e converta-as com segurança em números e opções.- Leia argc e argvDeclare
maincom seus dois parâmetros, descreva o que cada elemento deargvcontém e verifique a contagem de argumentos antes de usar qualquer argumento. - Converta e valide argumentos numéricosConverta cadeias de argumentos em números com verificação de erros, rejeite entradas inválidas e verifique a faixa dos valores antes de usá-los.
- Leia argc e argv
- Reconheça como programas em C leem e gravam fora de seus arranjos, por que isso é perigoso e como ler e copiar texto para que ele sempre caiba.
- Reconheça acessos fora dos limites e seus efeitosExplique por que C não impede acessos fora dos limites, o que pode acontecer quando ocorrem e quais erros os causam.
- Leia e copie texto respeitando os limites do bufferLeia entradas com limites de tamanho, detecte linhas longas demais e copie texto somente quando ele couber no destino.
- Reconheça acessos fora dos limites e seus efeitos
Guia de estudo de Arranjos e cadeias de caracteres em C
1Armazene e processe coleções de valores com arranjos
Arranjos permitem que um laço trabalhe com vários valores relacionados. O arranjo fixa o espaço de armazenamento disponível, enquanto índices selecionam elementos individuais e uma contagem registra quantos estão em uso. Aprenda como declarações estabelecem valores iniciais, como laços calculam resultados sem ultrapassar um limite e como funções compartilham os elementos da função chamadora. Pequenos exemplos relacionam o código às posições exatas que ele lê ou grava.
1.1 Declare, inicialize e acesse um arranjo por índices
Um arranjo dá um nome a uma quantidade fixa de valores do mesmo tipo. Seus elementos ficam lado a lado na memória. Use um arranjo quando a mesma operação se aplicar a muitos valores, como atualizar um conjunto de notas.
Crie os elementos
int scores[5] = {90, 72, 85, 64, 99};
int primes[] = {2, 3, 5, 7};
int counts[6] = {0};
A primeira declaração cria cinco inteiros. O compilador conta quatro valores no segundo inicializador, portanto primes tem quatro elementos. No terceiro, o primeiro elemento é explicitamente zero e cada inicializador ausente também se torna zero. Da mesma forma, int a[5] = {1, 2}; contém 1, 2, 0, 0, 0. Um inicializador designado, disponível desde C99, escolhe uma posição: int b[5] = {[2] = 7}; coloca 7 no terceiro elemento e zero nos demais.
Uma declaração local automática como int data[5]; reserva espaço sem fornecer valores iniciais. Grave cada elemento antes de lê-lo. Arranjos declarados fora de todas as funções e arranjos declarados como static são inicializados com zeros quando nenhum inicializador explícito é fornecido.
Acesse um valor pelo índice
Os índices começam em zero. Para cinco elementos, as posições válidas vão de 0 a 4. scores[1] significa a segunda nota, não a primeira. Um elemento pode ser usado em qualquer lugar em que uma variável comum de seu tipo possa ser usada:
scores[1] = 75;
scores[1] += 5;
int last = scores[4];
A segunda nota agora é 80. A última continua sendo 99. Um índice pode ser uma variável ou uma expressão, portanto scores[n - 1] acessa o último elemento quando n é a quantidade de elementos e é positivo. scores[5] não corresponde a nenhum elemento.
Conte elementos e bytes
sizeof scores mede todo o arranjo em bytes. Em um sistema com inteiros de 4 bytes, os cinco elementos ocupam 20 bytes. Dividir pelo tamanho de um elemento elimina a dependência do tamanho do inteiro:
size_t n = sizeof scores / sizeof scores[0];
printf("%zu\n", n);
Isso imprime 5. size_t é o tipo inteiro sem sinal usado para tamanhos; %zu o imprime. Esse cálculo funciona onde scores nomeia o arranjo propriamente dito. Um parâmetro de função não contém o tamanho completo do arranjo.
Mantenha tamanho e valores separados
Um nome como #define NUM_SCORES 5 permite que a declaração e seus laços compartilhem um tamanho. Em C17, uma declaração local const int n = 5; int a[n]; cria um arranjo de tamanho variável: const não transforma n em uma expressão constante inteira. Seu tamanho é escolhido quando a declaração é executada e permanece fixo durante o tempo de vida desse arranjo. Ele não pode usar uma lista de inicialização. O suporte a VLA é opcional em C11 e C17; C23 acrescenta constexpr para constantes em tempo de compilação.
Arranjos não podem ser atribuídos como um todo: b = a; é inválido. Copie seus elementos com um laço ou uma função de memória adequada. Para dois arranjos distintos, a == b compara endereços, não valores dos elementos. Compare os elementos correspondentes para testar a igualdade de valores. Uma comparação de bytes com memcmp testa suas representações armazenadas; valores de ponto flutuante iguais, como zero positivo e negativo, podem ter representações diferentes.
Principais conclusões
- Os índices de um arranjo vão de 0 até uma unidade a menos que a quantidade de elementos.
- Valores ausentes em inicializadores tornam-se zero; elementos locais não inicializados devem ser gravados antes do uso.
- Use
sizeof a / sizeof a[0]somente ondeaé um arranjo propriamente dito. - Um arranjo mantém seu tamanho durante seu tempo de vida.
- Copie e compare valores de arranjos elemento por elemento.
1.2 Percorra arranjos com laços sem ultrapassar seus limites
Um laço de contagem relaciona as posições de um arranjo a uma operação. Determine quais elementos contêm dados úteis e visite exatamente essas posições. O mesmo padrão permite calcular totais, fazer buscas e atualizar valores.
Visite os elementos em uso
int t[5] = {12, 15, 9, 14, 10};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += t[i];
}
double average = sum / 5.0;
O laço usa os índices 0, 1, 2, 3 e 4. O total passa por 12, 27, 36, 50 e 60, portanto a média é 12,0. Escrever i <= 5 acrescenta um acesso inválido no índice 5. Essa passagem extra é um erro de uma unidade.
Para uma média, faça a divisão em ponto flutuante. Com um total de 61, 61 / 5 resulta no inteiro 12; 61 / 5.0 resulta em 12,2. Armazenar depois o primeiro resultado em um double não recupera a fração já descartada.
Encontre um máximo ou uma correspondência
Para um arranjo não vazio, inicialize o máximo com seu primeiro valor:
int max = t[0];
for (int i = 1; i < 5; i++) {
if (t[i] > max) max = t[i];
}
A primeira comparação substitui 12 por 15. Os valores restantes são menores, portanto 15 permanece. Começar por zero falharia para uma lista como {-8, -3, -11}: zero é maior que todos os valores armazenados, mas não está na lista.
Uma busca sequencial verifica os valores em ordem:
int found = -1;
for (int i = 0; i < 5; i++) {
if (t[i] == 14) {
found = i;
break;
}
}
Aqui found torna-se 3. O valor -1 indica ausência de correspondência porque não pode ser um índice válido. Informe a falha somente após verificar todos os candidatos. Retornar -1 após o primeiro elemento diferente deixa de encontrar correspondências posteriores no arranjo.
Conte e reorganize
Um vetor de frequências armazena um contador por categoria. Para algarismos, int counts[10] = {0}; fornece contadores de 0 a 9. Após verificar d >= 0 && d < 10, counts[d]++ aumenta o contador do algarismo d. A verificação protege o arranjo quando o valor do algarismo vem da entrada.
Para inverter um arranjo, troque pares a partir de suas extremidades:
for (int i = 0; i < 5 / 2; i++) {
int temp = t[i];
t[i] = t[5 - 1 - i];
t[5 - 1 - i] = temp;
}
A primeira troca permuta 12 e 10. A segunda permuta 15 e 14. O 9 do meio permanece no lugar, resultando em {10, 14, 9, 15, 12}. Pare na metade: continuar pelas cinco posições trocaria cada par duas vezes.
Acompanhe a quantidade em uso separadamente da capacidade
Um arranjo com espaço para 100 valores pode conter apenas 37 entradas úteis no momento. Sua capacidade é 100; sua quantidade em uso é 37. Processe as posições abaixo de count. Para acrescentar um valor, verifique primeiro count < CAPACITY, armazene-o em a[count] e depois incremente count. Percorrer até a capacidade pode levar à leitura de posições que nunca receberam valores úteis, embora estejam fisicamente dentro do arranjo.
Principais conclusões
- Use o limite estrito
<no laço. - Use divisão em ponto flutuante quando uma média puder ter uma fração.
- Inicialize o máximo de um arranjo não vazio com um elemento, inclusive quando todos os dados forem negativos.
- Uma busca só é considerada malsucedida após a verificação de todos os candidatos.
- Valide um valor antes de usá-lo como índice.
- Inverta trocando apenas a primeira metade dos pares.
- A quantidade em uso é o número de elementos utilizados; a capacidade é o espaço disponível.
1.3 Passe arranjos para funções
Uma função pode processar um arranjo sem receber uma cópia separada de cada elemento. A chamada compartilha o acesso ao armazenamento da função chamadora. Passe a quantidade de elementos junto com ele para que a função saiba onde parar.
Forneça os dados e seu comprimento
#include <stddef.h>
double average(const int a[], size_t n) {
if (n == 0) return 0.0;
int sum = 0;
for (size_t i = 0; i < n; i++) {
sum += a[i];
}
return (double) sum / n;
}
A função chamadora pode declarar int values[] = {7, 8, 10}; e chamar average(values, sizeof values / sizeof values[0]). As três adições produzem 25; converter sum para double antes da divisão produz aproximadamente 8,33. Retornar 0,0 quando não há valores é o comportamento escolhido para entrada vazia nessa função. Os valores pequenos deste exemplo mantêm a soma inteira dentro da faixa representável.
Em uma declaração de parâmetro, int a[] é ajustado para int *a. Ele recebe o endereço do primeiro elemento. Mesmo int a[10] não verifica nem exige dez elementos. A função chamadora deve fornecer um comprimento que corresponda aos dados disponíveis.
Por que sizeof perde o comprimento
No local da chamada, sizeof values mede o arranjo. Dentro da função, sizeof a mede o parâmetro ponteiro. Onde ponteiros ocupam 8 bytes e inteiros ocupam 4, dividir esses tamanhos resulta em 2, independentemente da quantidade de elementos da função chamadora. Esse resultado não descreve uma cópia de dois elementos nem o arranjo original. Mantenha o comprimento como parâmetro explícito.
size_t, declarado por cabeçalhos que incluem <stddef.h>, é o tipo sem sinal produzido por sizeof. Ele pode representar tamanhos de objetos, e %zu o imprime. Usá-lo para o índice do laço evita comparar um índice com sinal a um comprimento sem sinal.
Decida se os elementos podem mudar
O const em const int a[] impede atribuições aos elementos por meio desse parâmetro. Ele é adequado a uma função que calcula um resultado a partir dos dados. Uma função destinada a atualizar elementos o omite:
void zero(int a[], size_t n) {
for (size_t i = 0; i < n; i++) {
a[i] = 0;
}
}
Após zero(values, 3), os três elementos da função chamadora contêm zero. O arranjo continua com três elementos. Um parâmetro escalar como n é uma cópia separada; alterar essa cópia não alteraria uma variável de contagem da função chamadora.
Para produzir vários resultados, deixe que a função chamadora forneça um arranjo de saída e seu comprimento. Uma função pode preencher out[i] com cada resultado. Funções em C não podem retornar um arranjo por valor, e retornar o endereço de um arranjo local falha porque esse arranjo deixa de existir quando a função retorna.
Conte de trás para a frente com um índice sem sinal
Um índice sem sinal não pode se tornar negativo. Em for (size_t i = n - 1; i >= 0; i--), o teste é sempre verdadeiro; após zero, ocorre redução modular para um número positivo grande. Com n == 0, até a subtração inicial sofre redução modular. Comece pela quantidade em uso:
for (size_t i = n; i > 0; i--) {
printf("%d\n", a[i - 1]);
}
Com três elementos, os índices acessados são 2, 1 e 0. Com zero elementos, o corpo nunca é executado. Inclua <stdio.h> para printf.
Principais conclusões
- Passe o comprimento de um arranjo separadamente; não é possível recuperar a quantidade de elementos a partir de um parâmetro.
- Gravações por meio de um parâmetro de arranjo alteram os elementos da função chamadora.
- Use
constpara um parâmetro que apenas lê elementos. - A função chamadora fornece armazenamento para vários valores de saída.
- Conte de trás para a frente a partir de
ne acessei - 1ao usarsize_t.
2Represente texto com caracteres e cadeias terminadas em nulo
O texto começa com códigos de caracteres e termina com uma regra de armazenamento: uma cadeia em C para em seu primeiro byte zero. Aprenda como caracteres, literais e arranjos modificáveis diferem e depois use laços para contar e transformar texto. UTF-8 acrescenta uma distinção essencial entre um byte e um ponto de código completo. Acompanhar o texto e seu armazenamento explica por que uma palavra visível pode precisar de mais posições no arranjo do que suas letras sugerem.
2.1 Trate caracteres como códigos numéricos
Um caractere em C é armazenado como um código numérico. Isso permite que um programa imprima um símbolo, compare-o com outro ou faça operações aritméticas com seu código. O conjunto de caracteres determina qual número representa cada símbolo.
Leia o código e o caractere
Um char ocupa um byte: sizeof(char) é 1 por definição. Uma constante de caractere como 'A' tem tipo int. No conjunto de caracteres baseado em ASCII usado aqui, seu código é 65:
printf("%c %d\n", 'A', 'A');
A saída é “A 65”. %c exibe o caractere; %d exibe seu número. ASCII atribui códigos de 0 a 127. Os algarismos vão de 48 a 57, as letras maiúsculas de 65 a 90, as minúsculas de 97 a 122 e o espaço tem código 32.
Aspas simples e aspas duplas criam coisas diferentes. 'A' é um código de caractere. "A" é um arranjo que contém 'A' e um byte zero terminador. Armazene um caractere com char c = 'A'; e compare-o usando c == 'A'.
Escreva caracteres que precisam de escapes
| Escrita em C | Caractere |
|---|---|
'\n' | Nova linha, código ASCII 10 |
'\t' | Tabulação, código ASCII 9 |
'\\' | Barra invertida |
'\'' | Aspas simples |
'\0' | Caractere nulo, código 0 |
O caractere nulo é diferente do algarismo visível '0', cujo código ASCII é 48. Uma cadeia de caracteres usa o caractere nulo para marcar seu fim.
Transforme códigos em valores úteis
O padrão C garante códigos consecutivos para algarismos. Após verificar que c é um algarismo, c - '0' produz seu valor. Assim, '7' - '0' é 7, não 55. Subtrair o código inicial elimina a posição do algarismo dentro do conjunto de caracteres.
As letras ASCII também são consecutivas, portanto subtrair 'A' converte uma letra maiúscula em uma posição de 0 a 25. Um deslocamento de César de três posições usa:
char shifted = (c - 'A' + 3) % 26 + 'A';
Para 'X', subtrair 65 resulta em 23; somar três resulta em 26; o resto da divisão por 26 é zero; somar 65 retorna 'A'. Apenas 'X' + 3 resulta no código 91, que é '['. A aritmética com letras depende da ordem de letras do ASCII; C garante algarismos consecutivos, mas não exige letras consecutivas.
Classifique e converta com ctype.h
Inclua <ctype.h> para usar isdigit, isalpha, isalnum, isspace, isupper, islower, toupper e tolower. Os testes retornam um valor diferente de zero quando há correspondência e zero caso contrário. toupper('q') retorna 'Q'; toupper('3') deixa o algarismo inalterado. isspace reconhece separadores como espaço, tabulação e nova linha.
Um char sem qualificador pode ter sinal. Um byte acima de 127 pode então se tornar um valor negativo, que não é um argumento válido para essas funções, a menos que seja o marcador especial de entrada EOF. Ao processar bytes de uma cadeia, converta primeiro:
if (isalpha((unsigned char) c)) {
c = (char) toupper((unsigned char) c);
}
Na configuração regional “C” padrão, essas funções reconhecem as letras básicas, não caracteres UTF-8 completos com vários bytes. A conversão explícita torna o byte um argumento válido; ela não decodifica UTF-8.
Principais conclusões
- Constantes de caractere usam aspas simples; literais de cadeia de caracteres usam aspas duplas.
\0é um caractere de valor zero, não o algarismo0.- Subtraia
'0'de um caractere de algarismo para obter seu valor. - A aritmética de posições de letras aqui usa a ordem ASCII.
- Converta um byte de cadeia para
unsigned charantes de chamar uma função ctype. - Um teste ctype retorna um valor diferente de zero quando há correspondência, não necessariamente 1.
2.2 Armazene texto em cadeias terminadas em nulo
Uma cadeia de caracteres em C é uma sequência de caracteres terminada em '\0'. O terminador faz parte de seu armazenamento, mas não do comprimento do texto. C não tem um tipo interno separado para cadeias de caracteres: os caracteres ocupam um arranjo.
Veja os bytes no arranjo
char word[] = "cat";
char name[20] = "Ada";
word contém quatro bytes: 'c', 'a', 't', '\0'. O tamanho de seu arranjo é 4 e strlen(word) é 3. Inclua <string.h> para usar strlen. O arranjo maior name contém as três letras, seu terminador e mais dezesseis bytes zero. Sua capacidade é 20, enquanto seu comprimento atual é 3.
Um inicializador caractere por caractere pode criar a mesma cadeia:
char word[] = {'c', 'a', 't', '\0'};
Omitir o último elemento cria três caracteres sem um terminador de cadeia. C também permite char word[3] = "cat";, que preenche as três posições e omite o byte zero. Esse arranjo não é uma cadeia de caracteres em C. Uma função como strlen ou printf com %s continua lendo até encontrar um byte zero, portanto não pode consumir com segurança esse arranjo de três bytes como texto.
Escolha um arranjo modificável ou um literal
| Declaração | Onde está o texto | Seus caracteres podem mudar? |
|---|---|---|
char a[] = "hello"; | Uma cópia no arranjo a | Sim |
const char *p = "hello"; | Um literal de cadeia ao qual p se refere | Não |
a[0] = 'H'; altera a cópia para “Hello”. Um literal não deve ser modificado. Mesmo que seja atribuído a um char * sem qualificador, gravar por esse ponteiro causa comportamento indefinido. Escrever const char * torna essa restrição visível ao compilador.
O compilador une literais de cadeia adjacentes: "Hello, " "world" produz o mesmo texto que "Hello, world". A cadeia resultante continua tendo um único terminador final. Isso é útil para dividir um literal longo entre linhas do código-fonte.
Imprima e altere o texto
printf("%s\n", word);
printf("%c\n", word[0]);
A primeira chamada imprime a cadeia inteira. A segunda imprime seu primeiro caractere. Um literal de cadeia em printf fica entre aspas duplas porque é um texto que contém um formato; %c recebe um código de caractere.
Uma atribuição a um elemento altera um caractere armazenado. Com char name[20] = "Ada";, definir name[0] = 'E'; produz “Eda”. Definir name[1] = '\0'; em seguida produz “E” como cadeia. Os bytes de 'a' e do terminador antigo ainda existem mais adiante no arranjo, mas as operações de cadeia param no primeiro zero.
Um arranjo não pode receber texto substituto usando name = "Bob"; após a declaração. Copie caracteres para ele, usando uma chamada verificada de strcpy ou um laço, e inclua o terminador. O comprimento do texto substituto deve ser menor que a capacidade.
Represente a ausência de texto
A cadeia vazia "" ainda ocupa um byte para '\0'. Ela tem comprimento zero e pode ser testada com name[0] == '\0'. Uma cadeia vazia é uma cadeia real com um terminador; um ponteiro nulo, por sua vez, não aponta para nenhum armazenamento de cadeia.
Principais conclusões
- Uma cadeia de caracteres em C termina em seu primeiro
'\0'. - A capacidade inclui o terminador; o comprimento da cadeia não o inclui.
- Um arranjo de caracteres sem terminador não pode ser passado como uma cadeia de caracteres em C.
- Cópias de literais em arranjos são modificáveis; os próprios literais não são.
- Gravar um terminador antes no arranjo encurta o texto sem redimensionar o arranjo.
2.3 Processe cadeias de caracteres um caractere por vez
O terminador de uma cadeia fornece a um laço seu ponto de parada. Visite os bytes anteriores a ele para contar, converter ou filtrar texto. Ao criar uma nova cadeia, o próprio programa deve gravar um novo terminador.
Percorra até o fim uma vez
for (size_t i = 0; s[i] != '\0'; i++) {
/* Process s[i]. */
}
A cada passagem, o teste verifica se o byte atual pertence ao texto. Ele para antes do terminador. Chamar strlen(s) nesse teste pode percorrer novamente toda a cadeia a cada passagem. Teste o byte atual diretamente ou calcule size_t len = strlen(s); uma vez, quando o comprimento permanecerá inalterado.
Para converter para maiúsculas, use um arranjo modificável e <ctype.h>:
for (size_t i = 0; s[i] != '\0'; i++) {
s[i] = (char) toupper((unsigned char) s[i]);
}
“Hello, World 42” torna-se “HELLO, WORLD 42”. A conversão preserva a vírgula, os espaços e os algarismos. A conversão para um tipo sem sinal torna cada byte armazenado um argumento válido para ctype.
Conte categorias e inícios de palavras
O original “Hello, World 42” tem 15 bytes de texto: 10 letras, dois algarismos, dois espaços e uma vírgula. Contadores separados podem usar isalpha, isdigit e isspace. Decida o que é uma palavra antes de contá-la. Para uma sequência de letras, uma nova palavra começa quando uma letra vem após um caractere que não é letra ou é o primeiro caractere:
int in_word = 0;
size_t words = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
int letter = isalpha((unsigned char) s[i]) != 0;
if (letter && !in_word) words++;
in_word = letter;
}
O exemplo tem duas sequências de letras, “Hello” e “World”. Os algarismos não formam uma palavra segundo essa definição. Atualizar in_word a cada passagem permite que a pontuação encerre uma sequência.
Inverta apenas o texto
Para uma cadeia de caracteres de um byte, obtenha len uma vez e depois troque s[i] por s[len - 1 - i] enquanto i < len / 2. Inverter “stressed” troca sua primeira e última letras, depois o par seguinte, até se tornar “desserts”. O byte zero permanece no índice len. Começar uma troca em s[len] moveria esse zero para o início. Inverter bytes dessa forma é adequado para texto ASCII; caracteres de vários bytes precisam ser decodificados antes de serem reorganizados.
Crie um resultado filtrado
Use índices diferentes para leitura e escrita, pois alguns bytes de entrada são ignorados:
char in[] = "a1b2c3";
char out[sizeof in];
size_t j = 0;
for (size_t i = 0; in[i] != '\0'; i++) {
if (isalpha((unsigned char) in[i])) {
out[j++] = in[i];
}
}
out[j] = '\0';
O resultado é “abc”. O destino tem espaço suficiente porque a filtragem não pode aumentar essa entrada. Sem out[j] = '\0';, a saída não tem um fim de cadeia definido.
Para uma cifra de César, desloque letras maiúsculas em relação a 'A' e letras minúsculas em relação a 'a', depois copie os outros bytes sem alteração. Com chave 13, “Hello, World!” torna-se “Uryyb, Jbeyq!”. Repetir esse deslocamento restaura o original porque dois deslocamentos totalizam 26. Uma comparação como s[i] == 'a' testa um caractere; use strcmp para comparar o texto completo.
Principais conclusões
- Teste o byte atual ou guarde o comprimento para evitar percursos completos repetidos.
- Mantenha índices de leitura e escrita separados ao filtrar.
- Grave um terminador após criar uma nova cadeia.
- Inverta os bytes do texto sem mover o terminador.
- Defina um limite de palavra antes de escrever um contador de palavras.
- Aplique deslocamentos de letras ASCII separadamente a letras maiúsculas e minúsculas.
2.4 Explique como o texto UTF-8 é armazenado em arranjos de char
O comprimento de um texto pode significar uma contagem de bytes ou uma contagem de pontos de código Unicode. Essas contagens frequentemente diferem. Um arranjo de char em C expõe bytes individuais, portanto seus índices e funções de cadeia não acompanham automaticamente caracteres não ASCII completos.
Separe caracteres, pontos de código e bytes
Uma codificação de caracteres descreve como o texto é armazenado. ASCII usa códigos de 0 a 127 para letras básicas, algarismos, pontuação e caracteres de controle. Unicode atribui pontos de código a caracteres de muitos sistemas de escrita: “é” tem o ponto de código U+00E9 e “€” tem U+20AC. UTF-8 codifica valores escalares Unicode usando de um a quatro bytes.
Os pontos de código ASCII mantêm suas codificações de um byte. O “é” pré-composto usa dois bytes, 0xC3 e 0xA9; “€” usa três. Muitos pontos de código individuais de emoji usam quatro bytes. Um símbolo exibido pode conter vários pontos de código, portanto mesmo uma contagem de pontos de código nem sempre é uma contagem de símbolos visíveis.
Meça uma cadeia UTF-8
char s[] = "café";
printf("%zu %zu\n", strlen(s), sizeof s);
Com texto de execução em UTF-8, isso imprime “5 6”. As três primeiras letras usam três bytes e “é” usa dois, totalizando cinco bytes de texto. O terminador acrescenta o sexto byte de armazenamento. s[3] é o primeiro byte de “é”, não a letra inteira.
Um corte após quatro bytes manteria 0xC3, mas removeria seu byte de continuação 0xA9. O resultado deixaria de ser UTF-8 válido. Portanto, um limite de buffer expresso em bytes precisa de uma verificação de limite de caractere se o programa truncar texto UTF-8.
Conte bytes iniciais em UTF-8 válido
Um byte de continuação começa com os bits 10. Seu valor está entre 0x80 e 0xBF. Um byte inicial ou byte ASCII não tem esse padrão:
size_t points = 0;
for (size_t i = 0; s[i] != '\0'; i++) {
unsigned char c = (unsigned char) s[i];
if ((c & 0xC0) != 0x80) points++;
}
A máscara 0xC0 mantém apenas os dois bits mais significativos; 0x80 representa o padrão 10 nessas posições. O teste conta “café” como quatro pontos de código ao contar seus quatro bytes iniciais. Ele pressupõe UTF-8 válido e não valida sequências malformadas nem combina pontos de código em símbolos visíveis.
Escolha operações que preservem a codificação
Copiar uma cadeia UTF-8 completa preserva seus bytes. Concatenar cadeias completas, comparar suas sequências de bytes para verificar igualdade e buscar um caractere ASCII ou uma subcadeia UTF-8 completa também funcionam. Bytes de continuação UTF-8 não podem ser confundidos com caracteres ASCII ou bytes iniciais.
strcmp ordena valores de bytes sem sinal, portanto sua ordem difere da ordem alfabética específica de cada idioma. Em UTF-8, letras latinas acentuadas comuns têm bytes iniciais acima do ASCII 'z'. Uma comparação de bytes, portanto, coloca essas letras depois de 'z', independentemente das convenções de dicionário.
Na configuração regional “C” padrão, toupper e isalpha processam um byte e não decodificam “é” como uma letra. Converter para unsigned char torna a chamada válida, mas não a transforma em uma conversão Unicode entre maiúsculas e minúsculas. Funções de caracteres largos ou uma biblioteca Unicode são necessárias para essa tarefa. Um laço de César restrito a ASCII pode preservar letras acentuadas alterando apenas bytes de A–Z ou a–z.
O byte zero é a codificação UTF-8 de U+0000; outros pontos de código codificados não contêm byte zero. Isso se ajusta à convenção de terminador de C. UTF-16 pode colocar bytes zero dentro de texto comum codificado, portanto um arranjo de bytes UTF-16 não pode ser processado como uma cadeia comum de char.
Principais conclusões
strlenconta bytes, inclusive em texto UTF-8.- Um ponto de código Unicode pode ocupar vários bytes.
- Um índice de char pode apontar para o interior de um caractere codificado.
- Contar bytes que não são de continuação só conta pontos de código em UTF-8 válido.
- A igualdade byte a byte funciona para texto codificado de forma idêntica; a ordem dos bytes não é a ordem de dicionário.
- Chamadas ctype que operam em um byte não decodificam UTF-8.
3Use as funções padrão para cadeias de caracteres
A biblioteca padrão fornece operações comuns de texto, mas cada função espera um tipo específico de entrada e um significado específico para seu argumento de tamanho. Aprenda a medir, copiar, acrescentar, comparar e buscar cadeias de caracteres e depois escolha formatação com limite ou operações com bytes quando forem adequadas. Verificar a capacidade e interpretar os valores de retorno transforma uma chamada curta de função em uma operação previsível sobre um espaço de armazenamento conhecido.
3.1 Meça, copie e concatene cadeias de caracteres
As funções de <string.h> trabalham com texto terminado em nulo. Elas podem encontrar seu comprimento, copiá-lo ou acrescentar mais texto, mas as funções de cópia não descobrem a capacidade do destino. Calcule o espaço necessário antes de gravar.
Meça o comprimento sem o terminador
strlen(s) retorna um size_t que indica a quantidade de bytes antes do primeiro byte zero. Assim, strlen("hello") é 5 e strlen("") é zero. Imprima o resultado com %zu.
char buf[64] = "hi";
printf("%zu %zu\n", strlen(buf), sizeof buf);
Isso imprime “2 64”. O primeiro resultado mede o texto atual; o segundo mede o espaço disponível no arranjo. Uma cópia posterior pode alterar o primeiro sem alterar o segundo. As duas operações são úteis aqui porque buf é um arranjo propriamente dito e já contém uma cadeia válida.
Copie uma cadeia completa
strcpy(dest, src) copia o texto e seu byte zero final. A capacidade necessária é o comprimento da origem mais um:
char dest[12];
const char *src = "Maple";
if (strlen(src) < sizeof dest) {
strcpy(dest, src);
}
“Maple” usa cinco bytes de texto e um terminador, portanto cabe. O < estrito é importante: uma origem cujo comprimento seja igual à capacidade não deixa espaço para seu byte zero. Se a verificação falhar, o programa deve tratar o erro antes de usar o destino como uma nova cadeia.
Uma atribuição de arranjo como dest = src; não pode substituir seu conteúdo. Atribuir uma variável char * a outra é permitido, mas apenas copia uma referência ao mesmo espaço de armazenamento. Isso não cria outra cópia dos caracteres.
Acrescente a uma cadeia existente
strcat(dest, src) primeiro encontra o terminador que já está em dest. Ela substitui esse terminador pelo primeiro byte da origem e grava um novo terminador após o texto acrescentado. A capacidade do destino deve comportar os dois comprimentos atuais mais um.
char full[16];
strcpy(full, "Ada");
strcat(full, " ");
strcat(full, "Lovelace");
Os comprimentos crescem de 3 para 4 e depois para 12. O resultado final “Ada Lovelace” precisa de 13 bytes de armazenamento, deixando três bytes sem uso. Um destino de 12 bytes seria pequeno demais por um byte, apesar de corresponder ao comprimento do texto visível.
Nunca acrescente texto a um buffer local não inicializado. char out[20]; strcat(out, "hi"); não fornece a strcat um fim de texto definido para encontrar. Comece com char out[20] = "";, grave out[0] = '\0'; ou faça da primeira operação uma cópia verificada.
Considere a sobreposição e o custo dos percursos
A origem e o destino não devem se sobrepor em strcpy ou strcat. Mover texto dentro do mesmo buffer pode criar uma sobreposição mesmo quando as duas posições são válidas individualmente. memmove é a função destinada a regiões de bytes sobrepostas.
strlen precisa percorrer a cadeia até o terminador. strcat precisa percorrer o destino atual antes de acrescentar texto. Portanto, acréscimos repetidos em um laço percorrem novamente o texto já criado. Ao montar várias partes, mantenha o comprimento atual da saída e escreva cada parte nesse índice, verificando a capacidade restante e mantendo o terminador. Um comprimento conhecido só é útil enquanto corresponder ao conteúdo real.
Principais conclusões
strlenmede o texto atual;sizeofaplicado a um arranjo mede sua capacidade.- Uma cópia precisa do comprimento da origem mais um byte.
- Um acréscimo precisa dos comprimentos das duas cadeias mais um byte.
- Inicialize o destino como uma cadeia antes de acrescentar texto.
- Copiar ou acrescentar com regiões de cadeia sobrepostas é inválido.
3.2 Compare cadeias de caracteres e faça buscas nelas
A comparação de cadeias responde a perguntas sobre o texto, enquanto a busca encontra uma posição dentro dele. Nenhuma das duas tarefas é realizada comparando nomes de arranjos com ==. Use o resultado da biblioteca de acordo com o que ele representa: o sinal de uma comparação, um comprimento ou uma posição correspondente.
Compare texto e prefixos
strcmp(a, b) compara os bytes correspondentes como valores unsigned char até encontrar uma diferença ou o fim da cadeia. Seu resultado é zero para textos iguais, negativo quando a vem primeiro e positivo quando vem depois. Apenas o sinal é especificado; não espere exatamente -1 ou 1.
if (strcmp(command, "quit") == 0) {
puts("Goodbye");
}
O teste explícito de zero significa igualdade. Um simples if (strcmp(command, "quit")) entra no bloco quando os textos são diferentes, pois um valor diferente de zero é verdadeiro. Comparar command == "quit" compararia posições de armazenamento.
Na ordem ASCII, “apple” vem antes de “banana” pela primeira letra. “Zebra” vem antes de “apple” porque o 'Z' maiúsculo tem código 90 e o 'a' minúsculo tem código 97. “app” vem antes de “apple” porque seu byte zero é encontrado antes do 'l' da outra cadeia. Essa é uma ordenação por bytes, não uma comparação de dicionário.
strncmp(a, b, n) compara no máximo n bytes. strncmp(s, "--", 2) == 0 reconhece um prefixo de dois hífens, mas não significa que toda a cadeia seja apenas “--”. O C padrão não tem uma função de comparação de cadeias inteiras que ignore maiúsculas e minúsculas. Um programa pode comparar os bytes convertidos por conta própria; POSIX fornece strcasecmp em <strings.h>.
Busque uma posição
Use strchr para a primeira ocorrência de um caractere, strrchr para a última e strstr para a primeira subcadeia completa. Elas retornam um ponteiro para a posição correspondente ou NULL se não houver correspondência.
char name[] = "report.final.txt";
char *extension = strrchr(name, '.');
if (extension != NULL) {
printf("%s\n", extension);
}
Isso imprime “.txt”, incluindo o ponto encontrado. Começar pelo primeiro ponto com strchr imprimiria “.final.txt”. strstr(name, "final") encontra o trecho final que começa com “final.txt”; buscar “draft” retorna NULL. Verifique se o resultado é NULL antes de imprimi-lo ou lê-lo.
Localize um separador ou divida texto
strcspn(s, set) conta os bytes iniciais que não correspondem a nenhum dos caracteres em set. Com "oak:pine,birch" e o conjunto ":,", ela para nos dois-pontos. Para uma cadeia de entrada válida, este padrão remove a primeira nova linha:
buf[strcspn(buf, "\n")] = '\0';
Se não houver nova linha, o índice retornado é o comprimento da cadeia, portanto a atribuição regrava o terminador que já está lá.
strtok divide uma cadeia modificável usando qualquer caractere de um conjunto de delimitadores:
char colors[] = "red, green,blue";
char *token = strtok(colors, " ,");
while (token != NULL) {
puts(token);
token = strtok(NULL, " ,");
}
Os tokens são “red”, “green” e “blue”. A primeira chamada fornece o arranjo; as chamadas seguintes passam NULL para continuar. A função grava bytes zero na entrada e mantém estado oculto entre chamadas. Use armazenamento modificável e não espere que a cadeia original com seus separadores permaneça intacta. Delimitadores consecutivos não produzem tokens vazios.
Principais conclusões
- Use
strcmp(a, b) == 0para verificar se os textos são iguais. - Interprete um resultado de comparação pelo sinal, não pelo valor exato.
- Uma correspondência de prefixo não estabelece a igualdade das cadeias inteiras.
- Resultados de busca precisam ser verificados quanto a ponteiro nulo.
strcspnretorna o comprimento de um prefixo;strtokmodifica sua entrada e mantém sua posição.- A ordenação de cadeias segue os códigos dos bytes sem sinal.
3.3 Copie respeitando os limites e trabalhe diretamente com bytes de memória
Um limite de comprimento só é útil quando descreve a quantidade correta. Algumas funções limitam os bytes da origem, outras limitam a capacidade do destino, e as funções de memória lidam diretamente com bytes sem terminadores de cadeia. Leia o contrato de cada função antes de escolher seu limite.
Saiba o que n significa
strncpy(dest, src, n) grava exatamente n posições quando a origem é menor, preenchendo o restante com bytes zero. Quando a origem tem pelo menos n bytes de texto, ela copia esses bytes sem um terminador. Para um arranjo com capacidade positiva, uma cópia truncada e terminada é:
strncpy(dest, src, sizeof dest - 1);
dest[sizeof dest - 1] = '\0';
A atribuição final é essencial quando a origem preenche o limite. Truncar um nome ou comando ainda pode mudar seu significado, portanto rejeite entradas longas demais quando for necessária uma cópia completa.
strncat(dest, src, n) acrescenta no máximo n bytes de texto e depois um terminador. Ela não recebe a capacidade total. Para uma cadeia válida que já está em um arranjo de destino, o espaço restante para texto é sizeof dest - strlen(dest) - 1. Passar sizeof dest como n pode causar estouro.
Formate e detecte truncamento
snprintf, declarada em <stdio.h>, recebe a capacidade total do destino. Com capacidade maior que zero, grava no máximo uma unidade a menos de bytes de texto e depois um terminador:
char buf[8];
int needed = snprintf(buf, sizeof buf, "%s-%d", "item", 2026);
if (needed < 0) {
puts("Formatting error");
} else if ((size_t) needed >= sizeof buf) {
puts("Text did not fit");
}
O resultado completo “item-2026” tem nove bytes de texto. O buffer armazena “item-20” e seu byte zero, enquanto needed é 9. O valor de retorno conta o texto que teria sido produzido, sem incluir o terminador. Verifique se o resultado é negativo antes de convertê-lo para size_t.
Copie e preencha bytes
memcpy(dest, src, n) copia exatamente n bytes, incluindo quaisquer bytes zero, sem procurar um terminador. Para dois arranjos de inteiros do mesmo tamanho, memcpy(b, a, sizeof a) copia todo o espaço que ocupam quando as regiões não se sobrepõem. Onde cada um de cinco inteiros ocupa quatro bytes, essa quantidade é 20 bytes. memmove copia bytes com comportamento definido para regiões sobrepostas.
memset(a, 0, sizeof a) preenche cada byte com zero e zera um arranjo de inteiros. Seu segundo argumento descreve cada byte, não cada elemento. Com inteiros de quatro bytes, preencher com 1 produz os bytes 01 01 01 01, resultando em 16.843.009 na representação usual, não no inteiro 1. Use um laço para atribuir valores inteiros diferentes de zero.
memcmp(a, b, n) compara bytes armazenados. Zero significa que essas sequências de bytes são iguais. Para verificar a igualdade de valores, compare os elementos: 0.0 e -0.0 em ponto flutuante são iguais na comparação, embora suas representações possam ser diferentes.
Reconheça outras famílias de bibliotecas
strlcpy e strlcat do BSD foram incorporadas ao POSIX em 2024, mas não são funções principais de C17. Elas retornam o comprimento que tentaram criar; um resultado pelo menos igual ao tamanho fornecido indica truncamento. strlcpy termina o destino quando o tamanho é positivo. strlcat só o termina se o texto existente terminar dentro desse tamanho. Elas estão disponíveis na glibc 2.38 e posteriores. Funções opcionais do Anexo K, como strcpy_s, estão ausentes de muitas bibliotecas, incluindo a glibc.
Principais conclusões
strncpypode omitir o terminador;strncatprecisa de espaço para um novo.snprintfretorna o comprimento completo necessário para o texto ou um erro negativo.- Um resultado não negativo de formatação pelo menos igual à capacidade indica truncamento.
- Funções de memória contam bytes e não param no zero.
- Use
memmovepara regiões sobrepostas. memsetpreenche bytes;memcmpcompara representações.
4Organize dados em arranjos multidimensionais
Tabelas organizam valores por mais de uma posição. Uma tabela em C armazena linhas de mesma largura em sequência, e laços aninhados permitem que um programa trabalhe por linha ou por coluna. Aprenda a declarar esse formato, passá-lo para uma função e manter ambos os índices válidos. Listas de texto apresentam uma escolha útil: linhas de caracteres modificáveis reservam espaço fixo, enquanto arranjos de ponteiros se referem a cadeias armazenadas em outro lugar.
4.1 Declare e percorra matrizes bidimensionais
Uma tabela precisa de um índice de linha e um índice de coluna. Em C, uma matriz bidimensional é um arranjo cujos elementos também são arranjos. Cada linha tem a mesma quantidade de elementos, e cada índice tem seu próprio limite.
Declare linhas e colunas
int grid[3][4];
int m[2][3] = {{1, 2, 3}, {4, 5, 6}};
grid contém três linhas com quatro inteiros cada: doze inteiros no total. Seus índices de linha vão de 0 a 2; seus índices de coluna vão de 0 a 3. grid[1][2] acessa o terceiro valor da segunda linha.
As chaves aninhadas do inicializador mostram o agrupamento por linhas. Elementos sem inicialização explícita tornam-se zero. Você pode deixar o compilador contar as linhas em int m[][3] = {{1, 2, 3}, {4, 5, 6}};, mas a quantidade de colunas deve ser informada. Sem ela, o compilador não poderia determinar onde cada linha termina.
Acompanhe o armazenamento por linhas
C armazena uma linha completa antes de começar a próxima. Em grid, os primeiros quatro inteiros armazenados formam a linha 0, os quatro seguintes formam a linha 1 e os últimos quatro formam a linha 2. grid[1][2] é o sétimo inteiro a partir do início, na posição de elemento 6 com indexação a partir de zero: uma linha completa de quatro, seguida de mais dois elementos.
Onde inteiros ocupam quatro bytes, uma linha usa dezesseis bytes e a tabela inteira usa quarenta e oito. No local da declaração:
size_t rows = sizeof grid / sizeof grid[0];
size_t cols = sizeof grid[0] / sizeof grid[0][0];
A primeira divisão resulta em 3 e a segunda em 4. Uma linha é, por si só, um arranjo, por isso sizeof grid[0] mede mais de um inteiro.
Percorra e some a tabela
int sales[2][3] = {{4, 0, 7}, {5, 2, 1}};
int total = 0;
for (int r = 0; r < 2; r++) {
int row_sum = 0;
for (int c = 0; c < 3; c++) {
row_sum += sales[r][c];
}
printf("%d\n", row_sum);
total += row_sum;
}
A primeira linha produz 11 e a segunda, 8. Somar esses totais das linhas resulta em 19. Reinicializar row_sum dentro do laço externo inicia um novo total para cada linha. Se ela fosse inicializada apenas uma vez antes dos dois laços, o segundo valor impresso também incluiria a primeira linha.
Para totais por coluna, coloque o laço de colunas fora e o de linhas dentro, continuando a acessar sales[r][c]. Os três totais passam a ser 9, 2 e 8, que novamente somam 19. Alterar a ordem do percurso não exige alterar o significado dos dois índices. Percorrer primeiro por linha segue o armazenamento contíguo e frequentemente melhora o uso do cache em tabelas grandes.
Mantenha cada dimensão dentro dos limites
grid[c][r] troca os significados dos índices. Se c chegar a 3, solicita uma quarta linha que não existe. O fato de o objeto completo conter doze inteiros não permite ultrapassar o limite de uma linha com um índice de coluna.
Escreva duas operações de indexação separadas: grid[1][2]. Em C17, grid[1, 2] avalia a expressão com vírgula e seleciona grid[2], uma linha, em vez de um elemento. Mais dimensões aplicam a mesma ideia repetidamente: int cube[2][3][4] tem 24 elementos inteiros, selecionados por três índices.
Principais conclusões
- Uma matriz bidimensional é um arranjo de linhas de mesma largura.
- As linhas são armazenadas uma após a outra, em armazenamento por linhas.
- Mantenha separados os limites das linhas e das colunas.
- Reinicialize um acumulador de linha ou coluna ao começar um novo grupo.
- Somente a primeira dimensão pode ser inferida a partir de um inicializador.
4.2 Passe tabelas para funções e armazene listas de cadeias de caracteres
Uma função que recebe uma tabela precisa de informações suficientes para identificar cada linha. Uma lista de cadeias de caracteres acrescenta outra escolha: armazenar os caracteres em linhas de mesma largura ou armazenar referências a cadeias de comprimentos diferentes.
Informe a largura da linha em um parâmetro de tabela
void double_grid(int rows, int g[][4]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < 4; c++) {
g[r][c] *= 2;
}
}
}
A primeira dimensão pode ser omitida porque a quantidade de linhas é passada separadamente. A largura 4 define o tipo de cada linha. Sem ela, g[r][c] não teria um espaçamento conhecido entre linhas. Uma declaração com int g[][] é inválida. Alterações feitas por meio desse parâmetro permanecem na tabela da função chamadora; um parâmetro de tabela somente para leitura pode usar const int g[][4].
Desde C99, compiladores que aceitam parâmetros de tipo variavelmente modificado aceitam dimensões declaradas anteriormente na lista de parâmetros:
void print_grid(int rows, int cols, int g[rows][cols]);
GCC e Clang aceitam essa forma de C17. Ela permite que uma função receba linhas de larguras diferentes; passe dimensões positivas que correspondam à tabela real. C23 exige suporte a esses tipos de parâmetro, enquanto objetos automáticos de arranjos de tamanho variável continuam sendo um recurso opcional separado. Parâmetros de largura fixa são úteis quando o suporte do compilador é limitado.
Armazene cadeias em linhas
char days[7][10] = {
"Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday", "Sunday"
};
Cada linha tem espaço para dez caracteres, independentemente do comprimento atual de seu texto. “Wednesday” precisa das dez posições: nove letras e um terminador. days[2] seleciona essa linha inteira como uma cadeia; days[2][0] seleciona 'W'.
Uma linha pode ser impressa com %s, medida com strlen ou comparada com strcmp. Ela também pode receber uma cópia verificada. strcpy(days[0], "Mon"); cabe em dez bytes e altera o texto da linha 0. A linha continua com dez bytes de largura, e a linha seguinte permanece na mesma posição. Um texto substituto de dez bytes precisaria de onze bytes e não caberia.
Armazene referências a literais
const char *names[] = {"Ann", "Bartholomew", "Li"};
Isso declara um arranjo de ponteiros. Cada elemento se refere a um literal com seu próprio comprimento mais um terminador. names[1] refere-se a “Bartholomew”, e names[1][0] é 'B'. Os literais não devem ser modificados.
Os elementos ponteiro podem mudar, embora os caracteres dos literais não possam. names[0] = "Anna"; altera o literal ao qual o primeiro elemento se refere; isso não amplia “Ann” no próprio local. Na forma com linhas 2D, um elemento é um arranjo de caracteres de largura fixa e não pode receber uma nova atribuição dessa maneira. Escolha linhas modificáveis para texto editado no próprio local e referências a literais para uma lista de opções de texto fixas. O parâmetro de linha de comando argv usa uma estrutura de arranjo de ponteiros, embora os caracteres dos argumentos fornecidos sejam modificáveis.
Principais conclusões
- Parâmetros de tabela precisam de todas as dimensões após a primeira.
- Uma dimensão passada separadamente deve corresponder à tabela real.
- Cada linha de cadeia precisa de seu próprio terminador dentro de sua largura fixa.
- Um arranjo de ponteiros armazena referências, não linhas de caracteres de mesma largura.
5Processe argumentos de linha de comando
Uma linha de comando fornece texto a um programa na inicialização. A contagem de argumentos, o agrupamento pelo shell e as operações com cadeias permitem que o programa interprete esse texto sem supor que um argumento exista ou já contenha um número. Siga um caminho com verificações de argv até um valor utilizável: verifique sua presença, faça a conversão completa, detecte erros de conversão e respeite a faixa que o programa realmente aceita.
5.1 Leia argc e argv
Argumentos de linha de comando permitem que a função chamadora forneça texto ao iniciar um programa. O ambiente de execução disponibiliza essas cadeias para main. Verifique quantas chegaram antes de acessá-las por índices.
Leia a lista de argumentos
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
printf("%d: %s\n", i, argv[i]);
}
return 0;
}
Inclua <stdio.h> para a saída. argc é a contagem de argumentos e argv é a lista de cadeias. A forma equivalente do parâmetro char **argv descreve a mesma interface. O laço começa em 1 porque o índice 0 normalmente contém o nome usado para iniciar o programa.
Em um shell comum, executar ./greet Ada Lovelace fornece três cadeias: “./greet”, “Ada” e “Lovelace”. Assim, argc é 3 e o último argumento do usuário é argv[2]. Um ponteiro nulo fica em argv[argc], aqui argv[3]; ele é uma sentinela após as cadeias de argumentos propriamente ditas.
Deixe o shell agrupar o texto
Aspas afetam a forma como o shell monta os argumentos. Executar ./greet "Ada Lovelace" fornece um argumento do usuário contendo um espaço. As aspas agrupam as palavras e não se tornam parte do texto do argumento. argc agora é 2.
Shells semelhantes ao Unix também podem expandir padrões antes de o programa começar. Em ./count *.txt, o programa geralmente recebe os nomes encontrados pelo shell como argumentos separados. Ele recebe as cadeias resultantes, não uma solicitação para expandir o padrão por conta própria. O comportamento exato da expansão depende do shell e de suas configurações.
Rejeite um argumento ausente ou extra
Se um programa precisar de exatamente um argumento do usuário, exija argc == 2 antes de usá-lo:
if (argc != 2) {
printf("Usage: %s name\n", argv[0]);
return 1;
}
printf("Hello, %s\n", argv[1]);
Quando argc é 1, argv[1] é o ponteiro nulo sentinela e não pode ser passado para strlen nem impresso com %s. Índices além da sentinela estão fora do arranjo de argumentos.
Retornar zero de main indica sucesso. Um código diferente de zero, como o 1 acima, informa ao shell que o programa não foi concluído com sucesso. <stdlib.h> também fornece EXIT_SUCCESS e EXIT_FAILURE.
Trate cada argumento como uma cadeia
argv[i][0] acessa o primeiro caractere do argumento; strlen(argv[i]) mede seus bytes de texto; strcmp(argv[i], "-v") == 0 verifica uma opção completa. Um argumento com aparência numérica ainda é texto e deve ser convertido antes de operações aritméticas.
argv[0] geralmente registra como o programa foi iniciado, mas pode estar vazio quando essa informação não está disponível. Ele é útil para mensagens, não como verificação de uma identidade fixa. Os caracteres dos argumentos podem ser modificados durante o programa, mas o espaço fornecido para eles não permite supor que um texto substituto mais longo caberá. Para acrescentar uma extensão ou aumentar o texto de outra forma, copie-o primeiro para um buffer dimensionado separadamente.
Principais conclusões
argcconta as cadeias de argumentos fornecidas, incluindo a entrada normal com o nome usado para iniciar o programa.- Verifique a contagem de argumentos antes de ler um argumento do usuário.
argv[argc]é um ponteiro nulo, não uma cadeia de argumento vazia.- Aspas no shell podem manter espaços dentro de um argumento.
- Use operações de cadeia para o texto dos argumentos e conversão para números.
5.2 Converta e valide argumentos numéricos
Um argumento numérico chega como caracteres, não como um inteiro. Uma conversão confiável verifica três questões distintas: algum algarismo formou um número, a conversão usou o texto necessário e o valor resultante é permitido?
Evite perder informações sobre erros
atoi, declarada em <stdlib.h>, faz uma conversão simples. Ela transforma “13” em 13, mas também transforma “12abc” em 12. Ela retorna zero tanto para “0” quanto para um texto como “abc” que não começa com um número. Um resultado fora da faixa representável causa comportamento indefinido, portanto um teste que aceita apenas algarismos seguido de atoi ainda é inseguro para entradas muito longas.
Uma regra de formato como “somente um ou mais algarismos” precisa de um percurso separado. Rejeite uma cadeia vazia e exija que cada byte satisfaça isdigit((unsigned char) c). Essa regra aceita “13” e rejeita “13a”, “-5” e “”. Ela verifica a forma escrita, não se o valor cabe em um inteiro da máquina.
Use strtol e examine onde ela parou
#include <errno.h>
#include <stdlib.h>
char *end;
errno = 0;
long count = strtol(argv[1], &end, 10);
if (end == argv[1] || *end != '\0' || errno == ERANGE) {
puts("Enter a whole number");
return 1;
}
if (count < 1 || count > 100) {
puts("Count must be from 1 to 100");
return 1;
}
Esse trecho vem após uma verificação da contagem de argumentos e usa <stdio.h> para puts. O 10 seleciona a conversão decimal. end recebe a posição em que a conversão parou; &end permite que a função armazene essa posição. *end lê o caractere nessa posição. Não é necessária aritmética de ponteiros.
Para “13a”, o valor retornado é 13, mas *end é 'a', portanto o texto é rejeitado. Para uma cadeia vazia ou “abc”, end é igual ao início do argumento, mostrando que nenhum número foi consumido. Ambas as verificações são necessárias: testar apenas o zero final aceitaria erroneamente uma cadeia vazia.
Antes de cada conversão, redefina errno como zero. Um valor fora da faixa de long faz strtol retornar um extremo da faixa e definir ERANGE. Sem a redefinição, um erro antigo poderia parecer pertencer a essa conversão. Verifique antes de converter o resultado para a faixa menor de int; use INT_MIN e INT_MAX de <limits.h> quando toda a faixa de int for o domínio aceito.
Aplique a regra do próprio programa
strtol aceita caracteres de espaço em branco no início e um sinal opcional. Decida se essas formas são permitidas. Se a interface exigir apenas algarismos, faça o percurso que verifica se a cadeia não está vazia e contém apenas algarismos, além das verificações de conversão. Após uma conversão bem-sucedida, verifique a faixa permitida pela aplicação antes de usar um valor como quantidade ou índice. “0” pode ser um texto numérico perfeitamente válido e ainda assim ser inválido para uma quantidade que deve ser positiva.
Um programa de César que aceita uma chave não negativa verifica primeiro argc, depois se ela contém apenas algarismos e, em seguida, o resultado completo de strtol e sua faixa. Reduzir uma chave válida com % 26 produz um deslocamento de 0 a 25 antes da aritmética com letras. A chave 27 tem o efeito da chave 1. Faça a verificação de faixa antes de uma conversão explícita para um tipo de faixa menor ou de qualquer operação aritmética que possa causar estouro. Para valores decimais, strtod oferece a interface correspondente para posição final e erro de faixa.
Principais conclusões
- Argumentos com aparência numérica ainda precisam de conversão.
atoinão consegue distinguir zero válido de uma falha de conversão.- Verifique se
strtolleu algo e consumiu todo o texto necessário. - Redefina
errno, verifiqueERANGEe depois verifique a faixa permitida pela aplicação. - Um percurso que verifica apenas algarismos não descarta a possibilidade de estouro.
- Valide um valor antes de convertê-lo para um tipo de faixa menor ou usá-lo como índice.
6Evite acessos fora dos limites e estouros de buffer
Erros de limites relacionam várias ideias anteriores: um laço pode fazer uma passagem extra, um texto pode precisar de um byte extra e uma função pode perder a informação sobre a capacidade de um arranjo. Aprenda a identificar o acesso inválido antes de prever seus efeitos. Depois, leia e copie entradas dentro de limites conhecidos, verificando separadamente o sucesso e a completude, para que um buffer que comporta os dados também contenha aqueles que o programa pretendia aceitar.
6.1 Reconheça acessos fora dos limites e seus efeitos
Todo acesso a um arranjo precisa de um índice válido. C não exige uma verificação de limites em tempo de execução, portanto o programador deve manter o índice dentro do objeto. Um acesso fora de sua faixa tem comportamento indefinido: a linguagem não garante nenhum resultado.
Reconheça um acesso inválido
Para int a[5], os índices válidos vão de 0 a 4. O índice 5 já é grande demais e -1 é negativo. Um compilador pode diagnosticar um erro visível, mas muitos índices inválidos dependem da entrada em tempo de execução e não são rejeitados durante a compilação.
Um programa com defeito pode parecer funcionar, encerrar inesperadamente ou produzir valores imprevistos. Uma gravação pode corromper dados próximos; o sintoma pode ocorrer mais tarde em um cálculo sem relação aparente. Uma leitura pode acessar bytes fora do objeto pretendido. Nenhuma das operações tem um resultado confiável. Repetir uma execução bem-sucedida não pode estabelecer que o acesso é válido.
Conte cada gravação, incluindo o terminador
char name[8];
strcpy(name, "Christopher");
“Christopher” tem onze bytes de texto. Copiá-lo também grava o terminador, portanto essa chamada tenta gravar doze bytes em oito posições. Isso é um estouro de buffer. Em sistemas reais, um estouro pode danificar outros dados ou informações de controle. Historicamente, ataques incluindo o worm Morris de 1988 exploraram esses defeitos no tratamento de entrada.
Um estouro pode ter apenas um byte:
char s[5];
for (int i = 0; i <= 5; i++) {
s[i] = 'x';
}
O corpo é executado seis vezes e grava no índice 5. Alterar o teste para i < 5 mantém cinco gravações de caracteres dentro do arranjo, mas ainda não cria uma cadeia. Para uma cadeia de quatro caracteres 'x', grave apenas nos índices de 0 a 3 e depois armazene '\0' no índice 4.
Valide índices calculados
Uma tabela de frequências pode transformar um caractere em índice, mas a subtração por si só não garante a faixa:
int counts[26] = {0};
if (c >= 'a' && c <= 'z') {
counts[c - 'a']++;
}
Com a ordem ASCII, esse teste limita o resultado de 0 a 25. Para 'A' ou um byte de pontuação, usar c - 'a' sem o teste poderia criar um índice negativo. Teste o valor original antes de indexar; verificar após a gravação é tarde demais.
Para uma tabela, valide a linha e a coluna separadamente. Em int g[2][3], um índice de coluna 3 é inválido mesmo que a linha seguinte esteja ao lado na memória. Não use o armazenamento da tabela inteira como justificativa para ultrapassar o limite de uma linha.
Use verificações adequadas à operação
Um laço sobre arranjo usa um limite superior estrito; um acréscimo verifica a quantidade em uso em relação à capacidade; uma cópia de cadeia verifica o comprimento do texto mais um. Funções recebem comprimentos ou capacidades reais de suas funções chamadoras. Essas verificações tratam de quantidades diferentes, portanto um único tamanho fixo no código não pode substituir todas elas.
Compile com avisos como -Wall -Wextra. A opção -fsanitize=address -g de GCC e Clang pode informar muitos acessos inválidos em caminhos executados e mostrar o local no código-fonte. Esses testes ajudam a encontrar erros, mas caminhos não executados ainda exigem raciocínio sobre os limites. Revise cada leitura e gravação indexada, identificando seu objeto, seu limite e a condição que mantém o índice válido.
Principais conclusões
- Leituras e gravações fora dos limites têm comportamento indefinido.
- Uma execução bem-sucedida não é prova de que um índice é válido.
- Uma cadeia copiada inclui seu terminador na quantidade de bytes gravados.
- Valide os dados antes de obter um índice de arranjo a partir deles.
- Verifique cada dimensão de uma tabela independentemente.
- Avisos e sanitizadores ajudam a detectar defeitos nos caminhos testados.
6.2 Leia e copie texto respeitando os limites do buffer
O comprimento da entrada é controlado por quem a fornece. Informe às funções de leitura o limite real do buffer e verifique o que elas retornam. Depois, decida se os dados formam uma linha completa e se atendem às regras do próprio programa.
Leia uma palavra com uma largura
Para char word[16];, scanf("%15s", word) lê no máximo quinze caracteres que não são de espaço em branco e acrescenta '\0'. A largura deixa uma das dezesseis posições para o terminador. %s sem largura não tem limite de comprimento; gets tinha o mesmo problema fundamental para linhas e foi removida de C em C11.
Verifique se scanf retorna 1 antes de usar uma palavra. Ela lê uma palavra, não uma linha inteira com espaços. Bytes excedentes da palavra podem permanecer sem leitura, portanto uma largura protege o armazenamento sem decidir se toda a entrada é aceitável.
Leia uma linha com fgets
char buf[8];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return 1;
}
fgets lê aqui no máximo sete caracteres e grava um byte zero final. Ela mantém uma nova linha quando a encontra antes do limite. Uma linha contendo “hello” e uma nova linha torna-se "hello\n" mais o terminador. Uma linha final que termina no fim de arquivo sem uma nova linha ainda pode ser lida com sucesso. Se nenhum caractere tiver sido lido antes do fim de arquivo, ou se ocorrer um erro de leitura, o resultado será NULL; não processe esse buffer como nova entrada.
Distinga uma nova linha armazenada de uma linha parcial
Encontre uma nova linha antes de removê-la:
size_t end = strcspn(buf, "\n");
int had_newline = buf[end] == '\n';
buf[end] = '\0';
Inclua <string.h>. Se nenhuma nova linha tiver sido armazenada, end será o comprimento do texto e a atribuição regravará o terminador existente. A ausência de uma nova linha pode significar uma linha parcial, um preenchimento exato do buffer antes de uma nova linha ou uma linha final que terminou no fim de arquivo. Só isso não permite concluir que restam caracteres.
Para a linha de entrada “abcdefghij” e um buffer de oito bytes, a primeira leitura armazena “abcdefg” e a próxima pode ler “hij\n”. Tratar o segundo trecho como uma resposta separada dividiria uma única entrada lógica. Um programa pode rejeitar uma linha sem uma nova linha obrigatória ou ler e descartar seu restante antes de perguntar novamente. Defina a política de entrada antes de implementá-la.
Para até trinta caracteres ASCII de um nome mais uma nova linha e um terminador, use 32 bytes. Para UTF-8, esse é um limite de bytes: trinta caracteres exibidos podem precisar de mais espaço.
Copie somente após verificar todos os requisitos
char user[10];
if (argc != 2) return 1;
if (strlen(argv[1]) >= sizeof user) {
puts("Name too long");
return 1;
}
strcpy(user, argv[1]);
A verificação da contagem de argumentos vem primeiro. A verificação do comprimento admite então no máximo nove bytes de texto, deixando a décima posição para o zero. Uma função de gravação deve receber a capacidade explicitamente, como em read_name(out, capacity), pois sizeof out dentro dela mede um parâmetro ponteiro.
Para entrada numérica, leia uma linha completa e converta-a com strtol, verificando a posição final, o erro de faixa e a faixa de valores permitida. Uma chamada malsucedida de scanf("%d", &n) pode deixar o texto problemático sem leitura; repeti-la sem verificação pode falhar para sempre nos mesmos bytes. No mínimo, verifique sua contagem de atribuições e trate a entrada inválida antes de tentar novamente.
Principais conclusões
- Defina a largura de leitura de uma palavra como uma unidade a menos que a capacidade do buffer.
- Verifique o resultado de uma leitura antes de usar seu buffer.
fgetsmantém uma nova linha somente quando a alcança dentro do limite.- A ausência de uma nova linha, por si só, não estabelece que ainda há entrada.
- Reserve espaço para os bytes do texto, a nova linha quando mantida e o terminador.
- Verifique a presença do argumento antes de medir e copiar seu texto.
- Passe a capacidade do buffer para uma função que grava nele.
Exercícios resolvidos de Arranjos e cadeias de caracteres em C
1Acompanhe um arranjo da declaração à chamada de função
13 passos
- 1IntroduçãoDê um nome a vários valores
Um arranjo contém uma quantidade fixa de elementos de um mesmo tipo. Um laço seleciona posições, enquanto uma função pode trabalhar no mesmo armazenamento por meio de um parâmetro de arranjo.
Acompanhe quatro leituras de sensor desde a declaração até um total e uma média. Em cada etapa, mantenha três quantidades distintas: a quantidade de elementos, o último índice válido e a quantidade de bytes usada para armazenamento.
- 2ExemploLeia as posições iniciais
int readings[4] = {11, 16, 13};Há quatro elementos, com índices de 0 a 3. O inicializador fornece 11, 16 e 13 nas três primeiras posições. O valor omitido torna-se zero, portanto o arranjo é
{11, 16, 13, 0}.O zero é uma regra de inicialização, não um sinal de que o arranjo tem apenas três elementos. Um arranjo local sem inicializador precisaria ter seus valores gravados antes do uso.
- 3ExplicaçãoConte os elementos na declaração
size_t n = sizeof readings / sizeof readings[0];O numerador mede os quatro elementos e o denominador mede um. Onde
intocupa quatro bytes, isso é dezesseis dividido por quatro, resultando em 4. A mesma expressão funciona com outro tamanho de inteiro.readings[3]é o último elemento.readings[4]está após o fim, embora a quantidade de elementos do arranjo seja 4.size_té o tipo sem sinal usado para esse resultado de tamanho. - 4DesafioAltere a última leitura
A declaração continua sendo
int readings[4] = {11, 16, 13};. Qual atribuição substitui o zero por 20 e qual é a quantidade resultante?---reveal---
Use
readings[3] = 20;. Os valores resultantes são{11, 16, 13, 20}e a quantidade permanece 4. Uma atribuição a um elemento altera um valor, não a quantidade de posições. O índice 4 estaria uma posição além do limite e não pode adicionar espaço a esse arranjo. - 5ExemploConstrua o total uma passagem por vez
int sum = 0; for (size_t i = 0; i < n; i++) { sum += readings[i]; }Usando
{11, 16, 13, 20}, a soma acumulada passa a ser 11, 27, 40 e 60. Após o índice 3, i torna-se 4 e o teste falha antes de outro acesso.Começar a soma em zero fornece um ponto de partida para o primeiro valor. O limite superior estrito permite que o laço visite exatamente os quatro elementos existentes.
- 6Ideia-chavePreserve uma média fracionária
Para essas quatro leituras,
(double) sum / nresulta em 15,0. A conversão explícita ocorre antes da divisão, portanto a operação pode produzir um resultado fracionário quando o total muda.Se o total fosse 61, a divisão inteira
sum / 4produziria 15, enquantosum / 4.0produziria 15,25. Atribuir o resultado inteiro já truncado a um double produziria apenas 15,0; isso não recuperaria a fração descartada. - 7DicaEscolha um candidato inicial válido
Uma busca do máximo precisa de um valor inicial obtido de um arranjo não vazio. Para
{-6, -2, -9}, inicializemaxcom -6 e depois substitua-o por -2 quando esse valor maior aparecer. A última comparação deixa -2 inalterado.Inicializar max com zero retornaria zero, que não está presente. Para uma busca sequencial, a regra de parada correspondente também importa: uma diferença não estabelece a falha; os elementos posteriores ainda precisam ser verificados.
- 8DesafioContinue a busca
Uma busca por 13 verifica
{11, 16, 13, 20}. Após verificar o índice 0, ela retorna -1 porque 11 é diferente de 13. O que deve mudar e onde está a correspondência?---reveal---
Continue verificando após uma diferença e retorne -1 somente depois que todos os candidatos falharem. Aqui o índice 1 também é diferente, mas o índice 2 corresponde. Uma busca bem-sucedida pode parar aí. A primeira comparação malsucedida descreve um elemento, não o arranjo inteiro.
- 9ConexãoPasse o cálculo da média para uma função
double mean(const int a[], size_t n);O parâmetro de arranjo compartilha o acesso aos elementos da função chamadora. Ele não contém a quantidade de elementos, portanto o segundo parâmetro a fornece.
constimpede gravações acidentais por meio de a nessa operação somente de leitura.Calcule a quantidade onde
readingsé declarado e chamemean(readings, n). Dentro de mean,sizeof amede um parâmetro ponteiro em vez do arranjo de quatro elementos da função chamadora. - 10ExemploTrate a faixa vazia antes de dividir
double mean(const int a[], size_t n) { if (n == 0) return 0.0; int sum = 0; for (size_t i = 0; i < n; i++) sum += a[i]; return (double) sum / n; }Para as quatro leituras pequenas, o total continua sendo 60 e o resultado é 15,0. Para n igual a zero, o resultado escolhido é 0,0 e não ocorre acesso ao arranjo nem divisão. A função chamadora deve passar uma quantidade utilizável e correta.
- 11DesafioExplique uma alteração no arranjo da função chamadora
Outra função recebe
int a[], size_t ne define cadaa[i]visitado como zero. O que acontece com as leituras da função chamadora e como uma função que apenas calcula o total poderia impedir essas gravações?---reveal---
Os elementos da função chamadora tornam-se zero porque a função grava no armazenamento compartilhado do arranjo. Suas quatro posições continuam existindo. Uma função que apenas calcula o total deve usar
const int a[], tornando inválidas as atribuições a elementos por meio de a. Alterar uma cópia escalar de n não mudaria uma variável de contagem da função chamadora. - 12DesafioUse apenas as leituras existentes
Um buffer tem capacidade 10, mas apenas quatro leituras estão em uso. Uma nova leitura deve ser acrescentada antes de calcular uma média. Quais verificações e qual quantidade o programa deve usar?
---reveal---
Verifique se a quantidade em uso, 4, é menor que a capacidade 10. Grave no índice 4 e depois atualize a quantidade para 5. Passe essa quantidade em uso para mean para que ela processe exatamente os cinco valores. Passar a capacidade incluiria posições que não receberam leituras.
- 13RecapitulaçãoRelacione cada contagem à sua função
Uma declaração cria as posições, um laço visita as que estão em uso e uma função recebe explicitamente a quantidade utilizável. Um parâmetro somente de leitura impede que cálculos sobrescrevam a entrada.
Ao revisar código de arranjos, acompanhe o primeiro e o último índice visitados e o estado de cada acumulador. Para laços regressivos com
size_t, comece em n, continue enquanto i for positivo e acessea[i - 1], para que uma faixa vazia não exija subtração a partir de zero.
2Transforme bytes armazenados em operações de texto
16 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoAcompanhe o texto e o armazenamento
- 2ExplicaçãoLeia um caractere como código
- 3DesafioRetorne ao início do alfabeto
- 4ExemploCrie uma cadeia modificável
- 5Ideia-chaveMova o fim sem mover o armazenamento
- 6DesafioDeixe uma posição para o fim
- 7ExemploSepare leitura e escrita
- 8ExemploTermine a nova cadeia
- 9DesafioInverta as letras sem o terminador
- 10DicaClassifique bytes com argumentos válidos
- 11ExemploVisualize uma letra acentuada em UTF-8
- 12ExplicaçãoReconheça bytes de continuação
- 13DesafioMeça uma nova palavra codificada
- 14ConexãoEscolha operações que mantenham os caracteres inteiros
- 15DesafioVerifique um atalho proposto para texto
- 16RecapitulaçãoLocalize o fim e os limites dos caracteres
3Monte, busque e formate texto com segurança
14 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoIdentifique o contrato de cada função
- 2ExemploComece com uma cópia completa
- 3ExemploAcrescente no fim existente
- 4DesafioDecida se outro acréscimo cabe
- 5ExplicaçãoUse zero para reconhecer textos iguais
- 6ExemploLeia a partir de uma posição encontrada
- 7DesafioExamine uma verificação de comando baseada em prefixo
- 8DicaEspere que a tokenização altere o texto
- 9ExemploFormate dentro de uma capacidade conhecida
- 10DesafioInterprete a mesma formatação com menos espaço
- 11Ideia-chaveUm limite pode contar bytes da origem
- 12ExemploMova uma região sobreposta
- 13DesafioPreserve um resultado completo após o deslocamento
- 14RecapitulaçãoSepare bytes de resultados de texto
4Leia uma tabela e escolha uma disposição para a lista de cadeias
10 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoDê dois índices a cada posição
- 2ExemploColoque valores nas linhas
- 3ExemploReinicialize o total no início de cada linha
- 4DesafioAltere o agrupamento, mantenha os índices
- 5ExplicaçãoInforme à função a largura da linha
- 6ExemploReserve uma cadeia terminada em nulo por linha
- 7Ideia-chaveReferências permitem cadeias de comprimentos diferentes
- 8DesafioSubstitua texto no armazenamento adequado
- 9DesafioMantenha ambas as dimensões válidas em uma função
- 10RecapitulaçãoMantenha o formato da tabela visível
5Valide uma seleção na linha de comando
11 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoReceba o texto antes de interpretá-lo
- 2ExemploRelacione um comando do shell às entradas
- 3ExplicaçãoVerifique a contagem antes da conversão
- 4DesafioAgrupe um nome corretamente
- 5DicaUm inteiro retornado não é suficiente
- 6ExemploExamine uma conversão completa
- 7ExplicaçãoVerifique a faixa da própria seleção
- 8DesafioDetecte texto parcialmente numérico
- 9Ideia-chaveFormato e valor são regras separadas
- 10DesafioCombine agrupamento e validação numérica
- 11RecapitulaçãoVerifique presença, conversão e finalidade
6Corrija uma rotina de entrada com limite
13 passos
Salve esta aula para seguir cada Lição Interativa passo a passo.
- 1IntroduçãoLimite a gravação e verifique o resultado
- 2ExemploEncontre a gravação extra
- 3Ideia-chaveUma última posição válida pode conter o fim
- 4DesafioVerifique um índice obtido de um byte
- 5ExplicaçãoLeia uma palavra com espaço para o terminador
- 6ExemploLeia um trecho de linha com limite
- 7ExemploObserve onde uma linha longa é dividida
- 8DicaExamine uma nova linha antes de removê-la
- 9DesafioReserve espaço para uma linha completa
- 10ExemploVerifique uma cópia antes de gravar
- 11DesafioSepare um prefixo seguro de uma resposta aceita
- 12ConexãoUse diagnósticos junto com o raciocínio sobre limites
- 13RecapitulaçãoMantenha quatro verificações distintas
Questões de Arranjos e cadeias de caracteres em C
Conjunto 1: Caracteres, terminadores de cadeia e UTF-810 Questões de Prática
Questão 1 de 10
'6' - '0' produz?Mostrar respostaOcultar resposta
Questão 2 de 10
('W' - 'A' + 5) % 26 + 'A'?Mostrar respostaOcultar resposta
Questão 3 de 10
c deve ser passado para isalpha sem arriscar um argumento de byte negativo?Mostrar respostaOcultar resposta
Questão 4 de 10
char color[] = "amber";?Mostrar respostaOcultar resposta
Questão 5 de 10
char s[8] = "planet"; s[3] = '\0'; s[0] = 'P';?Mostrar respostaOcultar resposta
Questão 6 de 10
char tag[4] = "east"; printf("%s", tag); não é seguro?Mostrar respostaOcultar resposta
Questão 7 de 10
"m8n2p" e as grava em um arranjo de saída suficientemente grande. O que ele deve gravar após o último p?Mostrar respostaOcultar resposta
Questão 8 de 10
char s[] = "lamp"; trocando s[i] por s[len - i] enquanto i < len / 2, onde len é strlen(s). Quais são o strlen(s) final e a capacidade inalterada?Mostrar respostaOcultar resposta
Questão 9 de 10
Mostrar respostaOcultar resposta
Questão 10 de 10
41 C3 B1 42 00. Um programa grava zero no índice de byte 2. Quais são o novo strlen e a validade UTF-8 do texto?Mostrar respostaOcultar resposta
Conjunto 2: Valores de arranjos, laços e chamadas de função10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
a[3] após int a[5] = {6, 9};?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
int a[7];, onde int ocupa 4 bytes. Qual par fornece sizeof a e o último índice válido?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
int a[] = {-12, -4, -9};, qual valor uma busca do máximo deve retornar?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
O que este código imprime?
int a[] = {3, 8, 5, 2};
int sum = 0;
for (int i = 1; i < 4; i++) sum += a[i];
printf("%d", sum);
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
{2, 9, 7, 4} retorna -1 no primeiro elemento diferente. Onde deve ocorrer o retorno que indica falha?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
a[i] por a[5 - 1 - i] para i = 0 e i = 1, começando por {4, 7, 1, 8, 6}?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
void set_first(int a[]) executa a[0] = 11;. Qual é o primeiro elemento do arranjo da função chamadora após a chamada?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
void f(int a[], size_t n), ponteiros ocupam 8 bytes e inteiros, 4 bytes. Qual é o resultado de sizeof a / sizeof a[0]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
size_t para n e i. Ela deve imprimir um arranjo de trás para a frente e funcionar para n = 0. Qual parâmetro e laço atendem aos dois requisitos?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
a[4] de int a[4]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 3: Escolha e verifique operações de biblioteca10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
char s[] = "wxyz"; memmove(s, &s[1], 4);, o que s contém como cadeia?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
"silver"?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
char label[10] = "blue"; strcat(label, "berry"); pode armazenar seu resultado completo?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
char out[20]; strcat(out, "go");. Por que essa é uma forma inválida de começar a construir uma cadeia?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
char *p = strrchr("archive.backup.bin", '.');, qual texto começa em p?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
"on,,off;wait". As chamadas usam strtok(s, ",;") e depois repetem strtok(NULL, ",;") até NULL. Quais tokens são produzidos e s é preservado?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
char b[6]; int r = snprintf(b, sizeof b, "%s:%d", "job", 84); armazena e retorna?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
"AB". O programa executa strncat(b, "123456", sizeof b - strlen(b) - 1). Qual é o texto resultante e sua quantidade de bytes armazenados, incluindo o zero?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 4: Tabelas, listas de texto e entrada na inicialização10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
int table[4][6]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
sizeof table[0] para int table[3][5]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
{{2, 7, 4}, {6, 1, 5}}. Um laço inicializa sum uma vez com zero antes dos dois laços, soma uma linha por vez e imprime após cada linha sem reinicializar sum. Quais valores são impressos e como isso é corrigido?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
char names[3][width] armazenar “Iris”, “Magnolia” e “Ash” como cadeias ASCII completas?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
char rows[2][5] = {"oak", "elm"}; e const char *refs[] = {"oak", "elm"};. Ele deve substituir a primeira palavra listada pelo texto completo “cedar”. Qual tratamento é válido para cada disposição?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
./mark "West Room" 9. Quais são argc e argv[2]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 5: Limites de entrada e resultados completos10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
char word[18]?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
"pine\n" para um arranjo de 10 bytes. Quais são o strlen do resultado e o índice de seu terminador?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
char b[6] sem outras leituras. Qual texto a segunda chamada armazena?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
counts[c - 'a']++ não é seguro para entrada de caractere não verificada?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
char out[6]. A chamada snprintf(out, sizeof out, "%s%d", "R-", 1234) é seguida de if (r > sizeof out) reject();, onde r é seu retorno não negativo. O que é armazenado, esse teste o rejeita e o que deve mudar?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
ERANGE e exige *end == '\0', mas não verifica end == start. Qual entrada inválida ainda pode ser aceita como zero?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
41 C3 A9 E2 82 AC 00. Um programa a copia para char b[5], reservando sua última posição para zero. Quais são o strlen resultante, a contagem de bytes iniciais e a validade da codificação?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Conjunto 6: Rastreie e corrija operações combinadas em C10 Questões de Prática
Salve esta aula para ver todas as respostas e praticar cada conjunto.
Questão 1 de 10
int a[4] = {[2] = 9};?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 2 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 3 de 10
int g[3][4], qual é a posição de elemento de g[2][1], contada a partir de zero, no armazenamento por linhas?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 4 de 10
./pick "" blue. Como argv[1] e argv[argc] diferem?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 5 de 10
int a[], size_t n e executa a[0] = 0; n = 0;. A função chamadora forneceu {5, 8, 2} e a quantidade 3 e depois calcula a soma inteira de seus elementos dividida por sua quantidade. Qual média e qual quantidade da função chamadora resultam?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 6 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 7 de 10
strncpy(b, "planet", sizeof b);. O programa exige a palavra original completa. Qual correção satisfaz o requisito?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 8 de 10
int values[4] = {14, 28, 35, 49};. Ele converte completamente “04” com strtol na base decimal, aceita seleções de 1 a 4 e depois lê values[selected]. Deve permitir as quatro seleções e mapear a seleção 1 para o primeiro valor. O que acontece e qual regra de índice corrige isso?Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 9 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Questão 10 de 10
Mostrar respostaOcultar resposta
Salve esta aula para ver esta resposta.
Travou em uma questão sua? Ajuda com Tarefas
Termos-Chave
A
Acesso fora dos limites
a[8] em um arranjo de oito elementos é inválido mesmo que uma execução de teste pareça retornar um valor útil.Acumulador
sum em zero permite que cada sum += a[i] some o próximo elemento do arranjo ao total atual.argc
argc fornece a contagem de cadeias de argumentos fornecidas a main, normalmente incluindo a cadeia usada para iniciar o programa../label red blue em um shell comum resulta em argc igual a 3: o nome usado para iniciar o programa e duas cores.Argumento de linha de comando
argv
argv fornece acesso por índice às cadeias de argumentos, seguidas por um ponteiro nulo na posição indicada por argc.argc, um programa pode usar strcmp(argv[1], "-v") para reconhecer sua primeira opção.Armazenamento por linhas
grid[0][3] no armazenamento de uma tabela de quatro colunas é grid[1][0].Arranjo
int levels[6] reserva seis inteiros; atualizar levels[2] altera o terceiro valor armazenado.Arranjo de ponteiros para cadeias de caracteres
const char *names[] = {"Al", "Mina"} armazena duas referências e permite substituir uma referência.Arranjo de saída
out[i] enquanto a função chamadora mantém a responsabilidade pelo arranjo.Arranjo de tamanho variável
const int n = 6; int a[n]; cria um VLA porque n não é uma expressão constante.ASCII
'8' - '0' produz 8 porque os códigos dos caracteres de algarismos são consecutivos.atoi
atoi converte uma parte numérica inicial para int sem um relatório confiável de erros e tem comportamento indefinido em caso de estouro.atoi, portanto um número retornado não estabelece que toda a entrada era numérica.B
Buffer
Busca sequencial
{3, 8, 2} encontra o valor no índice 2 após verificar os elementos anteriores que são diferentes.Byte de continuação
10 e vem após um byte inicial dentro de um ponto de código codificado com vários bytes.C
Cadeia de caracteres em C
char pet[] = "dog" contém três letras seguidas de um caractere de valor zero.Cadeia vazia
char message[20] = "" fornece um destino vazio válido para um acréscimo posterior que caiba em sua capacidade.Capacidade
Classificação de caracteres
<ctype.h>.isdigit((unsigned char) c) fornece um resultado diferente de zero quando o byte armazenado representa um algarismo decimal.Codificação de caracteres
Código de saída
main indica conclusão bem-sucedida.Coluna
g[r][c].g[r][c].Comparação pela ordem dos valores dos bytes
strcmp coloca uma letra latina acentuada depois do z ASCII porque seu byte inicial tem valor maior.Comportamento indefinido
Comprimento da cadeia de caracteres
Concatenação
Configuração regional
toupper, que opera em bytes, na configuração regional “C” não transforma uma letra acentuada UTF-8 completa em sua forma maiúscula.Constante de caractere
int, que representa um código de caractere, como o código de uma letra.printf("%c %d", 'B', 'B') exibe a letra B e o valor numérico 66.Contagem de atribuições
scanf concluiu com sucesso, usada para verificar se os dados solicitados foram realmente lidos.Conversão numérica
% 26.D
Delimitador
Deslocamento de César
E
Elemento
int a[3] = {8, 1, 6}, o elemento a[1] contém 1 e pode receber outro inteiro.ERANGE
ERANGE identifica um erro de faixa informado por meio de errno, como um resultado de strtol grande ou pequeno demais para long.errno como zero antes da conversão e depois verifique se é ERANGE antes de aceitar uma sequência longa de algarismos.Erro de uma unidade
i <= n faz um percurso de n elementos indexado a partir de zero tentar um acesso extra no índice n.Estouro de buffer
F
Faixa de valores permitida pela aplicação
fgets
fgets lê uma entrada de linha com limite de tamanho, mantendo uma nova linha alcançada e acrescentando um terminador quando lê texto com sucesso.Filtragem
Fim de arquivo
fgets ainda pode ter sucesso se tiver lido caracteres antes de alcançar essa condição.fgets suficientemente grande receba esse texto final.Í
Índice
I
Inicializador
int hits[4] = {3} inicializa o primeiro contador com 3 e os outros três contadores com zero.L
Laços aninhados
Largura da linha
int g[][6] aceita linhas com seis inteiros de largura, enquanto a função chamadora fornece a quantidade de linhas separadamente.Largura de campo
%s limita a quantidade de caracteres de entrada armazenados antes do byte zero terminador adicional.char word[10], a conversão %9s reserva o décimo byte disponível para o terminador.Limite de palavra
Linha
int table[2][5], table[1] designa a segunda linha, que contém cinco posições de inteiros.Linha parcial
fgets, portanto o segundo trecho não deve se tornar uma nova resposta.Lista de cadeias de caracteres com capacidade fixa por cadeia
char labels[5][12], cada rótulo tem doze bytes de armazenamento, mesmo quando seu texto atual é menor.Literal de cadeia de caracteres
const char *label = "ready" refere-se a um literal; uma cópia modificável pode usar char label[] = "ready".M
Máscara de bits
0xC0 mantém os dois bits mais significativos para que um programa possa reconhecer o padrão de continuação UTF-8.Matriz bidimensional
int board[4][6] fornece 24 inteiros, acessados por quatro índices válidos de linha e seis índices válidos de coluna.memcmp
memcmp compara uma quantidade fixa de bytes e informa sua ordem, testando representações armazenadas em vez de valores numéricos.memcmp encontra bytes armazenados diferentes.memcpy
memcpy copia exatamente uma quantidade solicitada de bytes entre regiões que não se sobrepõem, sem interpretar terminadores de cadeia.memcpy(b, a, sizeof a) copia todo o armazenamento do arranjo a quando b tem espaço suficiente e é uma região separada.memmove
memmove copia uma quantidade solicitada de bytes com comportamento definido mesmo quando as regiões de origem e destino se sobrepõem.memmove.memset
memset preenche uma região com um valor de byte repetido, sem atribuir esse valor numérico separadamente a cada elemento do arranjo.memset(counts, 0, sizeof counts) zera um arranjo de inteiros; o valor de byte 1 não atribuiria o inteiro 1.P
Parâmetro de arranjo
int a[] ainda precisa de um comprimento separado antes de poder percorrer sua entrada com um laço.Parâmetro de tipo variavelmente modificado
int g[rows][cols] após parâmetros que definem quantidades positivas e correspondentes de linhas e colunas.Parâmetro qualificado com const
const int a[] porque somar os valores de entrada não exige alterá-los.Ponteiro de fim da conversão
strtol retorna 9, mas o ponteiro de fim da conversão se refere ao z que não foi consumido.Ponteiro nulo
strchr(name, '.') != NULL antes de usar seu resultado como o início de um sufixo de nome de arquivo.Ponto de código Unicode
Q
Quantidade de elementos em uso
R
Redução modular sem sinal
size_t não pode parar ao se tornar negativa; use i > 0 e acesse a posição i - 1.S
Sequência de escape
"A\nB" contém uma nova linha entre suas letras; a barra invertida e o n codificam um caractere.size_t
size_t é um tipo inteiro sem sinal usado para tamanhos de objetos e retornado por sizeof; ele é comumente usado para comprimentos de arranjos.printf("%zu", sizeof data) usa o formato de tamanho para imprimir a quantidade de bytes ocupados por data.snprintf
snprintf formata texto dentro de uma capacidade fornecida e retorna o comprimento completo necessário para o texto ou um resultado negativo de erro.strcat
strcat acrescenta uma cadeia de origem no terminador existente do destino e grava um novo terminador após o texto combinado.strchr
strchr encontra o primeiro caractere correspondente em uma cadeia e retorna sua posição, ou um ponteiro nulo se não houver correspondência.strchr encontra o trecho final “.part.ext”, incluindo o primeiro ponto.strcmp
strcmp compara cadeias terminadas em nulo como bytes sem sinal e retorna um resultado negativo, zero ou positivo conforme sua ordem.strcmp("oak", "oak") == 0 testa conteúdos iguais mesmo quando as duas cadeias ocupam espaços de armazenamento separados.strcpy
strcpy copia uma cadeia de origem completa e seu terminador para um destino que não se sobrepõe à origem e tem armazenamento disponível suficiente.char out[5].strcspn
strcspn mede a parte inicial de uma cadeia que não contém nenhum dos caracteres fornecidos em seu segundo argumento.strcspn("fir:oak", ":,") retorna 3 porque o primeiro separador listado ocorre após as três letras de fir.strlen
strlen percorre uma cadeia válida até seu terminador e retorna a quantidade de bytes anteriores como um valor size_t.char tag[30] = "oak", strlen(tag) é 3, enquanto sizeof tag informa a capacidade completa de 30 bytes.strncat
strncat acrescenta no máximo uma quantidade especificada de bytes de texto da origem e depois grava um terminador após eles.strncmp
strncmp compara no máximo uma quantidade especificada de bytes de cadeia, parando antes ao encontrar um fim ou uma diferença.strncpy
strncpy copia até um limite e preenche textos menores com zeros, mas não acrescenta terminador quando a origem preenche esse limite.strrchr
strrchr encontra o último caractere correspondente em uma cadeia e retorna sua posição, ou um ponteiro nulo se não houver correspondência.strrchr pode localizar o separador da extensão.strtol
strtol converte texto para long usando uma base escolhida e informa uma posição de parada e informações sobre erro de faixa.strtol(text, &end, 10) permite que o programa rejeite uma letra restante após algarismos decimais válidos.Subcadeia
strstr encontra sua primeira posição inicial correspondente.T
Terminador nulo
text[2] = '\0' faz as funções de cadeia pararem após os dois primeiros caracteres desse arranjo.Tokenização
strtok faz isso modificando a entrada e mantendo uma posição.strtok(NULL, ",") continua dividindo a mesma entrada modificável em vez de reiniciá-la.Transformação no próprio local
Truncamento
U
UTF-8
V
Vetor de frequências
counts[4]++ acrescenta uma ocorrência à contagem desse algarismo.- 1Primeiros programas em C
- 2Funções em C
- 3Arranjos e cadeias de caracteres em C
- 4Ponteiros em C
- 5Gerenciamento de memória dinâmica em C
- 6Estruturas de dados em C
- 7Entrada e saída de arquivos em C
- 8Depuração em C
Sobre esta aula
Crie seus próprios Materiais de Estudo
Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.