Buscar

Programação_em_C

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 73 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 73 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 73 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Programação em C
	1 Introdução
	A linguagem C é uma linguagem de programação popular e amplamente utilizada para criar programas de computador. Programadores no mundo todo utilizam a linguagem C, pois ela oferece o máximo controle e eficácia. Se você é um programador, ou pretende se tornar um, eis alguns benefícios que você desfrutará ao aprender a linguagem C:
você poderá ler e escrever código para diversas plataformas. Desde microcontroladores até sistemas científicos mais avançados podem ser criados em C e diversos sistemas operacionais modernos são escritos em C;
o avanço para a linguagem C++ orientada para objeto torna-se muito mais fácil. A linguagem C++ é uma extensão de C e é praticamente impossível aprender C++ sem antes aprender C.
	
Esta animação mostra a execução de um programa simples em C. Ao final deste artigo, você entenderá como ela funciona
	2 O que é C?
	C é uma linguagem de programação de computadores. Isso significa que você pode usá-la para criar listas de instruções para um computador seguir. A linguagem C é uma das milhares de linguagens de programação atualmente em uso. Existe há várias décadas e ganhou ampla aceitação por oferecer aos programadores o máximo em controle e eficiência. A linguagem C é fácil de aprender: pode ter um estilo um tanto criptográfico comparada às outras linguagens, mas isso é logo superado.
	
	A linguagem C é o que se chama de linguagem compilada. Isso significa que, uma vez escrito o programa em C, ele deve ser passado por um compilador para transformar seu programa em executável para o computador rodar (executar). Um programa em C possui um formato legível ao homem, enquanto o executável gerado no compilador possui a forma legível para a máquina e é executada por ela. Isto significa que para escrever e executar um programa em C, você precisa ter acesso a um compilador de C. Se estiver usando uma máquina UNIX (por exemplo, escrevendo scripts CGI em C no seu computador UNIX, ou se você é um estudante que trabalha em uma máquina UNIX de um laboratório), o compilador de C está disponível gratuitamente. Ele é chamado “cc” ou “gcc” e está disponível na linha de comando. Se você é um aluno, estão a escola lhe fornecerá um compilador (descubra qual a escola usa e aprenda mais sobre ele). Se estiver trabalhando em casa em uma máquina Windows, você precisará fazer o download de um compilador de C gratuito ou comprar um compilador comercial. Um compilador comercial amplamente utilizado é o ambiente Visual C++ da Microsoft (ele compila programas em C e C++). Mas, infelizmente, este programa custa caro. Caso não disponha de algumas centenas de dólares para gastar em um compilador comercial, você pode usar um dos compiladores gratuitos disponíveis na internet. Veja delorie.com/djgpp como ponto de partida em sua pesquisa.
	Vamos começar com um programa em C bastante simples e progredir a partir dele. Vamos supor que você usará a linha de comando UNIX e o gcc como seu ambiente para estes exemplos, mas caso contrário, todos os códigos também funcionarão (basta compreender e usar o compilador que tiver disponível).
	3 O mais simples programa em C
	Vamos começar com o programa em C mais simples possível e usá-lo tanto para entender os fundamentos da linguagem C como o processo de compilação em C. Digite o programa seguinte em um editor de textos padrão (vi ou emacs no UNIX, Bloco de notas no Windows ou TeachText no Macintosh). Depois salve o programa em um arquivo denominado samp.c. Se deixar de incluir .c, você provavelmente receberá informação de algum tipo de erro ao compilá-lo (portanto, não se esqueça de inserir o .c). Certifique-se também de que o editor não anexe automaticamente caracteres extras (como .txt) ao nome do arquivo. Eis o primeiro programa:
#include <stdio.h>
int main()
{
	printf("Este é o resultado do meu primeiro program!\n");
	return 0;
}
	Quando executado, este programa instrui o computador a imprimir a linha: “Este é o resultado do meu primeiro programa!”, e depois encerra o programa.
	Posição
Ao escrever este programa, posicione #include de forma que o sinal # esteja na coluna 1 (mais à esquerda). Isso facilita o seu entendimento, mas na verdade o espaçamento e recuo podem ser do jeito que você preferir. Em alguns sistemas UNIX, você encontrará um programa chamado cb, o C Beautifier (algo como “embelezador de C”), que formata códigos. O espaçamento e recuo mostrados acima são um bom exemplo a seguir.
	Para compilar este código, siga estas etapas:
em uma máquina UNIX, digite gcc samp.c -o samp (se gcc não funcionar, tente cc). Esta linha executa o compilador em C chamado gcc, pede que compile samp.c e que nomeie o arquivo executável criado como samp. Para executar o programa, digite samp (ou em algumas máquinas UNIX, ./samp);
em uma máquina rodando DOS ou Windows e usando DJGPP (em inglês), digite o seguinte no prompt do MS-DOS: gcc samp.c -o samp.exe. Esta linha executa o compilador em C chamado gcc, Pede que compile samp.c e que nomeie o arquivo executável criado como samp.exe. Para executar o programa, digite samp;
se estiver trabalhando com algum outro compilador ou sistema de desenvolvimento, leia e siga as instruções dele para compilar e executar o programa.
	Você verá “Este é o resultado do meu primeiro programa!” ao executá-lo. Veja o que aconteceu ao compilar o programa:
	
	Caso tenha cometido um erro de digitação no programa, ele não compilará ou não poderá ser executado. Se o programa não foi compilado ou não executa corretamente, edite-o e localize os erros de digitação. Corrija o erro e tente novamente.
	4 O mais simples programa em C: o que está acontecendo?
	Vamos analisar este programa e aprender o que as diferentes linhas de comando fazem:
este programa em C começa com #include <stdio.h>. Esta linha inclui uma “biblioteca padrão de I/O” (entrada/saída) em seu programa, que permite ler a entrada a partir do teclado (denominada “entrada padrão”),  exibir o resultado em uma tela (denominada “saída padrão”), processar arquivos de texto armazenados em disco e assim por diante. É uma biblioteca extremamente útil. A linguagem C possui um grande número de bibliotecas padrão como stdio, incluindo bibliotecas de strings de caracteres, de horário e de funções matemáticas. Uma biblioteca é simplesmente um pacote de códigos que alguém escreveu anteriormente para simplificar a sua vida (discutiremos bibliotecas daqui a pouco);
a linha int main( ) declara a função principal. Todo programa em C deve ter uma função denominada main em algum lugar no código. Aprenderemos mais sobre as funções em breve. O programa começa a ser executado a partir da primeira linha da função main;
em C, os símbolos {e} marcam o começo e término de um bloco de código. Neste caso, o bloco de código que compõe a função principal contém duas linhas;
a instrução printf em C permite enviar o resultado para a saída padrão (para nós, a tela). A parte entre aspas é denominada string de formato e descreve como os dados serão formatados quando impressos. A string de formato pode conter strings de caracteres como “Este é o resultado do meu primeiro programa!”, símbolos de quebra de linha (\n), e operadores como expressão de controle para variáveis (vide abaixo). Se você está usando UNIX, pode digitar man 3 printf para obter uma documentação completa sobre a função printf. Caso contrário, consulte a documentação incluída em seu compilador para mais detalhes sobre a função printf;
a linha return 0; faz com que a função retorne um código de erro de 0 (sem erros) à shell que iniciou a execução. Esta capacidade será discutida em detalhes mais tarde.
	5 Variáveis
	Como programador, você com freqüência desejará que seu programa se “lembre” de um valor. Por exemplo, se seu programa solicita um valor do usuário, ou se ele calcula um valor, você vai querer armazená-lo em algum lugar para usá-lo mais tarde. O modo como seu programa se lembra das coisas é por meio do uso de variáveis. Por exemplo:
int b;
	Esta linha diz: “Quero criar um espaço chamado b que possa conterum valor inteiro”. Uma variável tem um nome (neste caso, b) e um tipo (neste caso, int, um inteiro). Você pode armazenar um valor em b escrevendo algo assim:
b = 5;
	Você pode usar o valor em b escrevendo algo assim:
printf(“%d”, b);
	Na linguagem C, há vários tipos padrões de variáveis:
int → valores inteiros (número inteiro);
float → valores de ponto flutuante;
char → valores de caractere único (como “m” ou “Z”).
	6 Printf
	A instrução printf permite enviar o resultado para a saída padrão. Para nós, o termo “saída padrão” se refere à tela (embora você possa redirecionar a saída padrão para um arquivo de texto ou outro comando).
	Eis outro programa que o ajudará a aprender mais sobre printf:
#include <stdio.h>
int main( )
{
	int a, b, c;
	a = 5;
	b = 7;
	c = a + b;
	printf("%d + %d = %d\n", a, b, c);
return 0;
}
	Digite este programa em um arquivo e salve-o como add.c. Compile-o com a linha gcc add.c -o add e depois o execute digitando add (ou ./add). Você verá a linha “5 + 7 = 12” como resultado.
	Eis uma explicação das diferentes linhas neste programa:
a linha int a, b, c; declara três variáveis de número inteiro denominadas a, b e c. 
a próxima linha inicializa a variável nomeada a para o valor 5. 
a próxima linha define 7 para b . 
a próxima linha soma a e b e "atribui" o resultado a c.
	O computador adiciona o valor em a (5) ao valor em b (7) para formar o resultado 12 e então coloca o novo valor (12) na variável c. Por este motivo, o sinal = nesta linha é denominado “operador de atribuição”.
a instrução printf depois imprime a linha “5 + 7 = 12”. As expressões de controle %d na instrução printf atuam como expressão de controle de valores. Há 3 expressões de controle %d, e no final da linha printf há três nomes de variável: a, b e c. A linguagem C liga o primeiro %d ao a e o substitui por 5. Ele liga o segundo %d com b e o substitui por 7, faz a correspondência do terceiro %d com c e o substitui por 12. Depois, imprime a linha completa na tela: 5 + 7 = 12. O +, o = e o espaçamento são parte da linha de formato e são automaticamente integrados entre os operadores %d conforme especificado pelo programador.
	7 Printf: lendo os valores de usuário
	O programa anterior é bom, mas seria melhor se ele lesse os valores 5 e 7 inseridos pelo usuário, em vez de usar constantes. Em vez disso, tente este programa:
