Você está na página 1de 13

APOSTILA I

Programao modular em C
Por programao modular, entende-se a tcnica de se dividir o cdigo de um
determinado programa em partes, de forma a reutilizar suas funes e procedimentos.
A linguagem C permite a modularizao por meio de funes. importante perceber
que, dependendo da linguagem de programao, funo so chamadas tambm de
procedimentos ou mtodos. Em C optou-se por preservar o nome funo, tanto para
funes que retornam valores quanto para aquelas que no o fazem.
Veja a seguir uma funo que recebe um arquivo do tipo texto e o escreve na tela:
void escrever(char *texto){
printf(texto);
}
Uma chamada a esta funo pode ser feita da seguinte forma:
escrever("Gosto muito de C");
Observe o uso da palavra-chave void para indicar que a funo no retorna nenhum
valor. Veja o cdigo completo para fins de estudo:
#include <stdio.h>
#include <stdlib.h>
void escrever(char *texto){
printf(texto);
}
int main(int argc, char *argv[])
{
escrever("Gosto muito de C");
printf("\n\n");
system("PAUSE");
return 0;
}
Vejamos agora uma funo que retorna um valor:
int somar(int a, int b){
return (a + b);
}
Esta funo recebe dois argumentos e exibe sua soma. Uma chamada a ela pode ser feita
da seguinte forma:

int res = somar(4, 6);


Para fins de estudo, eis o cdigo completo:
#include <stdio.h>
#include <stdlib.h>
int somar(int a, int b){
return (a + b);
}
int main(int argc, char *argv[])
{
int res = somar(4, 6);
printf("%d", res);
printf("\n\n");
system("PAUSE");
return 0;
}
Exerccios:
1) Escreva uma funo que retorna a quantidade de caracteres em uma string fornecida
como argumento.
Dica: Strings em C podem ser criadas da seguinte forma:
char texto[] = "C e Java so linguagens muito teis";
ou:
char texto[100] = "C e Java so linguagens muito teis";
ou:
char *texto = "C e Java so linguagens muito teis";

2) Escreva uma funo que recebe duas strings como argumento e retorne a
concatenao destas:
Dica: use a funo strcat() para concatenar as duas strings.
3) Escreva uma funo que receba dois inteiros e retorne o resultado do primeiro
elevado potencia do segundo.
Obs: Use laos. No permitido usar a funo pow() do header math.h.

4) Escreva uma funo que retorne a quantidade de ocorrncias de um determinado


caractere em uma string.
Dica: Use o operador de ndice [] para acessar o caractere individual de uma string.

Saiba mais sobre true e false em C e C++


Em praticamente todas as linguagens de programao ns encontramos expresses
condicionais que definem o fluxo de execuo. Expresses condicionais so aquelas
que, quando avaliadas, resultam em um valor true (verdadeiro) ou false (falso).
Muitas linguagens de programao possuem um tipo booleano que armazena os valores
true ou false. Enquanto o C++ possui o tipo bool, o C possui uma forma bem
interessante de definir true ou false.
Em C, um valor true qualquer valor diferente de 0, incluindo numeros negativos. Veja:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int pode = 1; // verdadeiro
int nao_pode = 0; // falso
if(pode)
printf("Teste resultou verdadeiro\n\n");
if(!nao_pode)
printf("Teste resultou verdadeiro\n\n");
system("PAUSE");
return 0;
}
Lembre-se ento. False em C o valor zero. Qualquer outro valor true.

Embora C++ j possua o tipo bool, possvel usar a abordagem do zero para false e
qualquer outro valor para true em C++ tambm. Voc ver muito cdigo legado usando
este artifcio. Quer ver algo interessante agora? Execute o seguinte cdigo C++:
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
bool pode = true;
bool nao_pode = false;

cout << pode << "\n";


