Caractere 'ã' influencia tamanho do retorno de strlen()???

Iniciado por edjin, 20 de Janeiro de 2012, 17:04

tópico anterior - próximo tópico

edjin

Estou com um probleminha em um exercício que pede para o usuário digitar o nome do estado (ex: São Paulo, Pernambuco, Paraíba etc.) e posteriormente retorna a sigla (ex: SP, PE, PB etc.). Mas quando digitado São Paulo, o programa só imprime a primeira letra S... alias, até imprime uma possível segunda letra para a sigla, mas pelo tamanho da string, imprime o espaço entre as duas palavras ???...
Pelos testes que fiz usando o gdb, percebi que se digitar Sao Paulo (sem o '~') imprime a saída 'SP'. A função strlen() retorna tamanhos diferentes para cada caso. O que poria ser?

Compilado com $gcc -Wall -ggdb -o programa programa.c
no ubuntu 10.10 e gcc-4.3.

Logo abaixo, o código:
(obs.: Sei que o código está muito amador e sujo, mas foi isso que saiu...)

/*
12.6.7 Escreva um programa em C que recebe via teclado o nome de um
estado (máximo 80 caracteres). Logo após a entrada do nome do estado
imprima: a sigla do estado (2 letras maiúsculas), conforme exemplos
abaixo:

Exemplo:
Estado: Rio Grande do Sul <enter>
Sigla: RS

Estado: são paulo <enter>
Sigla: SP

Estado: rio de janeiro <enter>
Sigla: RJ

Estado: <enter>
Observação: O programa encerra quando o usuário digitar apenas <enter> na entrada do nome do estado.

*/
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
   char *nome=malloc(80*sizeof(char));
   int tam, i = 0;
   
   do {

fputs("\nEstado, ou [ENTER] para sair: ", stdout);
fgets(nome, 80, stdin);

if(nome[0]=='\n') break;
     
tam=strlen(nome);
tam--;

/** breackpoint gdb **/

// Primeira letra da Sigla ///
fprintf(stdout, "Sigla: %c", toupper(nome[0]));

// Laço para segunda letra da Sigla ///
for(i=tam; i>0; i--) {

// Casos 1º Amapá AP ( Incompatibilade na sequencia ) ///
if( toupper(nome[0]) == 'A' && toupper(nome[3]) == 'P' ) {
fprintf(stdout, "%c", toupper(nome[3]));
break;
}

// Casos 2º Mato Grosso MT ( Incompatibilade na sequencia ) ///
if( toupper(nome[5]) == 'G' && tam < 14 ) {
fprintf(stdout, "%c", toupper(nome[2]));
break;
}

// Casos 3º Paraiba PB ( Incompatibilade na sequencia ) ///
if(toupper(nome[5]) == 'B') {
fprintf(stdout, "%c", toupper(nome[5]));
break;
}

// Casos 4º Parana PR ( Incompatibilade na sequencia ) ///
if(toupper(nome[0]) == 'P' && toupper(nome[4]) == 'N') {
fprintf(stdout, "%c", toupper(nome[2]));
break;
}

// Casos 5º Roraima RR ( Incompatibilade na sequencia ) ///
if(toupper(nome[0]) == 'R' && toupper(nome[2]) == 'R') {
fprintf(stdout, "%c", toupper(nome[2]));
break;
}

// Casos 6º São Paulo SP ( Incompatibilade na sequencia ) ///
if(toupper(nome[0]) == 'S' && toupper(nome[4]) == 'P') {

fprintf(stdout, "%c", toupper(nome[4]));
break;
}

// Para segunda letra das Siglas compostas (dois ou mais nomes) ///
if(nome[i] == ' ' && tam>=9) {
fprintf(stdout, "%c", toupper(nome[i+1]));
break;
}

// Para segunda letra das siglas simples (Somente um nome) ///
if(nome[i]!=' ' && tam<=10) {
fprintf(stdout, "%c", toupper(nome[1]));
break;
}
}
} while(1);
     
   free(nome);
   return 0;
}



agente100gelo

