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);

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 "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 < b pode 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 s1 vier lexicograficamente antes de s2.
  • Retorna zero se s1 e s2 são iguais.
  • Retorna valor maior que zero se s1 vier depois de s2.
    strcmp compara os bytes (como unsigned 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, usar strcasecmp (POSIX) ou converter antes.
  • Para ordenação segundo regras locais (por exemplo acentos), usar strcoll.
  • Nunca use a < b para 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) ...).

Exercícios relacionados