cout << nao_pode << "\n\n";
system("PAUSE"); // pausa o programa
return EXIT_SUCCESS;
}
Nos compiladores que obedecem o C++ padro voc ver os valores 1 e 0 serem
impressos.
Exerccios:
1) Escreva uma funo que retorna true se o valor fornecido como argumento for par e
false em caso contrrio.
Dica: use o nome is_par() para a sua funo.
2) Use uma varivel do tipo boolean como sentinela em uma lao while. Este lao
dever contar de 0 20. Porm, quando o valor for maior que 15, a varivel de sentinela
dever forar a interrupo do lao.

Ponteiros
Antes de pensarmos em ponteiros, importante nos lembrarmos de alguns aspectos
referentes variveis. Dependendo do seu conhecimento de programao, voc deve
saber que variveis possuem nomes que as identificam durante a execuo do programa.
Voc deve saber tambm que uma varivel armazena um valor (que pode ser fixo, no
caso de uma constante, ou pode mudar durante a execuo de seus cdigos).
O que poucos programadores se lembram que uma varivel possui um endereo, e que
o nome da varivel no nada mais que um apelido para a localizao deste endereo.
Desta forma, um ponteiro no nada mais que um tipo especial de varivel que
armazena o endereo de outra. Veja um exemplo:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// varivel do tipo int
int valor = 10;
// ponteiro para uma varivel do tipo int
int *p = &valor;
// exibe o valor da varivel "valor", apontada
// pelo ponteiro p
printf("%d", *p);

printf("\n\n");
system("PAUSE");
return 0;
}
Neste cdigo ns temos a declarao e definio de duas variveis:
int valor = 10;
int *p = &valor;
A primeira varivel uma varivel do tipo int e a segunda um ponteiro para uma
varivel do tipo int. Veja que devemos sempre usar "*" antes do nome de um ponteiro
em sua declarao. O smbolo "&" serve para indicar que estamos acessando o endereo
de uma varivel e no o seu contedo. O resultado destas duas linhas que agora temos
um ponteiro que nos permite acessar e manipular a varivel valor.
Observe a linha:
printf("%d", *p);
Aqui ns estamos acessando o valor da varivel apontada por p. Veja o uso do smbolo
"*" para acessar o valor da varivel. Isso chamado de desreferenciamento de
ponteiros. Pareceu complicado? Veja uma linha de cdigo que altera indiretamente o
valor da varivel valor para 30:
*p = 30;
Ponteiros so ferramentas muito importantes na programao em C. No entanto,
preciso ter muito cuidado ao lidar com eles. A primeira coisa a ter em mente que um
ponteiro no est apontando para nenhum lugar at que atribuimos a ele o endereo de
uma outra varivel. E a que mora o perigo. Um programa entra em colapso absoluto
se tentarmos acessar um ponteiro que aponta para um local de memria que j foi
liberado novamente ao sistema. No caso menos grave, estaremos tentando acessar locais
de memria invlidos ou reservados a outros programas ou tarefas do sistema
operacional. Isso nos lembra os velhos tempos da tela azul de morte.

Obtendo o tamanho de um ponteiro em bytes em C


Muitas vezes precisamos saber a quantidade de bytes que alocada quando declaramos
uma varivel do tipo ponteiro. Veja como isso pode ser feito no trecho de cdigo a
seguir:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// ponteiro para uma varivel do tipo float

float *p;
// obtm o tamanho de p em bytes
int tam = sizeof(p);
// exibe o resultado
printf("O tamanho do ponteiro e: %d bytes", tam);
printf("\n\n");
system("PAUSE");
return 0;
}
No se esquea de que uma varivel do tipo ponteiro guarda o endereo de outra
varivel. Desta forma, o valor armazenado em um ponteiro sempre do tipo int, que 2
bytes em sistemas de 16 bits, 4 bytes em sistemas de 32 bits e 8 bytes em sistemas de 64
bits.
Exerccios:
1) Escreva um programa que permita obter o tamanho em bytes dos tipos de dados: int,
long, float, double e char.
2) Escreva um programa que use um ponteiro do tipo int para acessar, alterar e exibir os
valores de outras trs variveis tambm do tipo int.
3) Modifique o programa do item 2 para trabalhar com ponteiro e variveis do tipo float.
4) Crie um programa que permita usar um ponteiro para percorrer todos os elementos de
uma matriz.

