Projeto de Algoritmos

Caracteres

Caracteres são um dos tipos-de-dados básicos da linguagem C.  Há dois tipos de caracteres em C: sem sinal (= unsigned characters) e com sinal (= signed characters).  Um caractere-sem-sinal nada mais é que um número natural entre 0255,  enquanto um caractere-com-sinal é que um número inteiro entre -128127.  A distinção entre os dois tipos é, em geral, irrelevante.  [Os padrões de bits dos dois tipos são os mesmos: 00000000 a 11111111.]  Cada caractere (de qualquer dos dois tipos) é armazenado em um byte na memória do computador.  Para criar uma variável u do primeiro tipo, diga

   unsigned char u;

Para criar uma variável c do segundo tipo, diga

   char c;

Representação gráfica de caracteres

Quando um caractere é exibido na impressora ou na tela do monitor de vídeo, ele é representado por um símbolo gráfico.  No intervalo 0..127, os dois tipos de caracteres têm os mesmos símbolos gráficos.  O símbolo do caractere 65, por exemplo, é

A

e o símbolo do caractere 66 é   B.  Alguns caracteres têm símbolos gráficos estranhos. Assim, por exemplo, o caractere 32 é representado por um espaço, o caractere 0 tem representação vazia (não ocupa espaço algum), e o caractere 10 é representado por uma mudança de linha.

Os símbolos gráficos e os efeitos não gráficos dos caracteres 0 a 127 foram estabelecidos pelo American Standard Code for Information Interchange. A correspondência é conhecida como "tabela ASCII".  Os símbolos dos caracteres-sem-sinal 128 a 255 e os símbolos dos caracteres-com-sinal -128 a -1 não estão bem padronizados: cada sistema escolhe a tabela que mais lhe agrada. Uma das tabelas mais difundidas é a ISO 8859-1 (também conhecida como ISO Latin1). Eis uma amostra dessa tabela:
símbolo
gráfico
unsigned
char
unsign
char
constante
C
caractere nulo 0 0 '\0'
mudança de linha 10 10 '\n'
quebra de página 12 12 '\f'
espaço 32 32 ' '
' 39 39 '\''
* 42 42 '*'
+ 43 43 '+'
- 45 45 '-'
/ 47 47 '/'
0 48 48 '0'
1 49 49 '1'
2 50 50 '2'
; 59 59 ';'
A 65 65 'A'
N 78 78 'N'
O 79 79 'O'
a 97 97 'a'
o 111 111 'o'
ã 227 -29 'ã'
ç 231 -25 'ç'
ÿ 255 -1 'ÿ'

A última coluna dá a representação dos caracteres como constantes do tipo char.

Cada caractere-com-sinal c no intervalo -128..-1 tem o mesmo símbolo gráfico que o caractere-sem-sinal c+256.  A tabela abaixo mostra a correspondência:  os caracteres que estão em uma mesma coluna da tabela têm o mesmo símbolo gráfico.
char   0 1 . . . 127 -128 -127 -126 . . . -2 -1
unsigned char   0 1 . . . 127 128 129 130 . . . 254 255

Do ponto de vista prático, a única diferença entre os dois tipos de caracteres é a seguinte: quando os caracteres-com-sinal são colocados em ordem crescente, as letras acentuadas (como á) precedem as não acentuadas (como a), enquanto o contrário acontece com os caracteres-sem-sinal.

Exercícios

  1. Escreva um fragmento de código que receba dois caracteres do teclado e diga se o primeiro vem antes ou depois do segundo na tabela ISO 8859-1.
  2. Escreva um programa que exiba na tela do monitor os símbolos gráficos dos caracteres 32 a 255.

Constantes e brancos

Não é cômodo escrever as constantes do tipo char como "97", "-29", "57", etc:

   char c, d, e;
   c = 97;  d = -29; e = 57;

É muito melhor escrever o símbolo gráfico do caractere embrulhado em aspas simples:

   c = 'a';  d = 'ã'; e = '9';

Para os caracteres "especiais", que têm símbolos incomuns, as constantes começam com um "\". Por exemplo, '\n' é o mesmo que 10 (a letra n é a inicial de newline) e '\0' é o mesmo que 0.

Os caracteres  9, 10, 11, 12, 13 e 32  (ou seja, '\t''\n''\v''\f'  '\r'  e  ' ')  são conhecidos como  brancos (= white-spaces).  Muitas funções C tratam todos os brancos como se fossem ' '. É o caso, por exemplo, da função scanf.

