Explique porque o seguinte trecho de código que pretende decidir se “abacate” vem lexicograficamente antes ou depois de “uva” está incorreto.
char *a, *b;
a = "abacate"; b = "uva";
if (a < b)
printf ("%s vem antes de %s\n", a, b);
else
printf ("%s vem depois de %s\n", a, b);
char *a, *b;
a = "abacate"; b = "uva";
if (a < b)
printf ("%s vem antes de %s\n", a, b);
else
printf ("%s vem depois de %s\n", a, b);
Passo 1
O código fornecido e o objetivo declarado:
char *a, *b;
a = "abacate"; b = "uva";
if (a < b)
printf ("%s vem antes de %s\n", a, b);
else
printf ("%s vem depois de %s\n", a, b);
O que o enunciado queria: decidir se a string
Informações dadas: as variáveis
"abacate" vem lexicograficamente antes/Depois de "uva".Informações dadas: as variáveis
a e b apontam para literais de string "abacate" e "uva" respectivamente.Passo 2
O que o
if (a < b) faz de verdade: ele compara os ponteiros a e b, ou seja, compara endereços de memória. Em C, uma variável do tipo char * contém um endereço — o local na memória onde começa a string. A expressão a < b pergunta “o endereço armazenado em a é numericamente menor que o endereço armazenado em b?” — não nada sobre os caracteres que as strings contêm.Passo 3
Por que comparar endereços é errado para ordenar strings:
- O valor numérico dos endereços depende de onde o compilador/ligador colocou os literais de string na memória; essa ordem não tem relação com a ordem lexicográfica dos caracteres.
- A comparação relacional (
<,>) entre ponteiros só é bem definida pelo padrão C quando ambos os ponteiros apontam para elementos do mesmo array (ou um a mais que o fim). Comparar ponteiros que referem a objetos diferentes resulta em comportamento indefinido. Ou seja,a < bpode até “funcionar” em uma execução (por acaso), mas não é correto nem portátil.
Passo 4
Exemplo mental para fixar: os literais
"abacate" e "uva" podem ficar em posições de memória quaisquer, por exemplo "uva" pode acabar num endereço menor que "abacate" no binário final — aí a < b seria falso, mesmo que lexicograficamente "abacate" venha antes. Logo, o resultado é acidental e não corresponde à comparação de texto.Passo 5
O que significa “comparar lexicograficamente” (explicação didática):
- Comparação lexicográfica é como em um dicionário: compara-se o primeiro caractere de cada string; se são diferentes, a ordem é dada por esses caracteres. Se são iguais, passa-se ao segundo caractere, e assim por diante. Se uma string termina e a outra continua, a mais curta vem antes.
- Aplicando a
"abacate"vs"uva": primeiro caractere de"abacate"é'a'e de"uva"é'u'. Como'a'vem antes de'u'na tabela de caracteres (ASCII/UTF-8),"abacate"vem antes de"uva".
Passo 6
Como fazer corretamente em C: usar a função padrão
strcmp (declaração em <string.h>). Assinatura e semântica:int strcmp(const char *s1, const char *s2);
- Retorna valor menor que zero se
s1vier lexicograficamente antes des2. - Retorna zero se
s1es2são iguais. - Retorna valor maior que zero se
s1vier depois des2.
strcmpcompara os bytes (comounsigned char) dos caracteres, caracter por caractere, até encontrar a primeira diferença ou o'\0'.
Passo 7
Código corrigido exemplo (uso recomendado de
const char * para literais):#include <stdio.h>
#include <string.h>
int main(void) {
const char *a = "abacate";
const char *b = "uva";
int r = strcmp(a, b);
if (r < 0)
printf("%s vem antes de %s\n", a, b);
else if (r > 0)
printf("%s vem depois de %s\n", a, b);
else
printf("%s é igual a %s\n", a, b);
return 0;
}
Isto faz exatamente a comparação lexicográfica desejada, de forma portátil e correta.
Passo 8
Se quiser entender o que
strcmp faz internamente, um esqueleto simples (didático) é este:int my_strcmp(const char *s1, const char *s2) {
while (*s1 != '\0' && *s1 == *s2) {
s1++; s2++;
}
return (unsigned char)*s1 - (unsigned char)*s2;
}
Explicação passo a passo: percorre os caracteres enquanto forem iguais e não for encontrado o terminador
'\0'; quando encontra uma diferença (ou o fim), retorna a diferença dos códigos dos caracteres (tratados como unsigned char), que segue a regra menor/igual/maior que zero.Passo 9
Notas extras e boas práticas:
- Declare literais como
const char *para indicar que não se deve modificar o conteúdo. strcmpé case-sensitive; para comparação sem diferenciar maiúsculas/minúsculas, usarstrcasecmp(POSIX) ou converter antes.- Para ordenação segundo regras locais (por exemplo acentos), usar
strcoll. - Nunca use
a < bpara comparar strings.
Resposta
Porque
if (a < b) compara os endereços (ponteiros) e não o conteúdo das strings; compare strings lexicograficamente com strcmp(a, b) (por exemplo if (strcmp(a,b) < 0) ...).