Funes e a passagem por valor e por referncia


A linguagem C permite que argumentos sejam passados s funes de duas formas
distintas: por valor e por referncia.
Na passagem por valor, alteraes no valor da varivel no corpo da funo no afetam a
varivel original. Veja um exemplo:
#include <stdio.h>
#include <stdlib.h>
void alterar(int valor){
valor = 10;
}
int main(int argc, char *argv[])
{
int valor = 5;

alterar(valor);
printf("%d", valor);
printf("\n\n");
system("PAUSE");
return 0;
}
Veja que ao imprimirmos o valor da varivel valor o resultado ser 5, e no 10, como
poderamos pensar.
Observe agora um exemplo de passagem de argumentos por referncia:
#include <stdio.h>
#include <stdlib.h>
void alterar(int *val){
*val = 10;
}
int main(int argc, char *argv[])
{
int valor = 5;
alterar(&valor);
printf("%d", valor);
printf("\n\n");
system("PAUSE");
return 0;
}
Agora o valor a ser impresso ser 10. Observe que, ao efetuar a chamada funo
alterar, ns estamos usando o operador & para indicar a posio da varivel valor na
memria. Isso permite que seu valor seja alterado como pretendamos.

Alocando memria usando a funo malloc()


A funo malloc() usada em C para alocarmos um bloco de memria. Esta funo
recebe a quantidade de bytes a serem alocados e retorna um ponteiro do tipo void
(genrico) para o incio do bloco de memria obtido. Veja sua assinatura:
void *malloc(size_t size);
Se a memria no puder se alocada, um ponteiro nulo (NULL) ser retornado.
importante se lembrar de alguns conceitos antes de usar esta funo. Suponhamos que
voc queira alocar memria para um inteiro. Voc poderia ter algo assim:

// aloca memria para um int


ponteiro = malloc(4);
Embora este cdigo esteja correto, no um boa idia assumir que um inteiro ter
sempre 4 bytes. Desta forma, melhor usar o operador sizeof() para obter a quantidade
de bytes em um inteiro em uma determinada arquitetura. Veja:
// aloca memria para um int
ponteiro = malloc(sizeof(int));
Eis o cdigo completo para um aplicativo C que mostra como alocar memria para um
inteiro e depois atribuir e obter o valor armazenado no bloco de memria alocado:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// ponteiro para uma varivel do tipo inteiro
int *ponteiro;
// aloca memria para um int
ponteiro = malloc(sizeof(int));
// testa se a memria foi alocada com sucesso
if(ponteiro)
printf("Memoria alocada com sucesso.\n");
else
printf("Nao foi possivel alocar a memoria.\n");
// atribui valor memria alocada
*ponteiro = 45;
// obtm o valor atribudo
printf("Valor: %d\n\n", *ponteiro);
// libera a memria
free(ponteiro);
system("PAUSE");
return 0;
}
Uma aplicao interessante da funo malloc() quando precisamos construir uma
matriz dinmica. Veja como isso feito no cdigo abaixo:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])

{
int i;
// quantidade de elementos na matriz
int quant = 10;
// ponteiro para o bloco de memria
int *ponteiro;
// aloca memria para uma matriz de inteiros
ponteiro = malloc(quant * sizeof(int));
// testa se a memria foi alocada com sucesso
if(ponteiro)
printf("Memoria alocada com sucesso.\n");
else{
printf("Nao foi possivel alocar a memoria.\n");
exit(1);
}
// atribui valores aos elementos do array
for(i = 0; i < quant; i++){
ponteiro[i] = i * 2;
}
// exibe os valores
for(i = 0; i < quant; i++){
printf("%d ", ponteiro[i]);
}
// libera a memria
free(ponteiro);
printf("\n\n");
system("PAUSE");
return 0;
}

Alocando memria dinmica usando a funo calloc()