#include <stdio.h>
int main()
{
	int a, b, c;
	printf("Entre o primeiro valor:");
	scanf("%d", &a);
	printf("Entre o segundo valor:");
	scanf("%d", &b);
	c = a + b;
	printf("%d + %d = %d\n", a, b, c);
	return 0;
 }
	Eis como este programa funciona ao ser executado:
	Faça as alterações, depois compile e rode o programa para certificar-se de que funciona. Observe que scanf usa as mesmas strings de formato que printf (digite man scanf para mais informação). Observe também o & na frente de a e b. Este é o operador de endereço em C: ele retorna o endereço da variável (isto não fará sentido até aprendermos sobre os ponteiros). Você tem de usar o operador & em scanf em qualquer variável do tipo char, int ou float, bem como tipos de estrutura (que discutiremos em breve). Se excluir o operador &, você receberá um erro ao executar o programa. Tente executá-lo para ver que tipo de erro ocorre.
	Vamos ver algumas variações para entender printf completamente. Eis uma instrução simples de printf:
printf(“Hello”);
	Esta chamada para printf tem uma string de formatos que diz ao printf para enviar a palavra “Hello” para a saída padrão. Compare-a com:
printf(“Hello\n”);
	A diferença entre as duas é que a segunda versão exibe a palavra “Hello” seguida de uma quebra de linha.
	As linha seguintes mostram como exibir o valor de uma variável usando printf.
printf("%d", b);
	O %d é uma expressão de controle que será substituída pelo valor da variável b quando a instrução printf for executada. Freqüentemente, você vai desejar incluir o valor entre outras palavras. Uma forma de fazer isso é:
printf("A temperatura é ");
printf("%d", b);
printf(" degrees");
	Um modo mais fácil de dizer isso é:
printf("A temperatura é %d graus\n", b);
	Você também pode usar múltiplas expressões de controle %d em uma instrução printf:
printf("%d + %d = %d\n", a, b, c);
	Na instrução printf, é extremamente importante que o número de operadores na string de formato corresponda exatamente ao número e tipo de variáveis que a seguem. Por exemplo, se a string de formatos contém três operadores %d, então ela deve ser seguida por exatamente três parâmetros do mesmo tipo e ordem que aqueles especificados pelos operadores.
	Você pode imprimir todos os símbolos normais na linguagem C com printf usando expressões de controle diferentes:
int (valores inteiros) usam %d;
float (valores de ponto flutuante) usam %f;
char (valores de caractere simples) usam %c;
strings de caracteres (matrizes de caracteres, discutiremos mais tarde) usam %s.
	Você pode aprender mais sobre as nuances do printf em uma máquina UNIX digitando man 3 printf. Qualquer outro compilador de C que você utilize provavelmente virá acompanhado de um manual ou arquivo de ajuda que contém uma descrição do printf.
	8 Scanf
	A função scanf permite aceitar entradas do dispositivo padrão, que, para nós, é geralmente o teclado. A função scanf pode fazer muitas coisas diferentes, mas pode ter resultados incertos quando não usada de forma simples. É falível pois não lida muito bem com erros humanos. Mas para programas simples, ela é boa o suficiente e fácil de usar.
	A aplicação mais simples de scanf se parece com:
scanf("%d", &b);
	O programa lerá um valor inteiro digitado pelo usuário usando o teclado (%d é para inteiros, como em printf, assim b deve ser declarado como um int) e o colocará em b.
	A função scanf usa as mesmas expressões de controle da printf:
int usa %d;
float usa %f;
char usa %c;
strings de caracteres (abordados mais tarde) usam %s.
	Você DEVE colocar & na frente da variável usada em scanf. A razão para isso ficará clara assim que você aprender sobre os ponteiros. É fácil esquecer o sinal &, e se você esquecer, seu programa quase sempre apresentará problemas ao ser executado.
	Em geral, é melhor usar scanf como mostrado aqui, lendo apenas um valor do teclado. Use múltiplas chamadas do scanf para ler valores múltiplos. Em qualquer programa real, você usará as funções gets ou fgets em vez de ler o texto em uma linha por vez. Então você fará a “análise” da linha para ler seus valores. Isso serve para detectar erros na entrada e controlá-los da maneira que achar adequada.
	As funções printf e scanf exigirão um pouco de prática para serem inteiramente compreendidas, mas uma vez dominadas serão extremamente úteis.
	Tente isto!
Modifique este programa para que ele aceite 3 valores em vez de 2 e some todos eles juntos:
#include <stdio.h>
int main()
{
 int a, b, c;
 printf("Entre o primeiro valor:");
 scanf("%d", &a);
 printf("Entre o segundo valor:");
 scanf("%d", &b);
 c = a + b;
 printf("%d + %d = %d\n", a, b, c);
 return 0;
}
Tente apagar ou adicionar caracteres ou palavras aleatórias em um dos programas anteriores e veja como o compilador reage a tais erros de compilação.
Por exemplo, apague a variável b na primeira linha do programa anterior e veja o que o compilador faz quando você se esquece de declarar uma variável. Apague um ponto-e-vírgula e veja o que acontece. Omita uma das chaves. Remova um dos parênteses próximos à função principal. Faça uma alteração por vez e compile o programa para ver o que acontece. Simulando erros como esses você pode aprender sobre diferentes erros de compilação, o que facilitará futuras detecções quando você os cometer.
	Erros a serem evitados na linguagem C
Usar letras maiúsculas e minúsculas aleatoriamente. Letras maiúsculas e minúsculas são importantes na linguagem C, portanto você não pode digitar Printf ou PRINTF. É obrigatório que seja printf;
Esquecer de usar o & em scanf;
Parâmetros em excesso ou a falta deles após a instrução de formato em printf ou scanf;
Esquecerde declarar o nome de uma variável antes de utilizá-la.
	9 Desvio e looping
	Em C, as instruções if e loops while regem-se pelos princípios das expressões Booleanas. Eis um programa simples em C que demonstra uma instrução if:
#include <stdio.h>
int main()
{
	int b;
	printf("Digite um valor:");
	scanf("%d", &b);
	if (b < 0)
	printf("O valor é negativo ");
	return 0;
}
	Este programa aceita um número do usuário. Ele então testa esse número utilizando uma instrução if para ver se ele é menor que 0. Se for, o programa imprime uma mensagem. Caso contrário, o programa não faz nada. A parte (b < 0) do programa é a expressão booleana. A linguagem C avalia esta expressão para decidir se imprime ou não a mensagem. Se a expressão booleana se mostra Verdadeira, então a linguagem C executa a linha imediatamente posterior à instrução if (ou um bloco de linhas entre chaves logo após a instrução if). Se a expressão booleana se mostrar Falsa, então a linguagem C pula a linha ou bloco de linhas logo após a instrução if.
	Eis um exemplo um pouco mais complexo:
#include <stdio.h>
int main()
{
	int b;
	printf("Digite um valor:");
	scanf("%d", &b);
	if (b < 0)
	printf("O valor é negativo ");
	else if (b == 0)
	printf("O valor é zero ");
	else
	printf("O valor é positivo ");
	return 0;
}
	Neste exemplo, as seções else if e else avaliam tanto para valores positivos como zero.
	Eis uma expressão booleana mais complicada:
if ((x==y) && (j>k))
	z=1;
else
	q=10;
	Esta instrução diz: “Se o valor da variável x for igual ao valor da variável y, e se o valor da variável j for maior que o valor da variável k, então defina a variável z como 1; de outro modo, defina a variável q como 10”. Você usará instruções if como esta em todos os seus programas C para tomar decisões. De um modo geral, a maioria das decisões será simples como o primeiro exemplo, mas, eventualmente, as coisas podem ser um pouco mais complicadas.
	Observe que a linguagem C utiliza == para testar a igualdade, enquanto utiliza = para atribuir um valor a uma variável. O símbolo && em C representa uma operação booleana AND.
	Aqui estão todos os operadores booleanos em C:
igualdade	==
menor que	< 
maior que	> 
menor ou igual	<= 
maior ou igual	>= 
desigualdade	!= 
e	&& 
ou	|| 
não	!
	Você descobrirá que as instruções while são tão fáceis de utilizar como as instruções if. Por exemplo:
while (a < b)
{ 
	print("%d\n", a); 
	a = a + 1;
}
	Isso faz com que duas linhas entre chaves sejam executadas repetidamente até que a seja maior ou igual a b. Em geral, a instrução while funciona assim:
	
	A linguagem C também oferece uma estrutura do-while:
do
{
	printf("%d\n", a);
	a = a + 1;
}
	while (a < b);
	O loop for na linguagem C é apenas um atalho para expressar uma instrução while. Por exemplo, suponha que você tenha o seguinte código em C:
x=1;
while (x<10)
{
	blá blá blá
	x++; /* x++ é o mesmo que dizer x=x+1 */
}
	Você pode converter isso em um loop for da seguinte forma:
for(x=1; x<10; x++)
{
	blá blá blá
}
	Observe que o loop while contém uma etapa de inicialização (x=1), uma etapa de teste (x<10) e uma de incremento (x++). O loop for permite colocar as três partes em uma única linha, mas você pode colocar qualquer coisa nelas. Por exemplo, suponha que você tenha o seguinte loop:
a=1;
b=6;
while (a < b)
{
	a++;
	printf("%d\n",a);
}
	Você também pode colocá-lo para indicação:
for (a=1,b=6; a < b; a++,printf("%dn",a));
	É um pouco confuso, mas é possível. O operador vírgula permite separar diversas instruções diferentes nas seções de inicialização e incremento do loop for (porém não na seção de teste). Muitos programadores de linguagem C gostam de concentrar muitas informações em uma única linha de código. Outros acham que isto torna o código mais difícil de entender, e portanto desmembram essas instruções.
	= versus == em expressões booleanas