Exercícios

  1. Qual a diferença entre 'O', '0' e '\0'?
  2. Consider o vetor inteiro 65 67 72 79 85 33 10 51 50 32 43 32 52 51 32 61 32 55 53 .  Interprete esses números como caracteres. Qual o resultado?
  3. Familiarize-se com a função isspace, definida na biblioteca ctype. Ela recebe um caractere-sem-sinal c e devolve um inteiro não nulo ou 0 conforme c seja ou não um white-space. [Na verdade, o argumento de isspace não é um unsigned char mas sim um int cujo valor deve ser igual a EOF ou deve pertencer ao conjunto 0,1,..,255.]
  4. Familiarize-se com o programa programa od (de octal dump) presente em todo sistema UNIX e GNU/Linux. Este utilitário recebe um arquivo e imprime o símbolo gráfico e o valor numérico de cada caractere do arquivo.  Por exemplo, a linha de comando   od -t u1 -A d xxx  produz a impressão do símbolo gráfico e do valor decimal de cada caractere do arquivo xxx.

Char versus int

O tipo-de-dados char pode ser automaticamente convertido em int e vice-versa. (O mesmo vale para unsigned charint.)  Seguem alguns exemplos. Em todos, x tanto pode ser uma variável do tipo char quanto uma do tipo int.

  1. As atribuições x = 'A' e x = 65 têm exatamente o mesmo efeito. O comando  printf( "CHAR=%c INT=%d", x, x) , executado depois de qualquer uma das atribuições, produzirá
    CHAR=A INT=65
    
  2. As atribuições x = '0' e x = 48 têm o mesmo efeito. Depois de qualquer uma das atribuições, o comando  printf( "CHAR=%c INT=%d", x, x)  produzirá
    CHAR=0 INT=48
    
  3. As atribuições x = '\0' e x = 0 são equivalentes. Depois de qualquer uma das atribuições, o comando  printf( "CHAR=%c INT=%d", x, x)  produzirá
    CHAR= INT=0
    
  4. As atribuições x = '\n' e x = 10 são equivalentes. Depois de qualquer uma das atribuições, o comando  printf( "CHAR=%c INT=%d", x, x)  produzirá
    CHAR=
     INT=10
    
  5. As atribuições x = 'ã' e x = -29 são equivalentes. Depois de qualquer uma das atribuições, o comando  printf( "CHAR=%c INT=%d", x, x)  produzirá
    CHAR=ã INT=-29
    

Operações aritméticas

As operações aritméticas envolvendo variáveis do tipo char e unsigned char são executadas em aritmética int (todos os operandos são previamente convertidos ao tipo int) e não módulo 256, como alguém podeira imaginar.  Assim, por exemplo, se as variáveis u e v são do tipo unsigned char e valem 255 e 2 respectivamente, o valor da expressão u+v é 257.

Já as atribuições de um inteiro a um caractere são feitas módulo 256. Assim, por exemplo, se u é uma variável do tipo unsigned char e c é uma variável do tipo char então depois de

   u = 256;
   c = 130;
o valor de u será 0 e o valor de c será −126  (pois −126 é o único inteiro k no intervalo −128..127 tal que a diferença 130−k é um múltiplo inteiro de 256).  Por isso, os processos iterativos abaixo "entram em loop":
unsigned char u;
for (u = 0; u < 256; ++u) printf( ".");
char c;
for (c = 0; c < 128; ++c) printf( ".");

Já os seguintes fragmentos de código imprimem todas as letras minúsculas, como seria de se esperar:

char c;
for (c = 'a'; c <= 'z'; c += 1) printf( "%c\n", c);
int i;
for (i = 1; i < 26; ++i) printf( "%c\n", 'a' + i - 1);

 


Veja a página ISO 8859-1 na Wikipedia.
Veja UTF-8 (8-bit Unicode Transformation Format), um esquema de codificação muito diferente do ISO-8859-1.
Veja a página Unicode: What You Can Do About It Today no Cprogramming.com.
URL of this site: www.ime.usp.br/~pf/algoritmos/
Last modified: Thu Sep 5 08:07:54 BRT 2013
Paulo Feofiloff
IME-USP

Valid HTML 4.01 Transitional    Valid CSS!