Nunca me arrisquei em C mas acho que o caminho seria:

1. Crie uma array associativa. No PHP seria:

$estado["ceará"] = "CE";
$estado["São Paulo"] = "SP";

2. Capture a informação.

3. Pela associação da array retorne a sigla.
Advogado e analista de sistema cearense.
Twitter: @glaydson

edjin

Olá agente100gelo, antes de mais nada agradecendo seu interesse pelo caso... Então, assim resolveria o caso sem problema ,  mas teria que comparar com duas strings, uma com 'ã' e outra com 'a', sem contar as diversas possibilidades dos outros estados, (achei mais fácil fazer o trabalho só com a string digitada) e mesmo assim continuaria a duvida com relação a strlen(). Mas muito obrigado pela resposta. []s

irtigor

#3
"ç" entre outros caracteres, não são representados com apenas um byte, exemplo:

fprintf(stdout, "Tamanho: %d", strlen("→"));

Vai retornar 3. Sendo direto, você está olhando a posição errada. Isso deve ajudar:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#mod

fpissarra

edjin, o irtigor está correto em dizer:

Citação de: irtigor online 22 de Janeiro de 2012, 16:08
"ç" entre outros caracteres, não são representados com apenas um byte, exemplo:

fprintf(stdout, "Tamanho: %d", strlen("→"));

Vai retornar 3. Sendo direto, você está olhando a posição errada. Isso deve ajudar:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#mod

O motivo é o a forma com que os caracteres são codificados. As diversas distribuições Linux tendem a usar, por default, o conjunto de caracteres conhecido com UTF-8, que é um MBCS (Multi Byte Character Set), ao contrário do Windows, onde a codificação WINDOWS-1251 ou WINDOWS-1252 é usada (e é SBCS, Single Byte Character Set).

Uma possível solução (não tão garantida assim) é usar o tipo wchar_t e a biblioteca iconv para converter o charset UTF-8 para UTF-16 ou WCHAR_T. Nesses charsets cada caracter têm 16 bits de tamanho e a concatenação de multiplos "words" para compor um caracter é rara (mas, existe, no caso do UTF-16!).

Dê uma olhada neste artigo que escrevi ano passado, num blog que compartilho com um amigo. Espero que ajude...

edjin

#5
Estou estudando (google tradutor rsss) pelo link que o amigo irtigor indicou, mas com o artigo (por sinal otimo artigo) do guru fpissarra acredito que vai ser mais facil (pt_BR). Ah, e pra quem tiver a mesma duvida, leiam o artigo, pois e muito esclarecedor.
Assim que resolver a pendenga, coloco um sinal de [resolvido]...
Abracos.

fpissarra

#6
Citação de: edjin online 27 de Janeiro de 2012, 13:44
Estou estudando (google tradutor rsss) pelo link que o amigo irtigor indicou, mas com o artigo (por sinal OTIMO ARTIGO) do guru fpissarra acredito que vai ser mais facil (pt_BR). Ah, e pra quem tiver a mesma duvida, leiam o artigo, pois e muito esclarecedor.
Assim que resolver a pendenga, coloco um sinal de [RESOLVIDO]...
Abracos.

Thanks a lot!!! ;)

Infelizmente, no meu antigo blog (hoje desativado) eu tinha mais 2 artigos interessantes sobre UTF-8 e Unicode. Recomendo que você baixe a especificação aqui e dê uma lida. Unicode (UTF-8 e outros formatos) tem recursos como composição de caracteres (tipo: A e ^ podem ser mesclados e aparecer como  - por ai!)...

[]s
Fred

edjin

É muito bom poder contar com a ajuda de pessoas (fpissarra, agete100gelo, irtigor, tota entre outros...) que acreditam que somente pelo conhecimento podemos melhorar o mundo a nossa volta. Ahhh ve se ativa o blog de novo, boa informação tem que ser difundida, mesmo que os meios sejam difíceis.

Aqui a cabeça ta pegando fogo... -->> To ansioso pelo [resolvido] lá em cima.
Abraços a todos.
.