O sinal == é um problema na linguagem C pois frequentemente você se esquece e digita apenas = em uma expressão booleana. Este é um erro comum de ocorrer, mas para o compilador há uma diferença significativa. A linguagem C aceitará = e == em uma expressão booleana, mas o comportamento do programa mudará consideravelmente quando usamos um ou outro.
As expressões booleanas em C avaliam os inteiros e os inteiros podem ser usados dentro de expressões booleanas. O valor inteiro 0 em C é Falso, enquanto qualquer outro valor inteiro é Verdadeiro. É código seguinte é permitido em C:
#include <stdio.h>
int main()
{
 int a;
 printf("Digite um número:");
 scanf("%d", &a);
 if (a)
 {
 printf("O valor é verdadeiro\n");
 }
 return 0;
}
Se a for qualquer número diferente de 0, a instrução printf é executada.
Em C, uma instrução como if (a=b) significa: “Atribuir b para a, e então testar a para seu valor Booleano". Assim, se a retornar o valor 0, a instrução if é Falsa. Caso contrário, é Verdadeira. O valor de a muda durante o processo. Este não é o comportamento desejado se você pretendeu digitar == (embora esta característica seja útil quando usada corretamente), assim, tenha cuidado com o uso de = e ==.
	10 Looping: um exemplo real
	Suponhamos que você queira criar um programa que imprima uma tabela de conversão Fahrenheit para Celsius. Isso pode ser facilmente obtido com um loop for ou loop while:
#include <stdio.h>
int main()
{
	int a;
	a = 0;
	while (a <= 100)
	{
	printf("%4d graus F = %4d graus C\n",
	a, (a - 32) * 5 / 9);
	a = a + 10;
	}
	return 0;
}
	Se executar este programa, ele produzirá uma tabela de valores iniciando em 0 graus F e terminando em 100 graus F. O resultado será este:
0 graus F = -17 graus C
10 graus F = -12 graus C
20 graus F = -6 graus C
30 graus F = -1 graus C
40 graus F = 4 graus C
50 graus F = 10 graus C
60 graus F = 15 graus C
70 graus F = 21 graus C
80 graus F = 26 graus C
90 graus F = 32 graus C
100 graus F = 37 graus C
	Os valores da tabela estão em incrementos de 10 graus. Observe como é fácil alterar os valores iniciais, finais ou de incremento da tabela que o programa produz.
	Para valores mais precisos, você pode usar valores de ponto flutuante:
#include <stdio.h>
int main()
{ 
 	float a;
	a = 0;
	while (a <= 100)
	{
	printf("%6.2f graus F = %6.2f graus C\n",
	a, (a - 32.0) * 5.0 / 9.0);
	a = a + 10;
	}
	return 0;
}
	Você pode ver que a declaração de a foi alterada para flutuante, e o símbolo %f substitui o símbolo %d na instrução printf. Além disso, o símbolo %f possui alguma formatação: o valor será impresso com 6 dígitos inteiros e 2 decimais.
	Agora vamos supor que queiramos modificar o programa para que a temperatura 98.6 seja inserida na tabela na posição adequada. Isto é, queremos que a tabela aumente a cada 10 graus e que inclua uma linha extra para 98.6 graus F, que é a temperatura corpórea normal do ser humano. O programa seguinte atende essa finalidade:
#include <stdio.h>
int main()
{
	float a;
	a = 0;
	while (a <= 100)
	{
 	 if (a > 98.6)
	{
	printf("%6.2f graus F = %6.2f graus C\n",
	98.6, (98.6 - 32.0) * 5.0 / 9.0);
	}
	printf("%6.2f graus F = %6.2f graus C\n",
	a, (a - 32.0) * 5.0 / 9.0);
	a = a + 10;
	}
	return 0;
 }
	Este programa funciona se o valor final for 100, mas se você alterar o valor final para 200, verá que o programa tem um bug. Ele imprime a linha de 98.6° várias vezes. Este problema pode ser corrigido de várias formas. Eis uma:
#include <stdio.h>
int main()
{
	float a, b;
	a = 0;
	b = -1;
	while (a <= 100)
	{
	if ((a > 98.6) && (b < 98.6))
	{
	printf("%6.2f graus F = %6.2f graus C\n",
 	98.6, (98.6 - 32.0) * 5.0 / 9.0);
	}
	printf("%6.2f graus F = %6.2f graus C\n",
 	a, (a - 32.0) * 5.0 / 9.0);
 	b = a;
 	a = a + 10;
	}
 	return 0;
}
	Tente isto
Tente alterar o programa conversor Fahrenheit-Celsius de modo que ele utilize scanf para aceitar o valor inicial, final e de incremento daquele usuário;
Adicione uma linha de cabeçalho àtabela que é gerada;
Tente encontrar uma solução diferente para o bug corrigido pelo exemplo anterior;
Crie uma tabela que converta libras em quilogramas ou milhas em quilômetros.
	Erros a serem evitados na linguagem C
Colocar = quando se deseja == em uma instrução if ou while;
Esquecer de aumentar o contador dentro do loop while. Isso causa um loop infinito (o loop nunca acaba).
Acidentalmente colocar um ; no final de um loop for ou instrução if, pois isto anula a instrução. Por exemplo: 
for (x=1; x<10; x++);
 printf("%d\n",x);
imprime apenas um valor, pois o ponto-e-vírgula após a instrução for atua como uma linha para a execução do loop for.
	11 Matrizes
	Nesta seção, criaremos um pequeno programa em C que gera 10 números aleatórios e os ordena. Para tal, utilizaremos uma nova disposição de variável denominada matriz.
	Uma matriz permite declarar e trabalhar com uma coleção de valores de mesmo tipo. Por exemplo, você pode querer criar uma coleção de 5 inteiros. Uma forma para fazer isso seria declarar 5 inteiros diretamente:
int a, b, c, d, e;
	Isso está certo, mas e se você precisasse de milhares de números inteiros? Uma forma mais fácil é declarar uma matriz de 5 inteiros.
int a[5];
	Os cinco inteiros individuais dentro desta matriz são acessados por um índice. Todas as matrizes iniciam em zero e vão até n-1 no C. Assim, int a[5]; contém 5 elementos. Por exemplo:
int a[5];
a[0] = 12;
a[1] = 9;
a[2] = 14;
a[3] = 5;
a[4] = 1;
	Uma das vantagens sobre a indexação de matriz é que você pode usar um loop para manipular o índice. Por exemplo, o código a seguir inicializa todos os valores na matriz em 0:
int a[5];
int i;
for (i=0; i<5; i++)
	a[i] = 0;
	O código seguinte inicializa seqüencialmente os valores na matriz e então os imprime:
#include <stdio.h>
int main()
{
	int a[5];
	int i;
	for (i=0; i<5; i++)
	a[i] = i;
	for (i=0; i<5; i++)
	printf("a[%d] = %dn", i, a[i]);
}
	As matrizes são usadas a toda hora em C. Para entender seu uso, inicie um editor e digite o seguinte código:
#include <stdio.h>
#define MAX 10
int a[MAX];
int rand_seed=10;
/* from K&R - retorna um número aleatório entre 0 e 32767.*/
int rand()
{
	int main()
	{
	int i,t,x,y;
	/* preenche a matriz */
	for (i=0; i < MAX; i++)
	{
	a[i]=rand();
	printf("%dn",a[i]);
	}
	/* mais coisas aparecerão aqui em breve */
	return 0;
	}
}
	Este código contém vários conceitos novos. A linha #define declara uma constante denominada MAX e a define em 10. Os nomes de constantes em geral são escritos em letras maiúsculas para destacá-los no código. A linha int a[MAX]; mostra como declarar uma matriz de inteiros em C. Observe que por causa da posição da declaração da matriz, ela é global ao programa.
	A linha int rand_seed=10 também declara uma variável global, desta vez denominada rand_seed, que é inicializada em 10 sempre que o programa inicia. Este valor é o inicial para o código de números aleatórios que segue. Em um gerador de números aleatórios reais, o seed deve inicializar como um valor aleatório, como a hora do sistema. Aqui, a função rand produzirá os mesmos valores sempre que executar o programa.
	A linha int rand() é uma instrução de função. A função rand não aceita parâmetros e retorna um resultado inteiro: aprenderemos mais sobre as funções em breve. As quatro linhas que seguem implementam a função rand. Por hora, nós as ignoraremos.
	A função principal é normal. Quatro inteiros locais são declarados e a matriz é preenchida com 10 valores aleatórios usando um loop for. Observe que a matriz a contém 10 inteiros individuais. Você aponta para um inteiro específico na matriz usando colchetes. Assim a[0] refere-se ao primeiro inteiro na matriz, a[1] refere-se ao segundo, e assim por diante. A linha que começa com /* e termina com */ é denominada de comentário. O compilador ignora completamente a linha de comentário. Você pode colocar notas para si próprio ou outros programadores nos comentários.
	Agora adicione o seguinte código no lugar do comentário mais coisas...:
/* ordenação por bolha da matriz */
for (x=0; x < MAX-1; x++)
	for (y=0; y < MAX-x-1; y++)
	if (a[y] > a[y+1])
	{
	t=a[y];
	a[y]=a[y+1];
	a[y+1]=t;
	}
/* imprime matriz classificada */
printf("--------------------n");
for (i=0; i < MAX; i++)
printf("%dn",a[i]);
	Esta codificação classifica os valores aleatórios e os imprime ordenadamente. Sempre que o executar, você obterá os mesmos valores. Para alterar os valores classificados, altere o valor de rand_seed sempre que executar o programa.
	O único modo fácil para realmente entender o que o código está fazendo é executá-lo “à mão”. Isto é, assuma que MAX é 4 para facilitar, pegue uma folha de papel e finja que é o computador. Desenhe a matriz no papel e coloque 4 valores aleatórios e não-classificados na matriz. Execute cada linha da seção de classificação do código e desenhe exatamente o que acontece. Você verá que, sempre que submetidos ao loop interno, os valores maiores na matriz são empurrados para baixo e os valores menores vão para o topo da matriz.
	Tente isto
No primeiro trecho do código, tente alterar o loop for que preenche a matriz para uma única linha de código. Certifique-se de que o resultado seja igual ao do código original;
Pegue o código de ordenação por bolha e coloque-o em sua própria função. O cabeçalho de função será void bubble_sort(). Depois transfira as variáveis utilizadas pela ordenação por bolha para a função e torne-as locais. Por ser uma matriz local, você não precisa passar parâmetros. 
Inicialize a semente do número aleatório para diferentes valores.
	Erros que devem ser evitados na linguagem C
