Programar em C
185 pág.

Programar em C


DisciplinaLinguagem de Programação Estruturada128 materiais1.055 seguidores
Pré-visualização40 páginas
um float fazemos sizeof(float). Se declararmos a variável f como float e
quisermos saber o seu tamanho faremos sizeof f. O operador sizeof também funciona com estruturas, uniões e
enumerações.
Outra aplicação importante do operador sizeof é para se saber o tamanho de tipos definidos pelo usuário. Seria, por
exemplo, uma tarefa um tanto complicada a de alocar a memória para um ponteiro para a estrutura ficha_pessoal,
criada na primeira página desta aula, se não fosse o uso de sizeof. Veja o exemplo:
typedef struct {
 const char *nome;
 const char *sobrenome;
 int idade;
} Pessoa;
int main(void)
{
 Pessoa *joaquim;
 joaquim = malloc(sizeof(Pessoa));
 joaquim->nome = "Joaquim";
 joaquim->sobrenome = "Silva";
 joaquim->idade = 15;
}
Outro exemplo:
#include <string.h>
#include <stdio.h>
Mais sobre variáveis 120
int
main(void)
{
 char *nome;
 nome = malloc(sizeof(char) * 10);
 sprintf(nome, &quot;wikibooks&quot;);
 printf(&quot;Site: http://pt.%s.org/&quot;, nome);
 /*
 Imprime:
 Site: http://pt.wikibooks.org/
 */
}
A sentença abaixo NÃO funciona, pois sizeof é substituído pelo tamanho de um tipo em tempo de compilação.
const char *FRASE;
FRASE = &quot;Wikibooks eh legal&quot;;
printf(&quot;Eu acho que o tamanho da string FRASE é %d&quot;, sizeof(FRASE));
Conversão de tipos
As atribuições no C tem o seguinte formato:
destino=origem;
Se o destino e a origem são de tipos diferentes o compilador faz uma conversão entre os tipos. Mas nem todas as
conversões são possíveis. O primeiro ponto a ser ressaltado é que o valor de origem é convertido para o valor de
destino antes de ser atribuído e não o contrário.
Em C, cada tipo básico ocupa uma determinada porção de bits na memória, logo, a conversão entre tipos nem
sempre é algo nativo da linguagem, por assim dizer. Há funções como atol e atof que convertem string em inteiro
longo (long int) e string em double, respectivamente. Mas em muitos casos é possível usar o casting.
É importante lembrar que quando convertemos um tipo numérico para outro, nós nunca ganhamos precisão. Nós
podemos perder precisão ou no máximo manter a precisão anterior. Isto pode ser entendido de uma outra forma.
Quando convertemos um número não estamos introduzindo no sistema nenhuma informação adicional. Isto implica
que nunca vamos ganhar precisão.
Abaixo vemos uma tabela de conversões numéricas com perda de precisão, para um compilador com palavra de 16
bits:
De Para Informação Perdida
unsigned char char Valores maiores que 127 são alterados
short int char Os 8 bits de mais alta ordem
int char Os 8 bits de mais alta ordem
long int char Os 24 bits de mais alta ordem
long int short int Os 16 bits de mais alta ordem
long int int Os 16 bits de mais alta ordem
float int Precisão - resultado arredondado
double float Precisão - resultado arredondado
long double double Precisão - resultado arredondado
Mais sobre variáveis 121
Casting: conversão manual
Se declararmos a = 10/3, sabemos que o resultado é 3,333, ou seja a divisão de dois números inteiros dá um número
real. Porém o resultado em C será o inteiro 3. Isso acontece, porque as constantes são do tipo inteiro e operações com
inteiros tem resultado inteiro. O mesmo ocorreria em a = b/c se b e c forem inteiros.
Se declararmos:
int a;
O resultado será 3.
Mesmo que declarássemos:
float a;
o resultado continua a ser 3 mas desta vez, 3,0000.
Para fazer divisão que resulte número real, é necessário fazer cast para um tipo de ponto flutuante:
a = (float)10/3
a = 10/(float)3
Nesse caso, o 10 ou o 3 é convertido para float. O outro número continua como inteiro, mas ao entrar na divisão com
um float, ele é convertido automaticamente para float. A divisão é feita e depois atribuída à variável a.
Em poucas palavras, casting é colocar um tipo entre parênteses antes da atribuição de uma variável. A forma geral
para cast é:
(tipo)variável
(tipo)(expressão)
variavel_destino = (tipo)variavel_origem;
Mas existem umas conversões automáticas:
int f(void)
{
 float f_var;
 double d_var;
 long double l_d_var;
 f_var = 1; d_var = 1; l_d_var = 1;
 d_var = d_var + f_var; /*o float é convertido em double*/
 l_d_var = d_var + f_var; /*o float e o double convertidos em 
long double*/
 return l_d_var;
 }
Repare que a conversão é feita de menor para o maior.
É possível fazer a conversão ao contrário de um tipo com mais bits para um com menos bits e isso é truncar. Nesse
caso, o cast explícito é necessário. Assim, um número float: 43.023 ao ser convertido para int deverá ser &quot;cortado&quot;,
ficando inteiro: 43. Se converter long para short, os bits mais significativos são perdidos na conversão.
O operador cast também e bastante utilizado para estruturar áreas de estoque temporários (buffer). A seguir um
pequeno exemplo:
#include <stdio.h>
typedef struct estruturar{
Mais sobre variáveis 122
 char a ;
 char b ; 
};
 
int main()
{
 char buffer[2] = {17, 4};
 estruturar *p;
 p = (struct estruturar*) &buffer;
 char* x = (char*)malloc(10);
 
 printf(&quot;a: %i b: %i&quot;, p->a,p->b);
 getchar();
 return 0;
}
Especificadores de Classe de Armazenamento
auto: O especificador de classe de armazenamento auto define variáveis automáticas, isto é, variáveis locais.
Raramente usado pois todas as variáveis locais do C são auto por definição.
static: O funcionamento das variáveis declaradas como static depende se estas são globais ou locais. Variáveis
globais static funcionam como variáveis globais dentro de um módulo, ou seja, são variáveis globais que não são
conhecidas em outros modulos. Isto é util se quisermos isolar pedaços de um programa para evitar mudanças
acidentais em variáveis globais.
Exemplo:
 
#include <stdio.h>
 
void f(void)
{
 static int i = 0; /* só sera inicializada a 0 na primeira chamada 
de f */
 int j = 0; /* j sera inicializada a cada vez */;
 i++;
 j++;
 printf(&quot;i vale %d e j vale %d.\n&quot;, i, j);
}
 
int main(void)
{
 f();
 f();
 f();
 return 0;
}
Mais sobre variáveis 123
resultado da execução do código:
i vale 1 e j vale 1.
i vale 2 e j vale 1.
i vale 3 e j vale 1.
extern :Define variáveis que serão usadas em um arquivo apesar de terem sido declaradas em outro.Todas as
variáveis e funções globais que não são definidas como static são extern por omissão.
register:Essa classe indica que a variável deve ser estocada em um registro do processador.Isso permite um ganho de
tempo comparado a variáveis estocada na memoria viva que sao executadas com menos rapidez.O numero de
registros do processador é limitado então é inútil definir toda uma estrutura com a classe register.
As variáveis estocadas dentro de um registro são obrigatoriamente local não podemos definir variáveis globais.
 
#include <stdio.h>
 
int main(void)
{
 register short i, j;
 for (i = 1; i < 1000; ++i)
 {
 for(j = 1; j < 1000; ++j)
 {
 printf(&quot;\n %d %d&quot;, i, j);
 }
 }
 system(&quot;pause&quot;);
 return 0;
}
auto: Essa classe é uma herança da linguagem B. Ela serve para indicar que as variáveis locais de uma função não
são estáticas. Mas na linguagem C quando uma variável local não usa o especificador static é automatic essa palavra
reservada é inútil .
Atributos das variáveis
Estes modificadores, como o próprio nome indica, mudam a maneira com a qual a variável é acessada e modificada.
Alguns dos exemplos usam conceitos que só serão abordados nas seções seguintes, então você pode deixar esta
seção para depois se assim o desejar.
const
O modificador