A funo calloc() bem parecida com a funo malloc() e tambm usada em C para
alocarmos um bloco de memria. A diferena que calloc() recebe a quantidade de
elementos e o nmero de bytes do elemento e retorna um ponteiro do tipo void
(genrico) para o incio do bloco de memria obtido. Veja sua assinatura:
void *calloc(size_t n, size_t size);
Se a memria no puder se alocada, um ponteiro nulo (NULL) ser retornado.
importante se lembrar de alguns conceitos antes de usar esta funo. Suponhamos que
voc queira alocar memria para um nico inteiro. Voc poderia ter algo assim:

// aloca memria para um int


ponteiro = calloc(1, 4);
Embora este cdigo esteja correto, no um boa idia assumir que um inteiro ter
sempre 4 bytes. Desta forma, melhor usar o operador sizeof() para obter a quantidade
de bytes em um inteiro em uma determinada arquitetura. Veja:
// aloca memria para um int
ponteiro = calloc(1, sizeof(int));
Eis o cdigo completo para um aplicativo C que mostra como alocar memria para um
inteiro e depois atribuir e obter o valor armazenado no bloco de memria alocado:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
// ponteiro para uma varivel do tipo inteiro
int *ponteiro;
// aloca memria para um int
ponteiro = calloc(1, sizeof(int));

// testa se a memria foi alocada com sucesso


if(ponteiro)
printf("Memoria alocada com sucesso.\n");
else
printf("Nao foi possivel alocar a memoria.\n");
// atribui valor memria alocada
*ponteiro = 45;
// obtm o valor atribudo
printf("Valor: %d\n\n", *ponteiro);
// libera a memria
free(ponteiro);
system("PAUSE");
return 0;
}
Uma aplicao interessante da funo calloc() quando precisamos construir uma
matriz dinmica. Veja como isso feito no cdigo abaixo:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])


{
int i;
// quantidade de elementos na matriz
int quant = 10;
// ponteiro para o bloco de memria
int *ponteiro;
// aloca memria para uma matriz de inteiros
ponteiro = calloc(quant, sizeof(int));
// testa se a memria foi alocada com sucesso
if(ponteiro)
printf("Memoria alocada com sucesso.\n");
else{
printf("Nao foi possivel alocar a memoria.\n");
exit(1);
}
// atribui valores aos elementos do array
for(i = 0; i < quant; i++){
ponteiro[i] = i * 2;
}
// exibe os valores
for(i = 0; i < quant; i++){
printf("%d ", ponteiro[i]);
}
// libera a memria
free(ponteiro);
printf("\n\n");
system("PAUSE");
return 0;
}

Estruturas (struct) em C
Matrizes (arrays) so muito importantes quando precisamos agrupar vrias variveis de
um mesmo tipo de dados. Porm, h casos em que precisamos agrupar variveis de
diferentes tipos. Para estes casos a linguagem C nos fornece as estruturas (struct). Veja
como declar-las:
// uma estrutura Pessoa
struct Pessoa
{
char *nome;

int idade;
};
Veja que esta estrutura possui dois tipos de dados diferentes: um ponteiro para uma
cadeia de caracteres e uma varivel do tipo int.
Para declarar variveis do tipo Pessoa voc tem duas opes. A primeira consiste em
declarar as variveis juntamente com a declarao da estrutura. Veja:
// uma estrutura Pessoa
struct Pessoa
{
char *nome;
int idade;
}pessoa, cliente, chefe;
A outra forma consiste em declarar a varivel no local no qual ela ser usada. Esta
forma mais prtica. Veja um exemplo completo de como isso feito:
#include <stdio.h>
#include <stdlib.h>
// uma estrutura Pessoa
struct Pessoa
{
char *nome;
int idade;
};
int main(int argc, char *argv[])
{
// declara uma varivel do tipo struct
struct Pessoa cliente;
cliente.nome = "Osmar J. Silva";
cliente.idade = 36;
// obtm os dados
printf("O nome do cliente e: %s\n", cliente.nome);
printf("A idade do cliente e: %d\n", cliente.idade);
printf("\n\n");
system("PAUSE");
return 0;
}

Exerccio:
Faa um programa em C que troca 2 valores usando ponteiros.