A linguagem C não tem nenhuma verificação de dimensão, portanto, se você indexar além do fim da matriz, ele não o informará a respeito. Ele provavelmente travará ou apresentará dados incorretos;
A chamada de função deve incluir () mesmo se nenhum parâmetro for informado. Por exemplo, C aceitará x=rand; mas a chamada não funcionará. O endereço de memória da função rand será colocado em x. Você deve dizer x=rand();.
	12 Mais sobre matrizes
	Tipos de variáveis
	Há 3 tipos padrão de variáveis em linguagem C:
inteiro: int;
ponto flutuante: float;
caractere: char.
	Um int é um valor inteiro de 4 bytes. Um float é um valor de ponto flutuante de 4 bytes. Um char é um caractere único de 1 byte (como “a” ou “3”). Uma string de caracteres é declarada como uma matriz de caracteres.
	Há vários tipos derivados:
duplo (valor de ponto flutuante de 8 bytes);
curto (inteiro de 2 bytes);
curto sem sinal ou int sem sinal (números inteiros positivos, sem bit de sinal).
	Operadores e precedência de operadores
	Os operadores em C são semelhantes aos operadores na maioria das linguagens:
+: adição;
-: subtração;
/: divisão;
*: multiplicação;
%: mod.
	O operador / realiza a divisão de inteiros se ambos os operandos forem números inteiros; caso contrário, realiza a divisão por ponto flutuante. Por exemplo:
void main()
{
	float a;
	a=10/3;
	printf("%f\n",a);
}
	Este código imprime um valor de ponto flutuante desde que a seja declarado como tipo float, mas a será 3.0 porque o código executou uma divisão de inteiros.
	A precedência de operador em C também é similar para a maioria das linguagens. A divisão e multiplicação ocorrem primeiro, depois a adição e a subtração. O resultado do cálculo 5+3*4 é 17, e não 32. Em C, o operador * tem precedência sobre o +. Você pode usar parênteses para alterar a ordem de precedência normal: (5+3)*4 é 32. O 5+3 é executado primeiro porque está entre parênteses. Abordaremos a parte da precedência mais tarde, já que ela se torna um pouco complicada em C quando os ponteiros são introduzidos.
	Conversão de tipo
	A linguagem C permite executar conversões de tipo na sua execução. Você utiliza este recurso com freqüência ao usar ponteiros. A conversão de tipo também ocorre durante a operação de atribuição para determinados tipos. Por exemplo, no código acima, o valor inteiro foi automaticamente convertido para um flutuante.
	Você faz a conversãode tipo em C colocando o nome de tipo entre parênteses e colocando-o na frente do valor que deseja alterar. Assim, no código acima, ao substituir a linha a=10/3; por a=(float)10/3; produz 3.33333 como resultado, pois 10 é convertido em um valor de ponto flutuante antes da divisão.
	Typedef
	Você declara tipos nomeados e definidos pelo usuário em C com a instrução typedef. O exemplo a seguir mostra um tipo que aparece freqüentemente no código C:
#define TRUE 1
#define FALSE 0
typedef int boolean;
void main()
{
	boolean b;
	b=FALSE;
	blá blá blá
}
	Este código permite declarar tipos booleanos em programas C.
	Se você não gosta da palavra “float” para números reais, você pode dizer:
typedef float real;
e mais tarde dizer:
real r1,r2,r3;
	Você pode colocar declarações typedef em qualquer lugar em um programa C contanto que venham antes de sua primeira utilização na codificação.
	Estruturas
	Estruturas em C permitem agrupar variáveis em um pacote. Eis um exemplo:
struct rec
{
	int a,b,c;
	float d,e,f;
};
struct rec r;
	Como demonstrado, sempre que desejar declarar estrutura do tipo rec, você precisa dizer struct rec. Esta linha é muito fácil de esquecer, e o compilador gera muitos erros caso você omita o struct. Você pode compactar o código desse modo:
struct rec
{
	int a,b,c;
	float d,e,f;
} r;
onde a declaração de tipo para rec e a variável r são declaradas na mesma instrução. Ou você pode criar uma instrução typedef para o nome de estrutura. Por exemplo, se você não gosta de dizer struct rec r sempre que deseja declarar um registro, pode dizer:
typedef struct rec rec_type;
e então declarar os registros de tipo rec_type dizendo:
rec_type r;
	Você acessa os campos da estrutura usando um ponto, por exemplo, r.a=5;.
	Matrizes
	Você declara matrizes ao inserir um tamanho de matriz após a instrução normal, como abaixo:
int a[10]; /* matriz de inteiros */
char s[100]; /* matriz de caracteres (uma string em C) */
float f[20]; /* matriz de reais */
struct rec r[50]; /* matriz de registros */
	Incrementação
Caminho Longo 	 Caminho Curto
i=i+1; i++;
i=i-1; i--;
i=i+3; i += 3;
i=i*j; i *= j;
	Tente isto
Tente diferentes trechos da codificação para investigar a conversão de tipo e precedência. Tente int, char, float e assim por diante;
Crie uma matriz de registros e digite um código para classificar a matriz em um campo de número inteiro.
	Erros que devem ser evitados na linguagem C
Como descrito acima, o uso do operador / com 2 inteiros quase sempre produzirá um resultado inesperado, portanto pense bem ao utilizá-lo.
	13 Funções
	A maioria das linguagens permite criar funções de algum tipo. Funções permitem dividir um longo programa em seções nomeadas, de forma que as seções possam ser reutilizadas ao longo do programa. As funções aceitam parâmetros e retornam um resultado. Funções de C podem aceitar um número ilimitado de parâmetros. Em geral, a linguagem C não se preocupa em qual ordem você coloca suas funções no programa, contanto que o nome da função seja conhecido pelo compilador antes de ser invocado.
	Já falamos um pouco sobre funções. A função rand previamente descrita é bastante simples. Ela não aceita parâmetros e retorna um resultado inteiro:
int rand()
/* de K&R - produz um número aleatório entre 0 e 32767.*/
{
	rand_seed = rand_seed * 1103515245 +12345;
	return (unsigned int)(rand_seed / 65536) % 32768;
}
	A linha int rand() declara a função rand para o resto do programa e especifica que aquele rand não aceitará nenhum parâmetro e retornará um resultado inteiro. Esta função não tem nenhuma variável local, mas se elas fossem necessárias, iriam logo abaixo da abertura {. A linguagem C permite declarar variáveis após qualquer {: elas existem até o programa atingir o } correspondente e então desaparecem. Desta forma, as variáveis locais de uma função desaparecem assim que o } correspondente é atingido na função. Enquanto existirem, as variáveis locais residem na pilha do sistema. Observe que não há nenhum ; depois de () na primeira linha. Caso tenha colocado um, acidentalmente, você receberá uma enorme cascata de mensagens de erro do compilador, que não farão sentido algum. Observe também que, mesmo sem parâmetros, você precisa usar o (). Eles indicam ao compilador que você está declarando uma função em vez de simplesmente declarar um int.
	A instrução return é importante para qualquer função que retorna um resultado. Ela especifica o valor que a função retornará e a encerra imediatamente. Isto significa que você pode colocar diversas instruções de retorno na função para proporcionar vários pontos de saída. Se você não colocar uma instrução de retorno em uma função, a função retorna quando atinge } e retorna um valor aleatório (muitos compiladores o advertirão se você não retornar um valor específico). Em C, uma função pode retornar valores de qualquer tipo: int, float, char, struct, etc.
	Há vários modos corretos para executar a função rand. Por exemplo: x=rand();. A variável x recebe o valor retornado por rand nesta instrução. Observe que você deve usar () na chamada da função, mesmo que nenhum parâmetro seja passado. Caso contrário, x recebe o endereço de memória da função rand, que geralmente não é desejável.
	Você também pode invocar rand desta forma:
if (rand() > 100)
	Ou deste modo:
rand();
	No último caso, a função é chamada, mas o valor retornado por rand é descartado. Talvez você nunca faça isso com rand, mas muitas funções retornam algum tipo de código de erro por meio da função, e se você não está muito preocupado com o código de erro (por exemplo, por saber que um erro é impossível), você poderá descartá-lo.
	Funções podem usar um retorno tipo void caso se deseje que não se retorne nada. Por exemplo:
void print_header()
{
	printf("Programa Número 1n");
	printf("Programa Número 1n");
	printf("Versão 1.0, lançada em 26/12/91\n");
}
	Esta função não retorna valor algum. Você pode invocá-la com a seguinte instrução:
print_header();
	Você deve incluir () na chamada. Se não o fizer, a função não é invocada, embora possa ser compilada corretamente em outros sistemas.
	As funções em C podem aceitar qualquer tipo de parâmetro. Por exemplo:
int fact(int i)
{
	int j,k;
	j=1;
	for (k=2; k<=i; k++)
	j=j*k;
	return j;
}
retorna o fatorial de i, que é passado como um parâmetro inteiro. Separe vários parâmetros com vírgulas:
int add(int i, int j)
{
	return i+j;
}
	A linguagem C evoluiu ao longo dos anos. Às vezes, você verá funções como add escritas do “modo antigo”, como mostrado abaixo:
int add(i,j)
	int i;
	int j;
{
	return i+j;
}
	É importante saber ler o código escrito no estilo antigo. Não há nenhuma diferença na forma em que o código é executado, apenas a notação é diferente. Você deve usar o “novo estilo” (conhecido como ANSI C) com o tipo declarado, como parte da lista de parâmetros, a menos que tenha conhecimento prévio de que o código será enviado a alguém com um compilador em “estilo antigo” (sem suporte a ANSI).
	14 Funções: protótipos de função
	É considerada boa prática utilizar protótipos de função para todas as funções em seu programa. Um protótipo declara o nome de função, seus parâmetros e seu tipo de retorno para o resto do programa antes da declaração real da função. Para entender a utilidade dos protótipos, digite o seguinte código e execute-o:
#include <stdio.h>
void main()
{
	printf("%d\n",add(3));
}
int add(int i, int j)
{
	return i+j;
}
	Este código compila em diversos compiladores sem emitir um aviso, apesar de add esperar dois parâmetros e receber apenas um. Ele funciona porque muitos compiladores C não verificam se o parâmetro corresponde ao tipo ou à quantidade. Você pode perder horas na depuração de um código no qual você está declarando parâmetros a mais ou a menos por engano. O código anterior compila corretamente, mas produz a resposta errada.
	Para resolver este problema, a linguagem C permite colocar protótipos de função no início (na verdade, em qualquer lugar) de umprograma. Se fizer isso, a linguagem C verifica tipos e quantidades de todas as listas de parâmetros. Tente compilar o seguinte:
#include <stdio.h>
int add (int,int); /* protótipo de função para add */
void main()
{
	printf("%d\n",add(3));
}
int add(int i, int j)
{
	return i+j;
}
	O protótipo faz com que o compilador sinalize um erro na instrução printf.
	Coloque um protótipo para cada função no início de seu programa. Os propótipos podem economizar bastante tempo de depuração e também resolver o problema que ocorre ao compilar com funções que são utilizadas antes de serem declaradas. Por exemplo, o seguinte código não compilará:
#include <stdio.h>
void main()
{
	printf("%d\n",add(3));
}
float add(int i, int j)
{
	return i+j;
}
	Você pode perguntar: “Por que ele compilará quando add retorna um int mas não quando retorna um float?” Porque os compiladores em C mais antigos padronizaram um valor de retorno para int. O uso de um protótipo resolverá este problema. Os “compiladores antigos” (sem suporte a ANSI) permitem protótipos, porém a lista de parâmetros do protótipo deve estar vazia. Os compiladores antigos não fazem a verificação de erros em listas de parâmetros.
	Tente isto
Retorne ao exemplo de classificação bubble sort anteriormente apresentado e crie uma função;
Retorne aos programas anteriores e crie uma função para obter a entrada de dado do usuário, em vez de obter a entrada de dado da função principal.
	15 Bibliotecas
	Bibliotecas são muito importantes na linguagem C, pois a linguagem suporta apenas os recursos mais básicos de que necessita. A linguagem C não contém sequer funções de I/O para ler a partir do teclado e digitar na tela. Qualquer coisa que vá além da linguagem básica deve ser escrita por um programador. Geralmente, os trechos de código resultantes são colocados em bibliotecas para torná-los facilmente reutilizáveis. Vimos a biblioteca padrão de I/O padrão ou stdio: as bibliotecas padrão existem para I/O padrão, funções matemáticas, manipulação da string de caracteres, manipulação de tempo e assim por diante. Você pode utilizar as bibliotecas em seus próprios programas para dividi-los em módulos. Isso os torna fáceis de entender, testar e depurar, como também possibilita a reutilização do código por outros programas que você criar.
	Você pode criar suas próprias bibliotecas facilmente. Como exemplo, pegaremos um código do artigo anterior desta série e criaremos uma biblioteca a partir de duas de suas funções. Eis o código com o qual iniciaremos:
#include <stdio.h>
#define MAX 10
int a[MAX];
int rand_seed=10;
int rand()
/* de K&R - produz um número aleatório entre 0 e 32767.*/
{
	rand_seed = rand_seed * 1103515245 +12345;
	return (unsigned int)(rand_seed / 65536) % 32768;
}
void main()
{
int i,t,x,y;
/* preenche a matriz*/
	for (i=0; i < MAX; i++)
	{
	a[i]=rand();
	printf("%d\n",a[i]);
	}
	/* ordenação por bolha da matriz */
	for (x=0; x < MAX-1; x++)
	for (y=0; y < MAX-x-1; y++)
	if (a[y] > a[y+1])
	{
	t=a[y];
	a[y]=a[y+1];
	a[y+1]=t;
	}
	/* imprime matriz classificada */
	printf("--------------------n");
	for (i=0; i < MAX; i++)
	printf("%d\n",a[i]);
}
	Este código preenche uma matriz com números aleatórios, ordena-os em bubble sort e depois os exibe na lista ordenada.
	Pegue o código bubble sort e use o que aprendeu no artigo anterior para criar uma função a partir dele. Visto que a matriz a e a constante MAX são globalmente conhecidas, a função que você cria não precisa de parâmetros, tampouco apresentar um resultado. Porém, você deve usar variáveis locais para x, y e t.
	Uma vez testada a função para verificar se ela está funcionado, passe o número de elementos como um parâmetro em vez de utilizar MAX:
#include <stdio.h>
#define MAX 10
int a[MAX];
int rand_seed=10;
/* de K&R - retorna um número aleatório entre 0 e 32767.*/
int rand()
{
	rand_seed = rand_seed * 1103515245 +12345;
	return (unsigned int)(rand_seed / 65536) % 32768;
}
void bubble_sort(int m)
{
	int x,y,t;
	for (x=0; x < m-1; x++)
	for (y=0; y < m-x-1; y++)
	if (a[y] > a[y+1])
	{
	t=a[y];
	a[y]=a[y+1];
	a[y+1]=t;
	}
}
void main()
}
	int i,t,x,y;
	/* preenche a matriz */
	for (i=0; i < MAX; i++)
	{	
	a[i]=rand();
	printf("%d\n",a[i]);
	}
	bubble_sort(MAX);
	/* imprime matriz classificada */
	printf("--------------------n");
	for (i=0; i < MAX; i++)
	printf("%d\n",a[i]);
}
	Você também pode generalizar ainda mais a função bubble_sort passando a como um parâmetro:
bubble_sort(int m, int a[])
	Esta linha diz: “Aceitar a matriz do inteiro a de qualquer tamanho como parâmetro”. Nada precisa ser alterado no corpo da função bubble_sort. Para chamar bubble_sort, altere a chamada para:
bubble_sort(MAX, a);
	Observe que &a não foi usado na chamada de função, embora a classificação vá mudar a. O motivo para tal ficará mais evidente depois que você entender os ponteiros.
	16 Criando uma biblioteca
	Uma vez que as funções rand e bubble_sort nos programas anteriores são úteis, você provavelmente vai querer reutilizá-las em outros programas que criar. Você pode colocá-las em uma biblioteca de utilitários para facilitar sua reutilização.
	Toda biblioteca possui duas partes: um arquivo de cabeçalho e o arquivo de código. O arquivo de cabeçalho, em geral indicado por um sufixo .h, contém informações sobre a biblioteca que os programas que o utilizam precisam saber. Em geral, o arquivo de cabeçalho contém constantes e tipos, junto com protótipos de funções disponíveis na biblioteca. Digite o seguinte arquivo de cabeçalho e salve-o com o nome util.h.
/* util.h */
extern int rand();
extern void bubble_sort(int, int []);
	Estas duas linhas são protótipos de função. A palavra “extern” em C representa funções que serão posteriormente vinculadas. Se estiver usando um compilador antigo, remova os parâmetros da lista de parâmetros do bubble_sort.
	Digite o seguinte código em um arquivo denominado util.c.
/* util.c */
#include "util.h"
int rand_seed=10;
/* de K&R - produz um número aleatório entre 0 e 32767.*/
int rand()
{
	rand_seed = rand_seed * 1103515245 +12345;
	return (unsigned int)(rand_seed / 65536) % 32768;
}
	void bubble_sort(int m,int a[])
{
	int x,y,t;
	for (x=0; x < m-1; x++)
	for (y=0; y > m-x-1; y++)
	if (a[y] < a[y+1])
	{
	t=a[y];
	a[y]=a[y+1];
	a[y]=a[y+1];
	}
}
	Este código inclui a biblioteca de utilitários. O benefício principal em utilizar uma biblioteca é que a codificação no programa principal fica muito menor.
	Compilando e executando com uma biblioteca
	Para compilar a biblioteca, digite o seguinte na linha de comando (assumindo que você está usando UNIX) (substitua gcc por cc, se seu sistema usa cc):
gcc -c -g util.c
	O -c faz com que o compilador produza um arquivo de objeto para a biblioteca. O arquivo objeto contém o código de máquina da biblioteca. Ele não pode ser executado até ser vinculado a um arquivo de programa que contenha a função principal. O código de máquina reside em um arquivo separado chamado util.o.
	Para compilar o programa principal, digite o seguinte:
gcc -c -g main.c
	Esta linha cria um arquivo denominado main.o que contém o código de máquina do programa principal. Para criar o executável final que contém o código de máquina de todo o programa, vincule os dois arquivos objetos digitando o seguinte:
gcc -o main main.o util.o
	Isso vincula main.o e util.o para formar um executável denominado main. Para executá-lo, digite main.
	Makefiles facilitam o trabalho com as bibliotecas. Você descobrirá mais sobre os makefiles na próxima página.
	17 Makefiles
	Pode ser inconveniente ter que digitar todas as linhas do gcc novamente, especialmente se você estiver realizando inúmeras alterações no código e possui várias bibliotecas. O utilitário make resolve este problema. Você pode usar o seguinte makefile para substituir a seqüência de compilação anterior:
main: main.o util.o
	gcc -o main main.o util.o
main.o: main.c util.h
	gcc -c -g main.c
util.o: util.c util.h
	gcc -c -g util.c
	Digite isto emum arquivo chamado makefile e digite make para criar o executável. Observe que você deve preceder todas as linhas gcc com um espaço de parágrafo (8 espaços não bastarão, é necessário uma tabulação; as demais linhas devem estar alinhadas à esquerda).
	Este makefile contém dois tipos de linhas. As linhas que aparecem alinhadas à esquerda são linhas de dependência. As linhas precedidas por uma tabulação são linhas executáveis, que podem conter qualquer comando UNIX válido. Uma linha de dependência indica que um arquivo é dependente de outro conjunto de arquivos. Por exemplo, main.o: main.c util.h diz que o arquivo main.o depende dos arquivos main.c e util.h. Se qualquer um destes dois arquivos for alterado, as linhas executáveis seguintes devem ser executada(s) para recriar main.o.
	Observe que o executável final produzido pelo makefile inteiro é main, na linha 1 no makefile. O resultado final do makefile deve sempre ir na linha 1, onde este makefile diz que o arquivo main depende de main.o e util.o. Em caso de alterações, execute a linha gcc -o main main.o util.o para recriar main.
	É possível colocar múltiplas linhas para serem executadas abaixo da linha de dependência (todas devem começar com uma tabulação). Um programa grande pode ter várias bibliotecas e um programa principal. O makefile recompila automaticamente tudo o que precisa ser recompilado por conta de uma alteração.
	Se não estiver trabalhando em uma máquina UNIX, seu compilador provavelmente tem a funcionalidade equivalente à dos makefiles. Leia a documentação de seu compilador para aprender como utilizá-lo.
	Agora você entende por que se tem incluído stdio.h nos programas anteriores. Ele é simplesmente uma biblioteca padrão que alguém criou há muito tempo e disponibilizou a outros programadores para facilitar suas vidas.
	18 Arquivos de texto
	Arquivos de texto em C são diretos e fáceis de entender. Todas as funções e tipos de arquivo de texto em C vêm da biblioteca stdio.
	Quando você precisa de I/O de texto em um programa em C e precisa apenas de uma fonte para informação de entrada e uma fonte para informação de saída, você pode usar o stdin (entrada padrão/teclado) e stdout (saída padrão/monitor). Você pode usar o redirecionamento de entrada e saída na linha de comando para mover diferentes fluxos de informações pelo programa. Há 6 comandos diferentes de I/O em <stdio.h> que você pode usar com stdin e stdout:
Printf → imprime a saída formatada para stdout;
Scanf → lê a entrada formatada do stdin;
Puts → imprime uma string de caracteres para stdout;
Gets → lê uma seqüência de caracteres do stdin;
Putc → imprime um caractere para stdout;
gets, getchar → lê um caractere do stdin.
	A vantagem do stdin e stdout é que eles são fáceis de usar. Da mesma forma, a capacidade para redirecionar a I/O é muito poderosa. Por exemplo, talvez você queira criar um programa que leia de stdin e conta o número de caracteres:
#include <stdio.h>
#include <string.h>
void main()
{
	char s[1000];
	int count=0;
	while (gets(s))
	count += strlen(s);
	printf("%d\n",count);
}
	Digite este código e execute-o. Ele aguardará pela entrada de stdin, portanto digite algumas linhas. Quando terminar, pressione CTRL-D para indicar o final do arquivo (eof, de “end-of-file”). A função gets lê uma linha até detectar o eof, depois retorna um 0, encerrando o loop while. Ao pressionar CTRL-D, você vê uma contagem do número de caracteres em stdout (a tela). Use man gets ou a documentação de seu compilador para saber mais sobre a função gets.
	Agora, suponha que você queira contar os caracteres em um arquivo. Se o programa for compilado em um executável nomeado xxx, você pode digitar o seguinte:
xxx < nome do arquivo
	Em vez de aceitar a entrada do teclado, será usado o conteúdo do arquivo denominado filename. Você pode obter o mesmo resultado usando o caractere barra vertical:
cat < filename | xxx
	Você também pode redirecionar o resultado para um arquivo:
xxx < filename > out
	Este comando coloca a contagem de caracteres produzida pelo programa em um arquivo de texto denominado out.
	Às vezes, você precisa usar um arquivo de texto diretamente. Por exemplo, você pode precisar abrir um arquivo específico e ler ou escrever nele. Talvez você queira gerenciar vários fluxos de entrada ou saída, ou criar um programa como um editor de textos que possa salvar e recuperar arquivos de dados ou configurações no comando. Nesse caso, use as funções de arquivo de texto em stdio:
fopen → abre um arquivo de texto;
fclose → fecha um arquivo de texto;
feof → detecta o marcador de final de arquivo em um arquivo;
fprintf → imprime a saída formatada em um arquivo;
fscanf → lê a entrada formatada de um arquivo;
fputs → imprime uma string de caracteres para um arquivo;
fgets → lê uma string de caracteres de um arquivo;
fputc → imprime um caractere para um arquivo;
fgetc → lê um caractere de um arquivo.
	19 Arquivos de texto: abrindo
	Use fopen para abrir um arquivo. Ele abre um arquivo para um modo especificado (os três mais comuns são r, w e a, para leitura, gravação e anexação). Ele então retorna um ponteiro de arquivo que você usa para acessar o arquivo. Por exemplo, suponha que você queira abrir um arquivo e escrever nele os números 1 a 10. Você pode usar a seguinte codificação:
#include <stdio.h>
#define MAX 10
int main()
{
	FILE *f;
	int x;
	f=fopen("out","w";);
	if (!f)
	return 1;
	for(x=1; x<=MAX; x++)
	fprintf(f,"%d\n",x);
	fclose(f);
	return 0;
}
	A instrução fopen abre um arquivo denominado out com o modo w. Este é um modo de escrita destrutivo, o que significa que se out não existir ele será criado, porém se ele já existir, será destruído e um novo arquivo será criado em seu lugar. O comando fopen retorna um ponteiro para o arquivo, que é armazenado na variável f. Esta variável é usada para referência ao arquivo. Se o arquivo não pode ser aberto por algum motivo, f irá conter NULL.
	Valores de retorno da função principal
Este programa é o primeiro programa desta série que retorna um valor de erro do programa principal. Se o comando fopen falhar, f contém um valor NULL (zero). Vamos testar este erro com a instrução if. A instrução if verifica o valor de Verdadeiro/Falso da variável f. Lembre-se de que em C, 0 é Falso e qualquer outro valor é verdadeiro. Se houvesse um erro ao abrir o arquivo, f conteria zero, que é Falso. O ! é o operador NOT. Ele inverte um valor booleano. Assim, a instrução if poderia ter sido escrita desta forma:
 if (f == 0) 
As duas formas são equivalentes. Porém, if (!f) é mais comum.
Se houver um erro de arquivo, retornamos um 1 da função principal. Em UNIX, você pode testar este valor na linha de comando. Veja a documentação de shell para mais detalhes.
	A instrução fprintf deve parecer bastante familiar: ela é igual a printf, mas usa o ponteiro de arquivo como seu primeiro parâmetro. A instrução fclose fecha o arquivo quando você termina.
	20 Arquivos de texto: lendo
	Para ler um arquivo, abra-o com o modo r. Em geral, não é uma boa idéia usar fscanf para leitura: a menos que o arquivo esteja perfeitamente formatado, fscanf não o manipulará corretamente. Em vez disso, use fgets para ler cada linha e então analisar gramaticalmente as partes necessárias.
	O seguinte código demonstra o processo de leitura de um arquivo e o descarregamento de seu conteúdo na tela:
#include <stdio.h>
int main()
{
	FILE *f;
	char s[1000];
	f=fopen("infile","r");
	if (!f)
	return 1;
	while (fgets(s,1000,f)!=NULL)
	printf("%s",s);
	fclose(f);
	return 0;
}
	A instrução fgets retorna um valor NULL ao marcador de final de arquivo. Ele lê uma linha (até 1 mil caracteres, neste caso) e depois a imprime para stdout. Observe que a instrução printf não inclui n na string de formatação, pois fgets adiciona n ao final de cada linha que lê. Assim, você pode saber se uma linha não está completa no evento que excede o comprimento máximo da linha especificado no segundo parâmetro para fgets.
	Erros que devem ser evitados na linguagem C
Não digite acidentalmente close emvez de fclose. A função close existe, portanto o compilador a aceita. Ela até parecerá funcionar se o programa apenas abrir ou fechar alguns arquivos. Entretanto, se o programa abrir e fechar um arquivo em um loop, eventualmente ficará sem manipuladores de arquivos disponíveis e/ou espaço em memória e travará, pois close não está fechando os arquivos corretamente.
	21 Ponteiros
	Ponteiros são bastante usados em C. Assim, se deseja usar a linguagem C por completo, você precisa ter uma boa compreensão sobre ponteiros. Eles devem se tornar fáceis de usar para você. A meta desta e das várias próximas seções é ajudá-lo a construir um entendimento completo sobre os ponteiros e como a linguagem C os utiliza. Para a maioria das pessoas, isto demora um pouco, pois requer prática familiarizar-se com os ponteiros, mas depois de dominá-los, você se torna um programador completo em linguagem C.
	A linguagem C utiliza ponteiros de três modos diferentes:
a linguagem C usa ponteiros para criar estruturas dinâmicas de dados, que são estruturas de dados criadas a partir de blocos de memória localizados na pilha durante o tempo de execução;
a linguagem C usa ponteiros para manipular parâmetros de variáveis passados para as funções;
os ponteiros em C oferecem um modo alternativo para acessar informações armazenadas em matrizes. As técnicas de ponteiro são especialmente valiosas quando se trabalha com strings de caracteres. Há uma estreita relação entre matrizes e ponteiros em linguagem C.
	Em alguns casos, os programadores de C também usam ponteiros porque eles tornam o código um pouco mais eficiente. O que você descobrirá é que, depois de se sentir familiarizado com os ponteiros, irá a usá-los o tempo todo.
	Iniciaremos esta discussão com uma introdução básica sobre ponteiros e seus conceitos relacionados, e depois passaremos para as três técnicas descritas acima. Você provavelmente vai querer ler este artigo duas vezes. Ao lê-lo da primeira vez, você aprenderá os conceitos. A segunda leitura permitirá ligar os conceitos e criar um todo integrado em sua mente. Após ler o material pela segunda vez, ele fará muito mais sentido.
	22 Ponteiros: por quê?
	Imagine que você gostaria de criar um editor de texto: um programa que permite editar arquivos de texto ASCII normal, como o “vi”, do UNIX, ou o “Bloco de notas”, do Windows. Um editor de textos é uma coisa bastante comum para alguém criar, pois é provavelmente o segmento de software mais usado pelo programador. O editor de textos é a ligação íntima de um programador com o computador, pois é nele que o programador digita todas as suas idéias e as organiza. Obviamente, como qualquer coisa que você utilize com tanta freqüência e com a qual trabalhe constantemente, você também vai desejar que o editor de textos funcione perfeitamente. Assim, muitos programadores criam seus próprios editores e os personalizam para atender seus estilos e preferências de trabalho individuais.
	Então, em um certo dia, você se senta para começar a trabalhar em seu editor. Depois de pensar sobre as características que deseja, você começa a pensar sobre a “estrutura de dados” de seu editor. Quer dizer, começa a pensar sobre como armazenará o documento que está editando na memória, de forma que possa manipulá-lo em seu programa. O que você precisa é de um modo para armazenar as informações inseridas de forma que possam ser manipuladas rápida e facilmente. Você acredita que um modo de fazer isso é organizar os dados com base na linha de caracteres. Visto o que já foi discutido, a única coisa disponível aqui é a matriz. Você pensa: “Bem, uma linha típica tem 80 caracteres de comprimento e um arquivo típico não tem mais do que mil linhas”. Assim, você declara uma matriz bi-dimensional como esta:
char doc[1000][80];
	Esta instrução solicita uma matriz de mil linhas com 80 caracteres. Esta matriz tem um tamanho total de 80 mil caracteres.
	Enquanto pensa sobre o editor e sua estrutura de dados, você pode se dar conta de três coisas:
alguns documentos são listas longas. Cada linha é curta, mas há milhares de linhas;
alguns arquivos de texto com finalidade especial possuem linhas muito longas. Por exemplo, certo arquivo de dados poderia ter linhas contendo 542 caracteres, com cada caractere representando um par de aminoácidos do DNA;
na maioria dos editores modernos, você pode abrir múltiplos arquivos de uma só vez.
	Digamos que você determinou um máximo de 10 arquivos abertos por vez, um comprimento máximo de linha de 1 mil caracteres e um tamanho de arquivo máximo de 50 mil linhas. Sua declaração agora se parecerá com:
char doc[50000][1000][10];
	Não parece uma coisa absurda, até você pegar sua calculadora, multiplicar 50 mil por 1 mil e depois por 10 e constatar que a matriz irá conter 500 milhões de caracteres! Atualmente, a maioria dos computadores tem problemas com matrizes deste tamanho. Eles não têm a memória RAM, ou até mesmo o espaço de memória virtual para suportar uma matriz desse tamanho. Se os usuários tentassem executar três ou quatro cópias deste programa simultaneamente, mesmo num sistema multiusuário maior, isso poderia representar um esforço muito grande a suas instalações.
	Mesmo que o computador aceitasse uma solicitação para uma matriz tão grande, você veria que isto seria um desperdício extravagante de espaço. Parece estranho declarar uma matriz de 500 milhões de caracteres se, na maioria dos casos, você executará este editor para pesquisar arquivos de 100 linhas, que consomem no máximo 4 ou 5 mil bytes. O problema com uma matriz é o fato de que você precisa declará-la como tendo o tamanho máximo em cada dimensão, desde o começo. Os tamanhos máximos freqüentemente se multiplicam para formar números muito grandes. Também, se precisar editar um arquivo que ocasionalmente possua 2 mil carcacteres em uma linha, você terá problemas. Não há como prever e manipular o comprimento máximo de uma linha de um arquivo de texto, pois, tecnicamente, este número é infinito.
	Os ponteiros são projetados para resolver esse problema. Com eles, você pode criar estruturas dinâmicas de dados. Em vez de declarar o pior caso de consumo de memória com antecedência em uma matriz, você aloca memória da pilha enquanto o programa está sendo executado. Dessa forma, você pode usar a quantia exata de memória que o documento precisa, sem desperdício. Além disso, quando você fecha um documento, pode devolver a memória à pilha para que outros trechos do programa possam usá-la. Com os ponteiros, a memória pode ser reciclada enquanto o programa está sendo executado.
	A propósito, se você leu a discussão anterior e uma de suas grandes dúvidas continua sendo “o que é, de fato, um byte?”, então o artigo Como funcionam os bits e os bytes irá ajudá-lo a compreender esses conceitos e também coisas como “mega”, “giga” e “terá”. Dê uma olhada nele e depois volte aqui.
	23 Fundamentos sobre ponteiros
	Para compreender os ponteiros, convém compará-los às variáveis normais.
	Uma “variável normal” é um local na memória que pode conter um valor. Por exemplo, quando você declara uma variável i como um inteiro, 4 bytes de memória são separados para isso. Em seu programa, você se refere àquele local na memória pelo nome i. No nível da máquina, aquele local tem um endereço de memória. Os 4 bytes naquele endereço são conhecidos pelo programador como i, e os 4 bytes podem conter valores inteiros.
	Um ponteiro é diferente. Um ponteiro é uma variável que aponta para outra variável. Isto significa que um ponteiro mantém o endereço de memória de outra variável. Em outras palavras, o ponteiro não contém um valor no sentido tradicional, mas sim o endereço de outra variável. Um ponteiro “aponta para” esta outra variável mantendo uma cópia de seu endereço.
	Como um ponteiro contém um endereço, e não um valor, terá duas partes. O ponteiro contém um endereço e o endereço aponta para um valor. Há o ponteiro e o valor para o qual ele aponta. Este fato pode ser um tanto confuso, até você se familiarizar com ele. Superada a etapa da familiarização,ele se torna extremamente eficaz.
	A codificação exemplificada a seguir mostra um típico ponteiro:
#include <stdio.h>
int main()
{
	int i,j;
	int *p;
/* um ponteiro para um inteiro */
	p = &i;
	*p=5;
	j=i;
	printf(("%d %d %d\n", i, j, *p);
	return 0;
}
	A primeira declaração neste programa mostra duas variáveis inteiras normais, nomeadas i e j . A linha int *p declara um ponteiro denominado p. Esta linha pede que o compilador declare uma variável p que seja um ponteiro para um inteiro. O * indica que foi declarado um ponteiro em vez de uma variável normal. Você pode criar um ponteiro para qualquer coisa: um flutuante, uma estrutura, um caractere e assim por diante. Basta usar um * para indicar que deseja um ponteiro em vez de uma variável normal.
	A linha p = &i; trará algo totalmente novo para você. Em linguagem C, & é denominado operador de endereço. A expressão &i significa: “O endereço de memória da variável i”. Assim, a expressão p = &i; significa: “Atribuir para p o endereço de i”. Uma vez executada esta instrução, p “aponta para” i. Antes de prosseguir, lembre-se que p contém um endereço aleatório e desconhecido e que sua utilização causará uma falha de segmentação ou erro de programa similar.
	Um bom método para visualizar o que está acontecendo é fazer um desenho. Depois que i, j e p são declarados, as coisas parecerão assim:
	Neste desenho, as três variáveis i, j e p foram declaradas, mas nenhuma delas foi inicializada. As duas variáveis inteiras foram desenhadas como caixas contendo os pontos de interrogação (elas poderiam conter qualquer valor nesta altura da execução do programa). O ponteiro é desenhado como um círculo para distingui-lo de uma variável normal que contém um valor e as setas aleatórias indicam que ele pode estar apontando para qualquer lugar neste momento.
	Depois da linha p = &I;, p é inicializado e aponta para i, desta forma:
	Assim que p aponta para i, o local de memória i tem 2 nomes. Ele ainda é conhecido por i , mas agora também é conhecido como *p. É assim que a linguagem C se comunica com as duas partes de uma variável de ponteiro: p é o local que mantém o endereço, enquanto *p é o local apontado por aquele endereço. Logo, *p=5 significa que o local apontado por p deve ser definido como 5, assim:
	Visto que o local *p também é i, i também assume o valor 5. Conseqüentemente, j=i; define j como 5 e a instrução printf produz 5 5 5.
	A principal característica de um ponteiro é sua dupla natureza. O próprio ponteiro contém um endereço. O ponteiro também aponta para um valor de um tipo específico: o valor no endereço do ponteiro. O próprio ponteiro, neste caso, é p. O valor apontado é *p.
	24 Ponteiros: entendendo os endereços da memória
	A discussão anterior torna-se um pouco mais clara se você compreender como funciona o endereçamento de memória em um computador. Caso ainda não tenha lido, agora é uma boa hora para ler Como funcionam os bits e os bytes para entender sobre bits, bytes e palavras.
	Todos os computadores têm memória, também conhecida por RAM (memória de acesso aleatório). Por exemplo, seu computador pode ter 16, 32 ou 64 megabytes de memória RAM instalados. A memória RAM mantém os programas que atualmente estão em execução no computador, junto aos dados que estão sendo manipulados (suas variáveis e estruturas de dados). A memória pode ser vista como uma matriz de bytes. Nesta matriz, cada local de memória tem seu próprio endereço. O endereço do primeiro byte é 0, seguido por 1, 2, 3, e assim sucessivamente. O endereço de memória atua como os índices de uma matriz normal. O computador pode acessar qualquer endereço na memória, a qualquer momento (por isso o nome “memória de acesso aleatório”). Ele também pode agrupar os bytes necessários para formar matrizes, variáveis e estruturas maiores. Por exemplo, uma variável de ponto flutuante consome 4 bytes contínuos em memória. Você pode fazer a seguinte declaração global em um programa:
float f;
	Esta instrução diz: “Declare um local denominado f que possa manter um valor de ponto flutuante”. Quando o programa é executado, o computador reserva espaço para a variável f em algum lugar na memória. Aquele local tem um endereço fixo no espaço de memória, assim:
A variável f consome 4 bytes de RAM na memória.
Este local tem um endereço específico, neste caso 248,440
	Enquanto você pensa na variável f, o computador pensa em um endereço específico na memória (por exemplo, 248,440). Assim, ao criar uma instrução como esta:
f = 3.14;
	O compilador poderia traduzir isso como: “Carregar o valor 3.14 no local de memória 248,440”. O computador está sempre pensando na memória em termos de endereço e valores para tais endereços.
	A propósito, existem vários efeitos colaterais interessantes na forma com a qual seu computador gerencia a memória. Por exemplo, suponhamos que você incluiu a seguinte codificação em um de seus programas:
int i, s[4], t[4], u=0;
	for (i=0; i<=4; i++)
	{
	s[i] = i;
	t[i] =i;
	}
	Printf("s:tn");
	for (i=0; i<=4; i++)
	printf("("%d:%dn", , s[i], t[i]);
	printf("u = %dn", u);
	O resultado que você vê no programa provavelmente será algo assim:
s:t
	1:5
	2:2
	3:3
	4:4
	5:5
	u = 5
	Por que t[0] e u estão incorretos? Se olhar cuidadosamente o código, você verá que os loops for estão escrevendo um elemento além do final de cada matriz. Na memória, as matrizes são colocadas lado a lado, como mostrado abaixo:
	
	Logo, ao tentar escrever para s[4], que não existe, o sistema escreve para t[0], uma vez que t[0] é onde s[4] deveria estar. Ao escrever para t[4], na verdade você está escrevendo em u. No que se refere ao computador, s[4] é simplesmente um endereço e pode ser escrito. Como você pode ver, mesmo que o computador execute o programa, ele não está correto ou válido. O programa corrompe a matriz t no processo de execução. A execução da seguinte instrução pode resultar em conseqüências mais graves:
s[1000000] = 5;
	O local s[1000000] provavelmente está fora do espaço de memória de seu programa. Em outras palavras, você está escrevendo na memória que seu programa não possui. Em um sistema com espaços protegidos de memória (UNIX, Windows 98/NT), este tipo de instrução fará com que o sistema encerre a execução do programa. Em outros sistemas (Windows 3.1, Mac), todavia, o sistema não sabe o que você está fazendo. Você acaba danificando o código ou as variáveis em outro aplicativo. O efeito da violação pode variar de nenhum a uma tremenda pane do sistema. Na memória, i, s, t e u são todos colocados próximos uns aos outros em endereços específicos. Portanto, se você escrever além dos limites de uma variável, o computador fará o que foi solicitado, porém acabará corrompendo outro local de memória.
	As linguagens C e C++ não executam qualquer tipo de verificação de extensão ao acessar um elemento na matriz. É essencial que você, como programador, preste atenção às extensões de matriz e respeite seus limites. A leitura ou escrita não-intencional fora dos limites da matriz quase sempre leva ao comportamento errôneo do programa.
	Como outro exemplo, tente o seguinte:
#include
	int main()
	{
	int i,j;
	int *p;
	/* um ponteiro para um inteiro */
	printf("%d %dn", p, &i);
	p = &i;
	printf("%d %dn", p, &i);
	return 0;
}
	Este código diz ao compilador para imprimir o endereço contido em p, junto com o endereço de i. A variável p começa com um valor estranho ou com 0. O endereço de i geralmente é um valor alto. Por exemplo, quando executei este código, recebi o seguinte resultado:
0
	2147478276
	2147478276
	2147478276
que significa que o endereço de i é 2147478276. Após executar a instrução p = &i;, p contém o endereço de i. Tente também:
#include
void main()
{
	int *p;
	/* um ponteiro para um inteiro */
	printf("%dn",*p);
}
	Este código diz ao compilador para imprimir o valor para o qual p aponta. Porém, p ainda não foi inicializado. Ele contém o endereço 0 ou algum endereço aleatório. Na maioria dos casos, resulta em uma falha de segmentação (ou algum outro erro no tempo de execução),o que significa que você usou um ponteiro que aponta para uma área inválida da memória. Quase sempre, um ponteiro não inicializado ou um endereço de ponteiro inválido é a causa das falhas de segmentação.
	Dito isso, agora podemos ver os ponteiros por uma ótica totalmente diferente. Veja este programa, por exemplo:
#include
int main()
{
	int i;
	int *p;
	/* um ponteiro para um inteiro*/
	p = &i;
	*p=5;
	printf("%d %dn", i, *p);
	return 0;
}
	Eis o que está acontecendo:
	A variável i consome 4 bytes de memória. O ponteiro p também consome 4 bytes (na maioria das máquinas atuais, um ponteiro consome 4 bytes de memória; os endereços de memória tem 32 bits de extensão na maioria das CPU’s, embora exista uma tendência de crescimento para o endereçamento de 64 bits). O local de i tem um endereço específico, neste caso 248,440. O ponteiro p contém aquele endereço, uma vez que você disse que p = &i;. As variáveis *p e i são, portanto, equivalentes.
printf("%d", p);
o resultado é o endereço corrente da variável i.
	25 Ponteiros: apontando para o mesmo endereço
	Eis um aspecto interessante da linguagem C: qualquer número de ponteiros pode apontar para o mesmo endereço. Por exemplo, você pode declarar p, q, e r como ponteiros de inteiros e defini-los para apontar para i, assim:
int i;
int *p, *q, *r;
p = &i;
q = &i;
r = p;
	Observe que neste código, r aponta para o mesmo que p, que é i. Você pode atribuir ponteiros uns aos outros, e o endereço é copiado da direita para a esquerda durante a atribuição. Ao executar o código acima, você verá algo assim:
	A variável i agora tem 4 nomes: i, *p, *q e *r. Não há limite de número de ponteiros que podem conter (e apontar para) o mesmo endereço.
	26 Ponteiros: bugs comuns
	Bug n.º1 - Ponteiro não inicializado
	Um dos meios mais fáceis de criar um bug de ponteiro é tentar fazer referência ao valor de um ponteiro, mesmo que ele não seja inicializado e ainda não aponte para um endereço válido. Por exemplo:
int *p;
*p = 12;
	O ponteiro p não é inicializado e aponta para um local aleatório na memória ao ser declarado. Ele poderia apontar para a pilha do sistema, variáveis globais, espaço de código do programa ou o sistema operacional. Quando você diz *p=12;, o programa simplesmente tentará escrever um 12 em qualquer local aleatório para onde p apontar. O programa pode explodir imediatamente ou daqui a meia hora, ou ainda pode corromper sutilmente os dados em qualquer outra parte do seu programa sem que você nunca perceba. Isso pode dificultar bastante o rastreamento de um erro. Certifique-se de inicializar todos os ponteiros para um endereço válido antes de referenciá-los.
	Bug n.º 2 - Referências de ponteiro inválidas
	Uma referência inválida ocorre quando o valor de um ponteiro é referido, mesmo que o ponteiro não aponte para um bloco válido.
	Uma forma de criar este erro é dizer p=q;, quando q não é inicializado. O ponteiro p se tornará não inicializado e qualquer referência a*p será uma referência de ponteiro inválida.
	O único modo para evitar este bug é desenhar imagens de cada etapa do programa e se certificar de que todos os ponteiros apontam para algum lugar. Referências de ponteiro inválidas fazem com que o programa trave inexplicavelmente pelos mesmos motivos citados no bug nº 1.
	Bug nº 3 - Referências de ponteiro
	Uma referência nula ocorre sempre que um ponteiro indicando zero é utilizado em uma instrução que tenta fazer referência a um bloco. Por exemplo, se p é um ponteiro de um inteiro, o seguinte código está inválido:
p = 0;
*p = 12;
	Como não há um bloco apontado por p, tentar ler ou escrever a partir de qualquer coisa ou para aquele bloco é uma referência de ponteiro nula e inválida. Existem motivos bons e válidos para apontar um ponteiro para zero, como veremos nos artigos posteriores. Entretanto, não fazer referência a um ponteiro desta maneira é inválido.
	Todos estes bugs são fatais para um programa. Você deve prestar atenção à sua codificação para que estes bugs não ocorram. A melhor forma para tal é desenhar imagens de cada etapa de execução do código.
	27 Usando ponteiros para parâmetros de função
	A maioria dos programadores em C usa ponteiros para implementar algo chamado de parâmetros variáveis em funções. Na verdade, você tem usado parâmetros variáveis na função scanf, por isso você precisou usar & (o operador de endereço) em variáveis com scanf. Agora que você já entende os ponteiros, pode ver o que realmente está acontecendo.
	Para entender como os parâmetros variáveis funcionam, vamos ver como nos saímos ao implementar uma função swap em C. Para implementar uma função swap, talvez você queira passar por duas variáveis fazendo-as trocar seus valores. Eis uma tentativa de implementação. Digite e execute a seguinte codificação e veja o que acontece:
#include <stdio.h>
void swap(int i, int j)
{
	int t;
	t=i;
	i=j;
	j=t;
}
void main()
{
	int a,b;
	a=5;
	b=10;
	printf("%d %d\n", a, b);
	swap(a,b);
	printf("%d %d\n", a, b);
}
	Ao executar este programa, você verá que nenhuma troca ocorrerá. Os valores de a e b são passados para troca, a função swap os troca, porém quando a função retorna, nada acontece.
	Para que esta função opere corretamente, você pode usar ponteiros:
#include <stdio.h>
void swap(int *i, int *j)
{
	int t;
	t = *i;
	*i = *j;
	*j = t;
}
void main()
{
	int a,b;
	a=5;
	b=10;
	printf("%d %d\n",a,b);
	swap(&a,&b);
	printf("%d %d\n",a,b);
}
	Para ter uma idéia do que esta codificação faz, imprima-a e desenhe os inteiros a e b e digite 5 e 10 neles. Agora desenhe os dois ponteiros i e j, juntamente com o inteiro t. Quando swap é executado, ele passa os endereços de a e b. Assim, i aponta para a (desenhe uma seta de i para a) e j aponta para b (desenhe outra seta de b para j). Depois que os ponteiros são inicializados pela função call, *i é outro nome para a, e *j é outro nome para b. Agora execute o código em swap. Quando o código usa *i e *j, na verdade quer dizer a e b. Quando a função se completa, a e b foram trocados.
	Suponha que você se esqueça do & quando a função swap é executada, e que a linha swap acidentalmente se pareça assim: swap(a,b);. Isso causa uma falha de segmentação. Quando você omite o &, o valor de a é passado em vez de seu endereço. Assim, i aponta para local inválido na memória e o sistema trava quando *i é usado.
	É por isso também que scanf trava se você se esquecer do & em variáveis passadas a ele. A função scanf está usando ponteiro para colocar o valor que ele lê de volta à variável que você passou. Sem o &, scanf recebe um endereço inválido e trava.
	Os parâmetros variáveis são um dos usos mais comuns de ponteiros em C. Agora você entende o que está acontecendo.
	28 Estruturas de dados dinâmicas
	As estruturas de dados são aquelas que crescem e encolhem conforme você precisa alocar e desalocar memória de um lugar chamado pilha. Elas são extremamente importantes em C, pois permitem ao programador controlar exatamente o consumo de memória.
	Elas alocam blocos de memória a partir da pilha conforme as necessidades e vinculam estes blocos em um tipo de estrutura de dados que usa ponteiros. Quando a estrutura de dados já não precisar de um bloco de memória, ela retorna o bloco à pilha para reutilização. Esta reciclagem faz uso eficiente da memória.
	Para entender completamente estruturas de dados dinâmicas, precisamos começar com a pilha.
	29 Estruturas de dados dinâmicas: a pilha
	Um computador pessoal ou estação de trabalho tem normalmente, algo entre 16 e 64 megabytes de RAM instalados. Usando uma técnica chamada memória virtual, o sistema pode fazer trocas entre a memória e o disco rígido, criando para a CPU a ilusão de que ela possui mais memória, por exemplo, 200 a 500 megabytes. Enquanto esta ilusão se completa para a CPU, ela pode tornar as coisas extremamente lentas para o usuário. Apesar desta desvantagem, a memória virtual é uma técnica extremamente útil para “aumentar” a quantidade de RAM em uma máquina de um modo bem barato. Vamos supor, para fins de argumentação, que um

Outros materiais