Vous êtes sur la page 1sur 42

ndice

Noes Base: .............................................................................................. 2


Variveis:.................................................................................................... 2
Operadores: ............................................................................................... 4
Funes/Procedimentos: ........................................................................... 5
Condies (testes): ..................................................................................... 7
Ciclos: ......................................................................................................... 9
Input / Output: ......................................................................................... 11
String Formatting: .................................................................................... 13
#define: .................................................................................................... 14
Arrays: ...................................................................................................... 14
Ponteiros: ................................................................................................. 16
Funes 2: ................................................................................................ 18
Estruturas:................................................................................................ 19
typedef: .................................................................................................... 21
Casting: .................................................................................................... 22
Alocao dinmica de memria: .............................................................. 23
Recursividade: .......................................................................................... 24
Enumeraes: .......................................................................................... 25
Ficheiros: .................................................................................................. 25
Listas e Pilhas: .......................................................................................... 28
Hashing: ................................................................................................... 31
Arvores Binrias: ...................................................................................... 31
Programao modular:............................................................................. 32
Macros: .................................................................................................... 36
Funes bastante usadas: ........................................................................ 38
Cdigos teis: ........................................................................................... 38
Debug:...................................................................................................... 39

Isto no foi feito com base cientfica. No assumam que tudo est certo,
isto apenas um conjunto de notas que fiz para ajudar o pessoal a
perceber mais sobre programao.
Noes Base:
Todos os programas em C tm que ter funo main() e librarias/includes.
A funo main a funo que chamada no incio do programa e por tanto a funo onde
tudo comea e da ser necessria.
Librarias ou includes so ficheiros que contm funes, definies, etc. j criadas. Estas so
necessrias para poder usar funes especficas, mas no so todas necessrias. Para adicionar
uma include ao programa a sintaxe : #include <LIBRARIA.h>
O fim de uma instruo tem de ser sempre seguido por um ; . Nem sempre corresponde ao fim
de linha.
Um exemplo de um programa hello world:
#include
#include<stdio.h>
<stdio.h>
/*/*
Comentrio
Comentrio
*/*/
//Comentrio
//Comentrio
void
voidmain()
main()
{{
printf("Hello
printf("HelloWorld");
World");
}}

Para inserir comentrios no cdigo h duas formas:


- // : a partir destas 2 barras e apenas nessa linha tudo comentrio
- /* */ : tudo entre /* e */ ir ser comentrio.
Mais a frente ira ser mostrado como mostrar mensagens ao utilizador e pedir dados ao
utilizador.
O cdigo no determinado pelas linhas ou tabulaes, estas so apenas para ter um cdigo
mais organizado e mais fcil de perceber. O cdigo executado pela ordem em que as
instrues aparecem. As instrues esta separadas por ; e agrupadas em blocos de chavetas
( {} ).

Variveis:
Variveis so expresses onde so guardados valores e, como o nome indica, podem ser
alterados a qualquer momento.
As variveis podem ser globais (criadas fora de uma funo e podem ser usadas/alteradas em
qualquer funo) ou locais (criadas numa funo e apenas existem dentro delas).

-Tipos e declarao:
Ao declarar (criar) uma varivel tem que se dizer qual o tipo de varivel. Os tipos de variveis
bsicas so as seguintes:
Tipo
Caractere
Inteiro
Real
Real preciso dupla
Booleana

Declarao
char
int
float
double
bool

Formatao1
c
d
f
lf

NOTA: O bool s existe em verses recentes do C/C++.


Um tipo de varivel especial so os vetores ou arrays. Arrays so uma cadeia de valores do
tipo especificado e podem ser usados para cada tipo, embora um array de caracteres
chamado string (ou cadeia de caracteres) e tem uma formatao especfica que s.
A sua sintaxe a seguinte:
TipoVar NomeVar[TamanhoArray];
Sendo TipoVar qualquer tipo de varivel, NomeVar o nome que quiseres dar a varivel e
TamanhoArray o nmero total de clulas(valores) desse array.
Os inteiros ainda podem ter alguns prefixos e alguns tambm se podem misturar:
- unsigned : inteiro sem sinal (apenas positivos)
- signed : inteiro com sinal (predefinio)
- short : inteiro pequeno
- long : inteiro longo
- long long : inteiro longo (pelo menos o mesmo tamanho que long, no quer dizer que seja
maior);
Em respeito a isto uma funo til para saber o tamanho de cada tipo sizeof().
Podem ser declaradas vrias variveis do mesmo tipo separando o nome das variveis por
vrgulas
Librarias podem ter outros tipos de variveis para alm destes. Tambm possvel definir
novos tipos de variveis2.
NOTAS: Os nomes das variveis podem conter letras maisculas e minsculas, nmeros e
underscore (_). Porm tem que comear por uma letra. Todos os nomes de variveis so case
sensitive (sensveis a maisculas/minsculas). TM QUE SER DECLARADAS ANTES DE USAR.

1
2

Ver Formatao de Strings


Ver typedef

-Inicializao:
A inicializao dar um valor a uma varivel. importante inicializar uma varivel antes de a
usar para prevenir erros, sem inicializar todas as variveis vo ter um valor que considerado
lixo.
A inicializao de variveis pode ser feita na declarao, depois da declarao ou pedindo ao
utilizador com a funo scanf.
Para atribuir um valor a uma varivel usa-se um =. Para variveis do tipo char e arrays por
favor ver o captulo referente a arrays.
Exemplos:

#include <stdio.h>
//varivel global
int x=5; //incializao direta.
float y;
void main()
{
//variveis locais
int a,b;
a=b=6; //incializao depois da declarao
scanf("%f",&y);
printf("x=%d y=%f a=%d b=%d\n",x,y,a,b);
}

Operadores:
-Matemticos:
Operadores matemticos so operadores que fazem operaes matemticas.

+ : Soma, faz a soma de 2 valores


- : Subtrao, faz a subtrao de 2 valores
* : Multiplicao, faz a multiplicao de 2 valores
/ : Diviso, faz a diviso entres 2 valores
% : Resto da diviso inteira, devolve o valor do resto da diviso entre 2 inteiros
( ) : parenteses, servem a mesma funo que na lgebra. Do prioridade ao que estiver
dentro deles
++ : Incremento (adiciona mais 1 varivel)
-- : decremento (subtrai 1 varivel)

NOTA: o incremento e decremento podem ser feitos de 2 maneiras: ++x ou x++ (sendo x o
nome da varivel). Porm tm diferenas. Para um exemplo pratico: y = ++x; e y = x++; y ir ter
valores diferentes em ambos os casos, isto porque quando o ++ aparece antes da varivel
primeiro incrementada a varivel e depois usada, se for depois da varivel, primeiro
usada e depois incrementada. Os exemplos podiam ser assim escritos: x+=1;y=x; e y=x;x+=1;
respetivamente.

Se for para fazer uma operao com o valor da varivel pode ser usado um = juntamente com
o operador da operao antes do igual. Por exemplo, multiplicar o valor de uma varivel por 2,
pode ser feito das seguintes maneiras:
x = x*2;
X *= 2;
NOTA: A diviso pode ser de 2 tipos, inteira ou real. Se for a diviso entre 2 inteiros ir
retornar um inteiro (aproximao por defeito, isto : 2,9 ir dar 2), se um dos valores for um
float ir retornar um float. Para retornar um real da diviso entre 2 inteiros tem que se
converter pelo menos um em float3

-Lgicos:
Operadores de lgica que retornam verdadeiro ou falso (true/false)

&& : E
|| : Ou
! : Negao

-Relacionais:
Operadores de relao entre 2 valores. Retornam verdadeiro ou falso

< : menor, verdade se o da esquerda for menor


> : maior, verdade se o da esquerda for maior
<= : menor ou igual, verdade se o da esquerda for menor ou igual ao da direita
>= : maior ou igual, verdade se o da esquerda for maior ou igual ao da direita
== : igual, verdade se os 2 valores forem iguais
!= : diferente, verdade se os 2 valores forem diferentes

Funes/Procedimentos:
Funes so bastante parecidas as funes matemticas, recebem valores (ou no) e retornam
(devolvem) um valor.
A diferena entre funes e procedimentos que um procedimento no devolve valor
nenhum. Para facilitar a coisa vou chamar tudo de funes.

-Declarao:
As funes so declaradas de maneira parecida as variveis. Tem que se especificar o tipo de
varivel a retornar, o nome da funo e os parmetros de entrada:
TipoVar NomeFuno(TipoVar NomePar)
Sendo TipoVar o tipo de valores a retornar (se for um procedimento, ou seja, no retorna
nada, ento no tipo escreve-se void).
As funes tm de ser declaradas antes de poderem ser chamadas.
3

Ver Casting

A parte do cdigo que a funo faz tem que estar entre chavetas ( { } ) mesmo que use apenas
uma linha. Ao fechar chavetas no precisa de ;

-Parmetros:
Os Parmetros de entrada podem ser quantos quiserem, para determinar os parmetros da
mesma forma que so declaradas variveis, s que os parmetros so separados por vrgulas e
cada parmetro tem de ter o tipo especificado.
As funes tambm podem ter parmetros de entrada opcionais. Para isso a inicializao do
parmetro feito quando especificado (Ateno: os parmetros opcionais tm que ser os
ltimos).

-Retorno (Devoluo)
Para retornar um valor numa funo usa-se a palavra reservada return.
Ateno: Depois de um return ser chamado j nenhum cdigo da funo ir ser executado.

-Chamada da funo:
Chamar uma simples, apenas tem que se escrever o nome da funo e depois entre
parenteses colocar as variveis ou constantes que serviram como parmetros de entrada
separadas por vrgula. A sintaxe tem que corresponder a definio da funo. Se no tiver
parmetros de entrada, deixa-se em branco entre os parenteses ou escrever void.
Para atribuir o valor retornado por uma funo a uma varivel apenas tem que se igualar (usar
o = ) a varivel funo.
Para usar como parmetro arrays ou saber mais sobre funes vai ao captulo das Funes
Parte 2.

Exemplo:
#include <stdio.h>
void Ola() //procedimento
{
printf("Procedimento: Ola\n");
}
int Soma(int x, int y) // funo que devolve 1 inteiro e com 2 inteiros como
parmetros de entrada
{
return x+y;
int z = x-y; // NUNCA VAI SER EXECUTADO!!
}
float Div(float x, float y=2.5) //funao que devolve 1 float com 2 floats como
parmetros de entrada e 1 como opcional
{
return x/y;
}
void main()
{
int s = Soma(2,3);
float f = Div(5);
Ola();
printf("Soma = %d\n",s);
printf("Divisao = %f\n",f);
}

Condies (testes):
As condies e/ou testes so uma das partes mais importantes da programao. Isto serve
para verificar valores e determinar o que fazer consoante o valor que for.

-ifelse ifelse
Teste para verificao de valores mais usual. Traduzido para portugus seria seseno se
seno.
O if (se) verifica se uma expresso verdadeira, se for faz o cdigo que for definido para ele
executar atravs de chavetas. Se for apenas uma instruo as chavetas sero desnecessrias.
O else if(seno se) e o else(seno) no so necessrios e sero executados se o if falhar. O
else ser chamado se o if e else if (se houver else if) derem falso. Pode conter quantos else if
quanto for necessrio.
A expresso que o if e else if verificam est dentro de parenteses a seguir a palavra. A
expresso pode conter um qualquer conjunto de instrues desde que o valor devolvido seja
um booleano. Por exemplo pode-se misturar operadores lgicos e relacionais.
NOTA: O bool apenas existe em verses recentes de C/C++. At l era usualmente usado um
char ou int para fazer as verificaes. false e true tambm no existiam, eram usado o 0 e 1. 0
false e 1 true.

Exemplo:
bool b=false, c=true;
int x=5;
if(b)
printf("b e verdadeiro.\n");
else if(x == 5 && !c)
{
printf("b e falso.\n");
printf("x e 5.\n");
printf("c e verdade.\n");
}
else
printf("O if e else if deram falso.\n"); //ir fazer este printf

-switch case
O switch permite agarrar o valor de uma expresso e comparar esta com constantes.
Primeiro usa-se switch para ir buscar o valor da expresso e depois abre-se um bloco para ele
(chavetas). Dentro desse bloco vai-se compara essa expresso com constantes atravs do case.
Os case no necessitam de chavetas, mas precisa de um : antes do bloco e sempre preciso
usar um break;4 no fim de cada case, para no executar o cdigo dos seguintes case. Caso
todos os case deem falso ir executar o cdigo do default (semelhante ao else), que
opcional.
Se vrios case forem executar o mesmo cdigo basta no colocar break;
Exemplo:
void main()
{
int x=2, y=3, sum;
char op = '-';
switch(op)
{
case '+':
sum = x+y;
break;
case '-':
sum = x-y;
break;
case '/':
sum = x/y;
break;
case '*':
sum = x*y;
break;
}
printf("%d\n",sum);
}

Ver Capitulo Ciclos

-Operador Ternrio:
O operador ternrio executado de maneira parecida ao ifelse, porem o que o operador
ternrio faz verificar se uma expresso verdadeira ou falsa e retornar um valor para cada
uma dessas. No serve para verificaes extensas ou com cdigo extenso.
O operador ternrio usa 2 smbolos que so ? e :
A sintaxe a seguinte:
Expresso ? resultado1 : resultado2
Verifica se a Expresso verdadeira, se for devolve o valor do resultado1, se for falso retorna
resultado2.
Exemplo:
void main()
{
int x=2,y;
bool multi = false;
y = multi ? x*2 : x/2; // y = 2/2 = 1
}

Ciclos:
Ciclos so estruturas que repetem um determinado cdigo as vezes que forem definidas, se
forem definidas.

-for:
O ciclo for dos mais usados porque permite fazer a inicializao, verificao e incrementao
numa s linha. Em portugus significa para e ainda em portugus a sintaxe seria algo do
gnero:
para var igual qualquercoisa enquanto expresso incrementa x
A sintaxe em C a seguinte:
for(var=com; expresso; var += incremento) { }
Como se pode ver o for composto por 3 campos:
1. Inicializao: aqui inicializa-se a varivel(variveis) que necessitem de ser inicializadas
neste ciclo.
NOTA: em C standard no era possvel criar uma varivel apenas para o ciclo neste
campo, porm em verses mais recentes de C j possvel.
2. Verificao: Aqui colocada a expresso que verificada em cada iterao do ciclo,
quando for falsa o ciclo termina.
NOTA: Cuidado com ciclos infinitos
3. Incremento: Aqui determinado o incremento da varivel(variveis) em cada iterao.
Este campo executado no fim de cada iterao antes da verificao.

Nenhum dos campos obrigatrio. Se o ciclo for apenas repetir uma instruo ento no
preciso chavetas, caso contrrio sempre preciso chavetas.
Exemplo: 5=1
void main()
{
int sum = 0;
for(int i=1; i<6; i++)
{ //no necessrio chavetas aqui
sum+=i;
}
printf("Somatorio = %d\n", sum);
}

-while
Em portugus enquanto, faz a verificao de uma expresso e enquanto for verdadeira
repete a seo de cdigo definida.
Sintaxe:
while(expresso){}
Mais uma vez, se for repetir apenas uma instruo as chavetas no so necessrias.
NOTA: A inicializao das variveis para a expresso tm de ser feitas antes do ciclo e o
incremento desta tem que ser feito dentro da seco do cdigo do ciclo.
Exemplo: 5=1
void main()
{
int sum = 0, i=1;
while(i<6)
sum+=i++;
printf("Somatorio = %d\n", sum);
}

-dowhile
Em portugus fazenquanto um ciclo como o while apenas com uma diferena: o cdigo
do ciclo sempre executado 1 vez pelo menos, ao contrrio do while e for em que a seco de
repetio pode nunca ser executada caso a expresso seja falsa.
Neste ciclo primeiro executado o cdigo e s depois feita a verificao. bastante usado
para fazer menus em que este tem que ser mostrado pelo menos a primeira vez.
A semelhana do resto, se for apenas executar uma instruo no precisa de chavetas.
Exemplo: 5=1

void main()
{
int sum = 0, i=1;
do
{
sum+=i;
i++;
}
while(i<6);
printf("Somatorio = %d\n", sum);
}

-Ciclos infinitos:
Ciclos infinitos, como o nome o indica, so ciclos sem fim determinado. So uteis para repetir
uma seco de cdigo sem fim previsto. Para sair dele necessrio usar um break;
muito usual ocorrerem ciclos infinitos por distrao, preciso ter cuidado com a correta
inicializao e incrementao de variveis, especialmente nos ciclos while.
Para criar um ciclo infinito pode-se usar, por exemplo:
for(;;) ou while(1)

-break;
O break uma definio usada para quebrar o cdigo de ciclos e switch case.

-continue;
O que o continue faz continuar o ciclo para a prxima iterao sem acabar o cdigo que falta
da seco. til, especialmente, em ciclos para fazer verificaes em arrays.

Input / Output:
A parte mais importante de um programa o contacto com o utilizador. Para isso preciso
mostrar-lhe mensagens e receber valores dele. A libraria stdio.h fornece 2 funes para esse
fim: scanf e printf

-printf:
O printf uma funo para mostrar uma mensagem no ecr. Esta funo serve para mostrar
mensagens fixas ou com os valores de variveis ou constantes.
Sintaxe:
printf(char[] string, [var]);
Sendo string a string a mostrar e var os valores a substituir na formatao da string e so
opcionais.
Os valores de var iram substituir na string os formats coretos para eles, estes esto definidos
atravs da combinao de % com o format da varivel, tm que corresponder o nmero de % e
na string de vars na funo. Para mais informaes ver String Formatting e Variveis.

Exemplo:

void main()
{
int x = 5;
printf("x = %d\n", x);
}

Output:
x=5

Sugiro darem uma vista de olhos aqui: http://www.cplusplus.com/reference/cstdio/printf/

-puts
Faz o mesmo que o printf mas mais bsico, mostra um string sem format no ecr.
puts(char []input);

-scanf
O scanf serve para ler informao que o utilizador insira no ecr.
A sintaxe:
scanf(string,[vars,]);
A string uma string com os formats das variveis que pretendido ler. Pode-se ler mais do
que uma varivel de uma s ver. Vars as variveis que iram receber os valores.
Todos os tipos de variveis iram ter que levar um & antes do nome da varivel5 exceto
variveis do tipo string. No possvel ler strings com espao sem usar flags no formatting da
string.
O scanf retorna o nmero de variveis a qual atribuiu valores. Por exemplo se estiverem a
tentar pedir ao utilizador 5 valores mas por algum motivo no insere os numa varivel ele ira
retornar 4. Vejam a parte das funes mais usadas.
Sugiro darem uma vista de olhos aqui: http://www.cplusplus.com/reference/cstdio/scanf/

-gets
Vai buscar uma string que o utilizador introduza at encontrar o \n da nova linha. Assim podese ler uma string ignorando os espaos em branco.
Apenas tem um parmetro: a varivel em que vai guardar a string.
ATENAO: DEPRECADO!! PARA MAIS INFOMAES TENTAR USAR NO VS QUE ELE DA LOGO
ERRO E DIZ O QUE USAR!!

-getcar
Vai buscar um s char. til para fazer pausas no cdigo, s avana at o utilizador pressionar
enter.

Ver Ponteiros

No tem parmetros e retorna o char lido.

String Formatting:
As strings so um conjunto de caracteres e um tipo de array que segue normas especificas.
Uma string sem ser em varivel especificada atravs do uso de aspas () (no caso de 1 s
caracter pelicas ()).
O fim de uma string especificado pelo caracter \0 (no caso de escrever uma string com as
no preciso especificar o \0 pois ele determinado automaticamente).
As strings podem conter vrios tipos de caracteres especiais:

\n : faz enter (uma nova linha)


\t : faz uma tabulao
\b : backspace
\0 : fim de string
\v : tabulao vertical
\\ : mostra o caracter \
\ \ : mostra a pelica ou aspa
%% : mostra o smbolo percentagem

No caso dos printf e scanf as strings ainda podem ter um conjunto de caracteres para a
colocao de valores (chamados placeholders, que literalmente guardam o local (traduo
literal) para uma varivel, mas quem quer saber do seu nome?):

%d ou %i : int
%u : unsigned int
%f : float
%c : char
%s : char[] (string)
Entre outros

Entre o % e a letra correspondente ao tipo ainda pode levar flags e descritores:

Flags:
o
o
o
o
o

- : alinhamento a esquerda (default a direita)


+ : mostra o sinal do numero
(espao em branco) : deixa um espao em branco se no for mostrar o sinal
0 : mostra os 0s a esquerda
^ : negao, usado no scanf para strings, l a string at encontrar um
dos caracteres especificados, por exemplo %[^\0]s ir ler toda a string
(incluindo espaos em branco) at ao fim. Pode conter mais do que um
caracter %[^\0\n;]s ir ler at encontrar \0 \n ou um ;
Descritores:
o (numero) : indica o numero de caracteres a serem mostrados (por
exemplo %06d ir mostrar 6 caracteres e mostra os 0s a esquerda at o 6
caracter, se no tiver o 0 mostra espao em branco)
o .(numero) : preciso para os float, numero de casas decimais
Especificadores:

o
o
o

h : short int
l : long int
ll : long long int

#define:
#define uma instruo do pr-processador que pode dar nomes a cdigos. O #define
(sempre em minsculas) define um nome a um valor, instruo ou conjunto de instrues ou
at mesmo expresses.
bastante usado para definir um nome ao tamanho mximo de um array e assim tornando
muito mais fcil alterar o tamanho sem ir procurar e alterar em todo o cdigo, mas alterar
apenas no #define (mas no a nica maneira de o usar).
Exemplo:
#DEFINE MAX_PALAVRA 50
Isto vai sempre, que encontrar no cdigo, a expresso MAX_PALAVRAS pelo valor 50.
VER MACROS!!

Arrays:
J foi explicado mais ou menos o que so arrays. Basicamente so uma cadeia de variveis do
mesmo tipo seguidas.
Os arrays podem ter varias dimenses, podem-se assim formar vetores, matrizes, etc.

-Declarao:
Array unidimensional (vetor):
int x[50];
Array bidimensional (matriz):
int x[4][4];
Array tridimensional:
int x[2][2][2];
Etc.
Para ser mais fcil de perceber pode-se assumir que um array bidimensional um array de
array e o array dimensional um array de matrizes.
Na declarao de arrays o(s) nmero(s) indicam o nmero de clulas (espaos) desse array.
Este nmero tem que ser uma constante e pode usar termos criados com #define

-String:
char Nome[MAX_NOME];
Ir criar uma string chamada Nome com 50 espaos para caracteres.
As strings so um caso especial de arrays, isto porque se declararmos uma string com 50
clulas apenas podemos ter uma palavra/frase no mximo com 49 caracteres, porque tem que
se reservar sempre uma clula para o caracter \0 que indica o fim da string e por isso o
nmero de caracteres legveis que uma frase numa string pode ter o nmero de clulas -1.
Devido a esta formatao todo o cdigo para trabalhar com strings tem que ser diferente do
resto dos tipos de variveis, a libraria sting.h contm vaias funes para manipular strings,
como copiar, comparar, etc.
Podem usar um array de char sem ser string, por exemplo para guardar alguns caracteres e
nesse caso no preciso usar o \0 nem se usam as funes para strings. Tornam-se arrays
normais como se fosse de int ou float.

-Inicializao:
Para inicializar um array na declarao parecido as variveis, porem tem que se usar
chavetas e separar os valores de cada clula por vrgulas. No necessrio inicializar todas as
clulas, basta apenas algumas, todas as outras iram ter o valor 0 por defeito.
Exemplo:
int x[5] = {1,2,3};
O array x ir ter os valores 1,2,3,0,0 no array.
Caso seja do tipo char inicializado da mesma forma, mas os valores tm de estar entre plicas
().
char nome[5] = {N,o,m,e}; //no string, mas sim um array de char
char nome[] = Kimossab; // uma string, neste caso o \0 adicionado automaticamente
Ao inicializar um array desta forma no preciso indicar o nmero de clulas, por exemplo:
int y[] = {1,2,3};
Neste caso o array y vai ter os valores 1,2,3. Notar que diferente do x!
No caso de arrays bi/tri/whatever dimensionais a inicializao feita da mesma forma, porm
so usadas chavetas e vrgulas para separar as primeiras das outras clulas (da eu antes ter
dito que podia-se chamar de array de array), e s um conjunto que pode no ter um nmero
mximo de clulas.
int mat[][3] = { {1,2,3},{4,5,6}};
O array mat ir criar uma matriz igual a seguinte:
1

(int mat[2][3] = {{1,2,3},{4,5,6}};)

Para se perceber melhor em arrays grandes podem-se usar mais do que uma linha.

-Aceder a clulas:
Para aceder ao valor de uma clula bastante simples, apenas se tem que escrever o nome do
array e entre parenteses retos colocar o ndice da clula que se quer aceder.
NOTA: os ndices dos arrays comeam sempre no 0 e vo at ao nmero de clulas menos 1.
Cada clula funciona da mesma maneira que qualquer varivel do tipo do array.
Quando preciso aceder a varias clulas do array usa-se um ciclo para no estar a usar vrias
linhas de cdigo desnecessariamente.
Dito assim at parece complicado, por isso esto aqui alguns exemplos:
#define MAX_BAR 20
int foo[][3] = {{1,2,3},{4,5,6}};
void main()
{
int bar[MAX_BAR];
for(int i=0; i<MAX_BAR; i++)
bar[i] = i*i;
printf("foo[1][2] = %d * bar[10] = %d = %d\n", foo[1][2],bar[10],
foo[1][2]*bar[10]);
}

Output:
foo[1][2] = 6 * bar[10] = 100 = 600

-Outras consideraes:
Nos arrays nem sempre se vai usar todas as clulas a toda a hora, por isso convm usar uma
varivel com o tamanho do array a parte e usa-la para funes por exemplo.
As vezes queremos inserir ou remover um valor numa determinada posio, para isso
importante compreender que temos que movimentar todas as clulas a frente da que
queremos para a frente ou trs e para isso tem que se usar variveis auxiliares para guardarem
temporariamente um valor.

Ponteiros:
Agora que comea a confuso.
Ponteiros so variveis (dos vrios tipos que existem) em que o valor o endereo de
memria que esta ocupa.
Basicamente num ponteiro no temos o valor da varivel mas sim a sua localizao na
memria. Por isso que se chamam ponteiros (ou apontadores, ou como um ou outro stor diz
ponteros), porque apontam para a memria.

preciso ter cuidado a trabalhar com ponteiros porque estamos a trabalhar com a memoria e
no com valores, por isso fcil enganarmo-nos e irmos para endereos que no devemos e
crashar tudo.
Antes que haja confuso (ou para confundir mais) convm eu explicar uma cena. Os ponteiros
podem ser dos mais variados tipos (int, char, float, whatever), mas este tipo apenas indica o
tipo de valores que iram ser guardados na memria, porque na realidade o ponteiro sempre
um inteiro (pode ser hexadecimal ou octal se preferirem) porque ele tem como valor o
endereo!
Explicado mais ou menos isto, vamos para o porque de ponteiros: os ponteiros so usados
para poder alterar valores de variveis dentro de funes. Os parmetros de entrada das
funes so apenas uma cpia da verdadeira varivel para prevenir que esta se altere na
funo. Os ponteiros fazem com que a varivel seja a original.

-Declarao:
Para criar um ponteiro igual a criar uma varivel. A nica diferena que entre o tipo de
varivel e o nome tem que se colocar um asterisco (*).
int *ptrx;

-Inicializao:
Os ponteiros podem ser inicializados com o valor NULL, isto indica que o ponteiro naquele
momento no aponta para nenhuma varivel. Lembrem-se tudo tem que ser inicializado, nem
que seja a NULL.
Tambm se pode dar o endereo de memria de uma varivel diretamente a qualquer altura

Ainda se pode alocar um espao de memria dinamicamente para o ponteiro.6

-Aceder ao endereo de uma varivel:


possvel saber o endereo de memria de uma varivel e atribu-la a um ponteiro tendo
assim 2 varivel que na realidade so a mesma.
bastante fcil, apenas tem-se que usar um e comercial (&) antes do nome da varivel e isto
ir retornar o endereo de memria.

-Aceder ao valor de um ponteiro:


Os ponteiros apontam para um endereo de memria, mas como sabemos o valor que esse
endereo guarda? Simples: usa-se um asterisco (*) antes do nome da varivel e assim obtmse o valor que est nesse espao de memria. de notar que assim age como se fosse uma
varivel normal, portanto pode-se alterar o valor.

Ver Alocao Dinmica de Memria

-Ponteiro de ponteiro:
Os ponteiros ocupam espao na memria, portanto possvel criar ponteiros de ponteiros
assim apontar para a memria que aponta para outra memria, mas no vou sequer
aprofundar isso, deixo isso para vocs experimentarem.

-Ponteiros e arrays:
Como j foi dito os arrays usam vrias partes da memria seguidas (sejam uni, bi, tri, n
dimensionais, sempre tudo seguidinho) e por isso tm vrios endereos.
Os arrays e os ponteiros so bastante parecidos. Os arrays apontam para o primeiro endereo
que usam (o endereo da clula 0) e depois entre parenteses retos determina-se em que clula
se quer ir buscar a informao (a memria dos arrays est seguida). Os ponteiros funcionam
da mesma forma, eles apontam para o primeiro endereo e depois para apontar para os
outros pode-se usar parenteses retos ou somar o nmero de clulas a frente.
Para mostrar que so essencialmente o mesmo:
void main()
{
int v[4] = {0,1,2,3};
int *ptrv = v;
printf("%d\n",*ptrv);
printf("%d\n",*(ptrv+2));
printf("%d\n",ptrv[2]);
}

Output:
0
2
2

Funes 2:
Depois de perceber como funcionam os ponteiros e vetores vamos complicar as funes.
Os parmetros de entrada so variveis locais que iram receber os valores de outras variveis,
ou seja, estas so cpias das originais, por isso qualquer valor que aqui seja alterado apenas e
s alterado nesta funo, a original mantm-se como estava.
As funes apenas podem retornar 1 varivel! Por isso uma maneira de poder alterar vrios
valores dentro de uma funo usando ponteiros como parmetros de entrada, assim
alteramos a varivel original e no uma cpia.
Como j foi dito, arrays e ponteiros so fundamentalmente semelhantes e por isso ao alterar
um array numa funo ir ser alterado o original. esta a razo por no usar o & no scanf para
strings e usar para os outros tipos.
Exemplo que mistura varias coisas ditas anteriormente:

//adicionar um valor a um array de inteiros de maneira ordenada e devolve a


posio
int addordenado(int *v, int add, int *tam)
{
int i=0, n, aux, aux2;
while(i < *tam && v[i] < add)
i++;
aux = v[i];
(*tam)++; //sem parenteses seria como *(tam++)
for(n=i+1; n<*tam; n++)
{
aux2 = v[n];
v[n] = aux;
aux = aux2;
}
v[i]=add;
return i;
}
void main()
{
int arr[20] = {1,2,4,5}, t=4, pos;
pos = addordenado(arr,3,&t); //adiciona o valor 3 ao array
printf("Array de tamanho : %d\nValor 3 adicionado na posicao %d.\n\n",
t, pos);
for(int i=0; i<t; i++)
printf("|%d|", arr[i]);
}

Output:
Array de tamanho: 5
Valor 3 adicionado na posicao: 2.
|1||2||3||4||5|

Estruturas:
Para alm dos outros tipos de dados que j foram falados existe o tipo struct. As estruturas
podem conter varias variveis de vrios tipos diferentes e assim sendo fcil de guardar vrios
tipos de dados numa s varivel.

-Declarao
A sintaxe simples:
struct NomeStruct
{
declarao_campos;
};
O NomeStruct o nome da estrutura que se quer dar. Dentro do bloco feita a declarao dos
campos (variveis) que iram fazer parte da estrutura. possvel fazer a inicializao destas na
declarao. O ponto e vrgula no fim do bloco necessrio.

-Criao de variveis:
Uma estrutura no uma varivel, mas sim um tipo. Assim sendo primeiro criamos uma
estrutura e depois criamos variveis com essa estrutura, estas podem ser, variveis normais,
ponteiros ou arrays.
Para isso do mesmo modo que a declarao de uma varivel mas substituindo o tipo por
struct NomeStruct .
Duas variveis com a mesma struct como tipo sero variveis diferentes e portanto os campos
da estrutura iram ter valores e endereos diferentes!
Tambm se podem criar as variveis quando se define a estrutura, pondo o nome das variveis
a frente do } e antes da ;

-Aceder a campos da estrutura.


Para aceder aos valores da estrutura de uma varivel preciso colocar um ponto a seguir ao
nome da varivel e colocar o nome do campo que se quer. Se a varivel for um ponteiro usa-se
uma seta -> (tracinho + >), se usarmos os parenteses retos (array ou ponteiro) ento usa-se
um ponto.
Caso a varivel seja um ponteiro tem que se verificar se este no NULL. Tentando aceder a
um campo de um ponteiro NULL ir crashar o programa.
Exemplo:
Este programa ira criar uma turma de quantos aluno o utilizador desejar.

#include <stdio.h>
#define MAX_NOME 100
#define MAX_ALUNO 25
struct aluno
{
char nome[MAX_NOME];
int idade;
int numero;
float nota;
};
void AdicionarDadosAluno(struct aluno *a)
{
if(!a) //if(a == NULL)
return;
printf("\nInsira o numero do aluno: ");
scanf("%d", &a->numero);
printf("Insira o nome do aluno: ");
scanf("%s", a->nome);
printf("Insira a idade do aluno: ");
scanf("%d", &a->idade);
printf("Insira a nota do aluno: ");
scanf("%f", &a->nota);
}
void main()
{
struct aluno turma[MAX_ALUNO];
int tam;
printf("Insira o numero de alunos: ");
scanf("%d", &tam);
for(int i=0; i<tam; i++)
AdicionarDadosAluno(&(turma[i]));
}

typedef:
O nome typedef vem de type definition que significa definio de tipos. Basicamente isto
facilita bastante a criao de novos tipos para a criao mais fcil de variveis. Por exemplo
com o typedef podemos definir o tipo int* como ptrint e assim para criar um ponteiro apenas
temos que escrever ptrint e no int *.
O typedef bastante usado para criar um tipo de variveis para as estruturas e assim a criao
de variveis fica mais fcil porque no tem que se escrever struct. Neste caso no precisamos
de dar nome a estrutura.
possvel criar mais do que um tipo numa s definio, por exemplo numa struct podemos
criar uma definio para variveis normais e outra para ponteiros.
Seguindo o exemplo anterior se usarmos typedef o cdigo podia ficar como o seguinte:

#include <stdio.h>
#define MAX_NOME 100
#define MAX_ALUNO 25
typedef struct
{
char nome[MAX_NOME];
int idade;
int numero;
float nota;
}ALUNO, *PTALUNO; //PTALUNO > ponteiro
void AdicionarDadosAluno(PTALUNO a)
{
if(!a) //if(a == NULL)
return;
printf("\nInsira o numero do aluno: ");
scanf("%d", &a->numero);
printf("Insira o nome do aluno: ");
scanf("%s", a->nome);
printf("Insira a idade do aluno: ");
scanf("%d", &a->idade);
printf("Insira a nota do aluno: ");
scanf("%f", &a->nota);
}
void main()
{
ALUNO turma[MAX_ALUNO];
int tam;
printf("Insira o numero de alunos: ");
scanf("%d", &tam);
for(int i=0; i<tam; i++)
AdicionarDadosAluno(&(turma[i]));
}

Casting:
Casting o ato de alterar o tipo de varivel diretamente. H certas funes que no devolvem
um tipo de dados especfico7 e nesse caso usamos um casting para certificarmos que os dados
ficam corretos e o programa no dar warnings de tipos de variveis erradas.
Tambm converte alguns tipos de variveis para outros. Por exemplo, queremos fazer a
diviso de 2 int, mas queremos o resultado em float, para isso vamos ter que fazer um cast em
pelo menos 1 int.
Para fazer casting apenas temos que escrever o tipo de dados desejado entre parenteses antes
do nome da varivel a converter.
Ateno, nem todos os tipos, especialmente arrays, structs, d para converter diretamente par
outros.
7

Um exemplo as funes de alocao de memria (malloc realloc)

Exemplo:
int x = 5, y=2;
float f = x/(float)y;
Neste caso f ir ficar com valor 2.5 em vez de 2 que seria o valor se no fosse feito casting.

Alocao dinmica de memria:


Um dos problemas com arrays que eles no so dinmicos, isto tem sempre um nmero
mximo de clulas definido e muitas vezes esse nmero pode ser em demasia ou no chegar.
Com alocao dinmica esses problemas deixam de existir, no desperdiada memria
desnecessariamente e se for preciso mais pode-se alocar.
Para usar a alocao dinmica tem que se usar ponteiros de um tipo qualquer.
H 3 formas de alocar a memria, atravs das funes malloc, realloc e calloc. As funes tm
a seguinte sintaxe:
void *malloc(size_t nBytes);
void *calloc(size_t num, size_t nBytes);
void *realloc(void *ptr, size_t nBytes);
A calloc bastante semelhante malloc, por isso no a uso nos exemplos. size_t o tipo
unsigned int,nBytes o tamanho em Bytes, num o nmero de elementos.
O realloc como o nome diz, realoca um ponteiro. Altera o tamanho alocado de um ponteiro
ptr. Caso o ptr seja NULL ele age como malloc.
IMPORTANTE

A memria no infinita e pode nem sempre haver espao e nesse caso a alocao
no feita. Sempre que usarem uma destas funes verifiquem logo se deu NULL ou
no. Habituem-se para no se esquecerem.
A memria depois de alocada tem que ser desalocada quando j no necessria.
Cada vez que fazem malloc, calloc ou realloc (exceto se for para realocar, como disse
o realloc pode ser usado como malloc) usem logo a funo free para no se
esquecerem!
Se no usaram uma destas funes ento o free no preciso nem se pode usar.
Arrays no so alocados dinamicamente por isso o free no tem efeito neles.

Com o malloc no nBytes temos que indicar o nmero de Bytes que queremos alocar. Para isso
usamos a funo sizeof que retorna o tamanho de uma varivel ou tipo em Bytes. No caso de
arrays multiplicamos o resultado do sizeof com o nmero de clulas desejadas. Em caso de
arrays bi/tri/whatever dimensionais iremos multiplicar o sizeof pelos diferentes nmeros de
clulas. Exemplo:
Int *matriz = (int *)malloc(sizeof(int) * 2 * 3); //int matriz[2][3];

Nos casos que tm mais do que uma dimenso no possvel usar mais do que 1 conjunto de
parenteses retos, por isso temos que ir calcular a posio na memoria relativamente
primeira clula. Sejam nc e nl o nmero da clula desejada no mximo dos usados no exemplo
anterior (2 e 3 respetivamente). Para acedermos a esse valor temos que fazer do seguinte
modo:
matriz[nc*3+nl];
//ou *(matriz+nc*3+nl);
Isto o mesmo que matriz[nc][nl] caso no fosse um ponteiro. O 3 representa o nmero
mximo do segundo parenteses reto. Isto serve para qualquer ponteiro para arrays mais de 1
dimenso.
Exemplo:
void main()
{
int *matriz = (int *)malloc(sizeof(int) * 2 * 3);
if(!matriz)
return;
for(int i=0; i<2; i++)
for(int n=0; n<3; n++)
matriz[i*2+n] = (i+1)*n;
for(int i=0; i<2; i++)
for(int n=0; n<3; n++)
printf("|%d|", *(matriz+i*2+n));
free(matriz);
}

Recursividade:
Ah, a bela da recursividade xD
Como j devem ter percebido (se no deviam) as funes podem ser chamadas dentro de
outras funes e at ser usadas como argumentos. Da nada de novo. Porm as funes
tambm se podem chamar a si prprias e comeam assim um ciclo sem ser for nem while.
Em teoria recursividade quando algo est definido em funo de si mesmo. Basicamente
chamaste a ti mesmo para te acabar. o que aqui diz.
J agora, mtodo iterativo o que no recursivo, ou seja usa um ciclo for por exemplo.
A maior parte das vezes usando recursividade menos eficiente pela quantidade grande de
chamadas da funo que ocupam memria quando comparado com uma funo iterativa. No
entanto pode ser mais fcil de perceber/fazer e muitas vezes nem usa variveis auxiliares. Em
rvores binrias muito usado a recursividade em vez de um mtodo iterativo pela maior
facilidade de fazer e perceber, a maior parte dos exemplos ficar nessa seco!

Um exemplo muito usado e pedido uma funo que faa a sequncia de Fibonacci8
int Fib(int N)
{
if(N == 0 || N == 1)
return N;
else return Fib(N-1)+Fib(N-2);
}

Neste caso considera-se o 0 como o primeiro valor.


Numa funo recursiva comea-se com o critrio de paragem, sem ele a funo entra num
ciclo infinito e BOOM!
Tentem usar o mnimo (0 do melhor) de variveis auxiliares, pois so criadas cada vez que a
funo chamada e chamada demasiadas vezes!
Tentem usar sempre que possvel mtodos iterativos, so mais rpidos e consomem menos
memria, mas so mais difceis de fazer e muitas vezes de perceber.

Enumeraes:
O enum uma maneira fcil de criar expresses com um valor especfico.
Um exemplo as variveis booleanas. Apenas em verses mais recentes o bool j vem
implementado, mas antes disso para poder-mos ter o true e false usava-se um enum:
typedef enum {true;false}bool;
A sintaxe praticamente igual s estruturas. Porem os elementos no tm um tipo definido,
so apenas expresses. Se no lhes dermos um valor por predefinio so lhes atribudos os
valores a comear em 0 at ao numero de elementos -1. Se por exemplo quisermos os meses
do ano em nmero a comear em 1 bastava fazer um enum{janeiro =1, fevereiro,maro,
Deste modo o enum comea no numero 1 e vai dar o resto dos valores automaticamente.
Para aceder do mesmo modo que a varivel bool e no com pontos ou setinhas como nas
estruturas.

Ficheiros:
Trabalhar com ficheiros bastante importante para guardar e carregar dados.
Para trabalharmos com ficheiros temos que criar um ponteiro para o ficheiro do tipo FILE.
De certo modo funcionam como se fosse um livro, antes de inserires ou leres tens que abrir o
ficheiro em modos diferentes, por exemplo modo leitura ou modo escrita. Para guardar as
alteraes e prevenir perda de informao sempre que se abre um ficheiro tem que se fechalo no fim.

Google yourself!

-Declarao e inicializao do ponteiro:


Para declarar um ponteiro para o ficheiro temos que usar o tipo de variveis FILE (sempre em
maisculas). Para darmos um valor ao ponteiro usa-se a funo fopen para abrir um ficheiro.
FILE *f = fopen(FileName,Mode);
FileName uma string com a localizao do ficheiro. H 2 tipos de localizao, a relativa que
relativa localizao do programa, ou a localizao absoluta (por exemplo
C:\Users\Utilizador\Documents\Outros\css\crashinfo.txt). Convm lembrar que para mostrar
uma \ numa string tem que se usar \\.
O Mode o modo de abertura que pode ser um dos seguintes:

r: read only, apenas l. Se o ficheiro no existir devolve NULL;


w: write only, escrever penas. Recria o ficheiro;
a: append, escreve apenas e no fim do ficheiro. Se o ficheiro no existir criado um
novo;
r+: read/write, escreve e l. Se o ficheiro no existir criado um novo;
w+: read/write, escreve e l. Recria o ficheiro;
a+: read/write, escreve e l. Abre o ficheiro e fica a apontar para o fim, criado um
novo se no existir.

possvel abrir um ficheiro no modo binrio. O modo binrio mais rpido que ficheiros de
texto normais. Para isso basta adicionar um b no fim no modo (por exemplo a+b).

-Escrever
Escrever num ficheiro feito da mesma forma que se escreve na caixa de comandos. Usam-se
as mesmas funes mas com o f antes do nome da funo e tm mais um parmetro, o
ponteiro para o ficheiro (fprintf, fputs, fputc).
Tambem existe a funo fwrite
size_t fwrite(void *ptr, size_t size, size_t count, FILE *f);
Esta funo permite escrever elementos de qualquer tipo no ficheiro.

void *ptr: ponteiro para o elemento que se quer escrever no ficheiro;


size_t size: o tamanho do tipo do elemento que se quer escrever;
size_t count: a quantidade de elementos que para escrever;
FILE *f: ponteiro para o ficheiro que para escrever.
Retorno: nmero de elementos que foram escritos com sucesso

Esta funo bastante utilizada para escrever em ficheiros binrios.

Exemplo:
void main()
{
FILE *f = fopen ("array.bin", "wb");
int arr[] = {1,2,3,4,5,6,7,8,9,10};
fwrite (arr , sizeof(int), sizeof(arr), f);
fclose (f);
}

Esta funo vai criar um ficheiro binrio array.bin e escreve l o array arr.

-Leitura:
A leitura feita da mesma maneira que a leitura da caixa de comandos (fscanf, fgets, fgetc).

semelhana da escrita tambm tem uma funo que vai ler elemento a elemento:
size_t fread(void *ptr, size_t size, size_t count, FILE *f);
Esta funo permite escrever elementos de qualquer tipo no ficheiro.

void *ptr: ponteiro para onde queremos gravar o que lemos no ficheiro;
size_t size: o tamanho do tipo do elemento que se quer ler;
size_t count: a quantidade de elementos que para ler;
FILE *f: ponteiro para o ficheiro que para escrever.
Retorno: nmero de elementos que foram lidos com sucesso

Por exemplo para ler o ficheiro criado no exemplo anterior:

void main ()
{
FILE *f = fopen ("array.bin", "rb");
int arr[10];
fread (arr , sizeof(int), 10, f);
fclose (f);
}

Normalmente usado um ciclo para ir lendo at chegar ao fim. O ltimo caracter de um


ficheiro o caracter EOF. Uma funo que diz se o fim do ficheiro ou no o feof. A funo
fgets l linha a linha e retorna NULL quando j no leu mais nada, ou seja j chegou ao fim.
Usem as funes que vos derem mais jeito.

-Posicionamento:
As vezes preciso voltar atrs no ficheiro ou avanar para o fim e isso possvel atravs das
funes fseek, rewind e ftell. A ftell diz o numero do byte em que est neste momento, o
fseek d para ir para um determinado byte determinando o offset de uma origem
(fseek(FILE*f,long offset,int origem)) Para mais informaes:
http://www.cplusplus.com/reference/cstdio/fseek/

Listas e Pilhas:
Fila/listas e pilhas so uma forma de ter uma base de dados extensa no programa de uma
maneira fcil e organizada e de realizar operaes sobre elas.
So um conjunto de ns (nodos ou o que quiserem) que contm 2 ponteiros, um para o
seguinte n e outro que aponta para a informao desse n. Assim sendo tm sempre pelo
menos 2 estruturas, uma para o n e outro para a informao. (O ponteiro para a informao
no necessrio, a informao pode ficar contida no n, mas mais fcil de perceber assim).
habitual serem criadas 3 estruturas. A primeira contm o nmero de nos de uma lista/fila e
um ponteiro para o incio. As outras 2 so as que foram referidas anteriormente.
As diferenas entre Listas e Pilhas est no prprio nome. Uma pilha como se fosse uma pilha
de qualquer coisa, apenas podes tirar do cimo e por no cimo. Uma Lista podes colocar ou
retirar seja onde for. Uma fila uma mistura dos dois, inseres no incio retiras do fim. Devido a
isso apenas vou explicar as listas visto que o resto so casos particulares deste.
H 2 grandes tipos de listas, as biligadas e as simplesmente ligadas. A diferena est em que
nas biligadas os ns contm ponteiros para o prximo e para o no anterior. E a lista tem um
ponteiro para o incio e fim. til para listas com muitos elementos, mas se forem poucos
torna-se desnecessrio.

-Criao e Declarao:
As listas no so nada mais que estruturas ligadas entre si. Eu costumo usar 3 estruturas, mas
no a nica forma de fazer.
Em primeiro lugar cria-se uma estrutura para guardar a informao. De seguida preciso uma
estrutura n, que ir conter o ponteiro para a informao e outro para o n seguinte
(alternativamente pode-se ter um ponteiro para o n anterior e assim torna-la numa lista
biligada). A 3 estrutura contem um inteiro para guardar o nmero total de ns e um ponteiro
para o incio da lista.
Para declarar um varivel lista usa-se a 3 estrutura (usualmente em ponteiro). Pode-se inicila a NULL e assim dizer que a lista no existe, ou aloca-la dinamicamente, mas ao aloca-la tem
que se por o ponteiro para o inicio a NULL e o inteiro a 0.
Exemplo:

typedef struct
{
char *nome;
int numero;
}ALUNO;
typedef struct no
{
ALUNO *info;
struct no *next; //no se pode usar NO porque o NO ainda no foi
definido como a struct aqui
}NO;
typedef struct
{
NO *inicio;
int nel;
}LISTA;
void main()
{
LISTA *L = NULL;
}

-Pesquisar:
Para passar por todos os ns da lista ir ser necessrio pelo menos uma varivel auxiliar com o
tipo NO. Esta ir receber o ponteiro para o incio. Com um ciclo while verifica-se se existe e
executa o cdigo especificado, se no existir quer dizer que alcanamos o fim da lista e por isso
sai do ciclo.

-Insero de um novo n:
Para introduzir um n primeiro tem que se criar e dar valores a uma varivel ponteiro para a
estrutura com a informao a guardar. De seguida criar um novo n e inserir a informao
anteriormente criada neste.
O valor que se coloca no ponteiro para o prximo vai depender de onde se quer colocar o n
na lista. Se for no fim este ser NULL, mas se for no incio ser um ponteiro para o atual
primeiro da lista.
Mas ambos so um caso particular da insero no meio, por isso para os exemplos iremos criar
uma funo para inserir na lista os ns ordenados pelo nmero.
Exemplo:

NO *InsereLista(LISTA *L, ALUNO *A)


{
NO *novo = (NO *)malloc(sizeof(NO)),//novo n
*ax = L->inicio, //varivel auxiliar para o ciclo
*ant = NULL; //como vamos inserir temos que guardar o no
anterior temporariamente
novo->info = A; //insero da informao
if(!novo) //falta espao
return NULL;
if(!L) // a lista no existe
{
L = (LISTA *)malloc(sizeof(LISTA));
if(!L)
return NULL;
}
while(ax)
{
if(ax->info->numero > A->numero)
{
novo->next = ax;
if(ant)
ant->next = novo;
else // inicio da lista porque o ant NULL
L->inicio = novo;
break; //no me apetece tar a criar uma var auxiliar para
verificar se inseriu...
}
ax = ax->next; //temos que ir para o proximo n
}
if(!ax) //quer dizer que no foi inserido ainda
{
novo->next = NULL;
if(ant)
ant->next = novo;
else // inicio da lista porque o ant NULL
L->inicio = novo;
}
L->nel++;
return novo;
}
void main()
{
LISTA *L = NULL;
ALUNO *A = (ALUNO *)malloc(sizeof(ALUNO));
if(!A)
return;
char nome[150];
printf("Insira o nome do aluno: ");
gets(nome);
A->nome = (char *)malloc(sizeof(char) * (strlen(nome) + 1)); //+1 para
dar espao para o \0
strcpy(A->nome, nome);
printf("Insira o numero do aluno: ");
scanf("%d", &A->numero);
InsereLista(L,A);
LimparLista(L);
}

-Remoo:
Para remover um n da lista mais simples que inserir, basicamente tem que se procurar pelo
identificador do NO a remover e depois fazer os free necessrios. NO fazer free ao next,
apenas ao info. Tambm preciso certificar que o no anterior fica a apontar para o seguinte
do que foi removido!
Exemplo:
void RemoveNO(LISTA *L, int num)
{
if(!L) //lista no existe entao adeus
return;
NO *ax = L->inicio,
*ant = NULL;
while(ax && ax->info->numero <= num) // a lista est ordenada!!
{
if(ax->info->numero == num)
{
if(ant)
ant->next = ax->next;
else L->inicio = ax->next; //se o ant for NULL entao o
inicio muda
free(ax->info->nome); //alocamos o nome
free(ax->info);
free(ax);
L->nel--;
ax = NULL; //sai do ciclo
}
}
}

Hashing:
Basicamente hashing usar arrays para separar informao, normalmente listas por uma
chave (pode por exemplo ser a primeira letra do nome, agrupa todos os que comeam por a
no ndice 0, etc).
bastante simples de usar o hashing, basta substituir o inicio da 3 estrutura de uma lista por
um array de ponteiros para o no. Ou ento criar um array de listas, nem preciso criar uma
nova struct se no quiserem.
O modo de funcionamento igual aos arrays, porque um array, s muda o tipo e o tipo passa
a ser uma lista, portanto apenas misturar a modo de funcionamento dos arrays e listas.

Arvores Binrias:
Pensem numa rvore genealgica de pernas para o ar, mais ou menos parecido.
Arvores outra forma de guardar informao. Tendes o topo e depois cada n tem um
ponteiro para a esquerda e outro para a direita.

Devido ao formato da rvore (direita ou esquerda) o acesso a informao feito de maneira


diferente, pois no linear como as listas. Por isso mais fcil de usar recursividade aqui.
Nas estruturas a nica coisa que muda o ponteiro para o seguinte, passa 2 ponteiros, 1 para
a esquerda e outro par a direita. Devido a este formato muito mais fcil de organizar dados.
Por exemplo, se o nmero do que quero inserir menor que o no atual, insere na esquerda, se
for maior vai para a direita. E faz isto recursivamente at encontrar um NULL que onde
insere a informao.
Exemplos de listagem ordenada recursiva:
typedef struct
{
char *nome;
int numero;
}ALUNO;
typedef struct no
{
ALUNO *info;
struct no *esq;
struct no *dir;
}FOLHA;
typedef struct
{
FOLHA *inicio;
int nel;
}ARVORE;
//listagem ordenada recursiva:
void ListaRec(FOLHA *F)
{
if(!F)
return;
ListaRec(F->esq);
printf("Nome:%s Numero:%d\n", F->info->nome,F->info->numero);
ListaRec(F->dir);
}
void ListaR(ARVORE *A)
{
if(A)
ListaRec(A->inicio);
}

FATOS (LOL) (POUCO) INTERESSANTES:


As arvores no tm que ser binrias, por exemplo, pensem que cada n tenham um array de
listas que por sua vez tem arrays de nos Basicamente assim que o SO est organizado, tem
a compartio C como base e depois varias pastas que tem pastas e pastas e pastas e ficheiros
e merda

Programao modular:
Se usarmos apenas um ficheiro para um programa iremos ter um ficheiro enorme com
demasiadas linhas de cdigo e mal organizado, para combater este problema um programa

pode conter vrios ficheiros .cpp com funes. Assim o cdigo pode ficar separado em vrios
ficheiros, melhor organizado e mais fcil de procurar o que for preciso.
Porm os ficheiros no esto diretamente ligados e por isso os tipos e variveis definidos num
ficheiro no vo estar no outro.

-extern
extern uma palavra reservada que vai buscar algo a um dos ficheiros do projeto. Por
exemplo, criamos uma funo no ficheiro funes.cpp e queremos usar essa funo no
ficheiro main.cpp, para isso no ficheiro main.cpp teremos que escrever extern headerfuno;.
Substitui-se o headerfuno pelo header da funo aquando declarada pelo outro ficheiro.
No preciso especificar em que ficheiro est, ele vai buscar automaticamente. Tambm pode
ser usado para variveis.

-Headers:
Header files so ficheiros como includes. So bastante uteis para quando se tm vrios
ficheiros que usam as mesmas estruturas e tipos. Assim possvel criar as estruturas, tipos,
defines e usar as mesmas includes num s ficheiro e usa-lo nos que forem necessrios.
Para incluir um ficheiro header criado por ns usando #include NomeHeader.h.
Tambm possvel usar um ficheiro .h para no usar extern. Para isso basta escrever os headers
das funes no .h e depois criar o corpo da funo num ficheiro que inclua este header.

-Ponteiros para funes:


possvel usar ponteiros para funes como parmetros de entrada de outras funes.
Por exemplo queremos uma funo que possa fazer o mesmo cdigo para vrias outras
funes mas s para uma especifica de cada vez.
Exemplo:
int multiplicacao(int x, int y)
{
return x*y;
}
int soma(int x, int y)
{
return x+y;
}
void calculo(int (*func)(int,int), int a, int b)
{
printf("%d\n", (*func)(a,b));
}
void main ()
{
calculo(soma,2,3);
calculo(multiplicacao, 2,3);
}

Neste exemplo criamos a funo calculo que o que faz mostrar o resultado retornado por
uma funo que devolve um int e tem como parmetros de entrada 2 int.

-Ponteiro para void


Como j foi referido anteriormente, na parte do malloc, possvel ter funes que devolvam
um tipo qualquer de dados e assim sendo tambm possvel criar variveis que possam ser de
qualquer tipo.
Assim, por exemplo, para criar listas de vrias coisas diferentes podemos ter a estrutura lista e
n que do para todos, basta por o tipo de dados do ponteiro info do n como void *.
O void * diz que vai ser um ponteiro e sem um tipo especfico definido podem ser receber
qualquer tipo de variveis, tendo assim uma funo/varivel genrica.
Exemplo:

typedef struct
{
int num;
char nome[120];
}ALUNO;
typedef struct
{
int nalunos;
char nome[120];
}DISCIPLINA;
typedef struct no
{
void *info;
struct no *prox;
}NO;
typedef struct
{
NO *inicio;
int nel;
}LISTA;
void CriarAlunos(LISTA *L)
{
if(!L)
return;
ALUNO *A = (ALUNO *)malloc(sizeof(ALUNO));
if(!A)
return;
strcpy(A->nome,"Kimossab");
A->num=14180;
NO *novo = (NO *)malloc(sizeof(NO));
novo->info = A;
novo->prox = NULL;
L->inicio = novo;
L->nel = 1;
}
void CriarDisci(LISTA *L)
{
if(!L)
return;
DISCIPLINA *A = (DISCIPLINA *)malloc(sizeof(DISCIPLINA));
if(!A)
return;
strcpy(A->nome,"IP");
A->nalunos=20;
NO *novo = (NO *)malloc(sizeof(NO));
novo->info = A;
novo->prox = NULL;
L->inicio = novo;
L->nel = 1;
}

Aqui est um exemplo de como com 4 estruturas se pode criar 2 listas diferentes e inserir l
valores. Notar como o novo->info aceita tanto DISCIPLINA como ALUNO.

Macros:
As Macros so pores de cdigo que so substitudas pelo pr-processador antes de o
compilador passar pelo cdigo.
O #define que j foi falado usado para criar macros, no cdigo C mas pode ser usado em
qualquer linha e indica ao pr-processador que a partir daquela linha uma expresso que l
colocarmos ir ser substituda por outra expresso que l colocarmos.
Normalmente os macros so conhecidos no pela definio de constantes como foi falado mas
sim de funes.
Exemplo:
#define Multi(x,y) (x*y)
A primeira parte do define funciona como uma funo, procura a palavra Multi que tenha 2
parmetros entre parenteses (independentemente do tipo) e depois vai substituir toda essa
expresso pela 2 parte do define, por exemplo:
int x = Multi(2,3); // o que o pr processador faz isto: int x=(2*3)
Neste caso esta funo no retorna um valor mas substituda pelo que est a frente.
Para poder escrever em mais do que uma linha, no fim da linha coloca-se \.

-#
Num macro o smbolo # um smbolo que diz que coloca um dos parmetros entre aspas.
Deste modo convertendo uma expresso no seu equivalente em string.
Exemplo:
#define getstring(x) #x
void main()
{
printf(getstring(Sem aspas ( "" )\n));
}

-##
## um concatenador, ou seja junta duas expresses, a da esquerda com a da direita. Lembrar
que os macros so expresses e no valores.

Exemplo:
#define getvar(x) var ## x
void main()
{
int var1=2,var2=3,var3=4,var4=5;
printf("%d", getvar(3));
}

No output ir mostrar o nmero 4.

-Pr definies
J existem macros pr definidas, entre algumas esto:

__FUNCTION__ : substituda pelo nome da funo atual


__TIME__ : substituda por uma string com o tempo atual hh:mm:ss
__DATE__ : substituda por uma string com a data atual Mmmm dd yyyy

-#ifdef
possvel verificar se algum macro est j est definido. Isto bastante til para evitar que um
header file seja includo mais do que uma vez e assim prevenir erros como o de criar estruturas
j criadas. Tambm til para executar cdigos diferentes dependendo do sistema que for
(por exemplo em Linux algumas funes tm que ser diferentes por o sistema no as suportar
e as barras na direo de ficheiros so diferentes para Linux e Windows (\ e /))
Para verificar se um macro j existe usa-se o #ifdef ou #if defined e colocar o macro que se
dejesa verificar a frente. Pode-se usar tambm #elseif e #else. Para terminar um bloco #if
preciso usar o #endif.
A negao do #ifdef ou #if defined #ifndef e #if !defined respetivamente.
Exemplos:
//windows
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
&& !defined(__CYGWIN__)
#include <direct.h>
#define GetCurrentDir _getcwd
#define SetCurrentDir _chdir
#else //unix
#include <unistd.h>
#define GetCurrentDir getcwd
#define SetCurrentDir chdir
#endif
#ifndef MyLib_h
#define MyLib_h
//INCLUDES
//typdef
//structs
//headers de funoes
#endif

Este ultimo vai verificar se um header file j foi includo e assim prevenindo que seja includo
outra vez.

Funes bastante usadas:

sscanf: faz o scanf mas a uma string, o primeiro parmetro o da string qual
queremos fazer o scan.
sprintf: faz o printf a uma string, assim deste modo podemos inserir dados numa string
facilmente. O primeiro parmetro o da string a qual ir ficar com o resultado.
setlocale: esta funo que vem na libraria locale.h bastante til porque ir definir o
locale do programa e assim permitir a utilizao de caracteres especiais e das normas
conforme a localizao definida. O primeiro parmetro para escolher o que parte do
sistema queremos definir o locale (tudo, tempo, valores numricos, valores
monetrios, etc.). O segundo parmetro o locale que queremos, para usar o do
sistema basta colocar . Mais informao:
http://www.cplusplus.com/reference/clocale/setlocale/ e
https://msdn.microsoft.com/en-us/library/cdax410z.aspx
fflush: o fflush fora a que bytes que ainda estejam num stream (podem ser ficheiros)
sejam colocados e limpa o stream, deste modo forando a que mensagens sejam
mostradas ou guardadas limpa o stream para receber mais informao (bastante
usado antes de um gets para limpar o stdin (standard input) com fflush(stdin))
strcmp e stricmp: compara duas strings, a primeira case sensitive, a segunda no. Se
a primeira string for menor devolve -1 se forem iguais devolve 0 se for maior devolve 1
rand(): includo no include stdlib.h uma funo para calcular um nmero pseudoaleatrio. Para poder obter um nmero aleatrio entre 0 e x basta fazer o resto da
diviso inteira (%) da funo rand() por x+1. Exemplo: numero aleatrio de 0 a 9:
rand() %10.

Cdigos teis:
Alguns cdigos que podem ser teis.

-Aceitar apenas nmeros:


Um problema recorrente ao fazer um scanf o programa crashar ou no dar corretamente por
inserir caracteres quando tem que se inserir um numero. Para prevenir este erro normalmente
pede-se uma string e depois faz-se o sscanf ou algo do gnero. Porm no necessrio.
Com um ciclo while e um scanf possvel no atribuir caracteres a uma varivel numrica,
seguindo a seguinte lgica: enquanto o scanf no atribuir valores a 1 varivel mostrar erro.
Exemplo:
void main()
{
int x;
printf("Insira um numero positivo:");
while(scanf("%d",&x) < 1 || x < 0)
{
printf("Apenas numeros positivos!\n");
fflush(stdin);
}
}

necessrio fazer um flush ao stdin porque o enter fica no buffer do teclado e depois est
sempre a l-lo.

Debug:
ESTE CAPITULO FOI FEITO BASEADO NO VISUAL STUDIO 2013. TAMBEM FUNCIONA PARA
OUTRAS VERSES DO VS, MAS PARA OUTROS COMPILADORES PODEM MUDAR ALGUMAS
COISAS, MAS A LGICA A MESMA.
Muitas vezes o cdigo no faz o que queremos ou simplesmente o programa crasha e ns no
sabemos porqu. No modo debug tudo isto pode ser facilmente solucionado.
Para entrar no debug pressionem F5 e o cdigo ser compilado e depois executado no modo
debug.

-Crash:
Quando ocorre um crash no programa no modo debug normalmente aparece uma mensagem
de erro do gnero:

A maior parte das vezes que esta message box aparece porque tentmos aceder a um
ponteiro que est a NULL, mas nem sempre o caso. Nesta situao pode-se ver que o erro diz
que tentou aceder memria na localizao 0x00000000, por isso neste caso foi mesmo por
causa de um NULL. Mas apenas isto no nos diz onde ocorreu.
Pressionem Break e no cdigo poderam ver a linha onde ocorreu o erro assinalada com uma
setinha:

Neste caso fcil de perceber o que correu mal. A varivel L est a NULL. Mas isso nem
sempre fcil de perceber no meio de muitas linhas e funes, por isso h outras duas
ferramentas importantes no debug no Visual Studio, o break points e a janela Locals.

-Locals:
A melhor ferramenta que podem ter no debug. Para a ligarem durante um debug podem ir na
barra de tarefas a Debug > Windows > Locals ou ento ALT+4.
Esta janelas mostra as variveis e os valores destas naquele momento e assim tornando-se
ainda mais fcil de perceber o que se pode passar de errado ao verificar os valores.

Como se pode ver esta janela d o nome da varivel, o seu valor e o seu tipo. Neste casp est
confirmado que o valor de L NULL e isso foi o que fez o programa crashar.

-Break Points:
Por vezes o programa no crasha mas o cdigo no faz o que pensvamos que iria fazer e
portanto existem erros lgicos no programa. Por isso s vezes d jeito saber em que partes do
programa que o cdigo passa, ou saber os valores das variveis em certas linhas do cdigo,
para isso podemos usar break points.
No modo de debug quando o programa passa por uma linha que tenha um break point este
para nessa linha at o mandarmos seguir.
Para colocar um break point apenas temos que carregar no lado esquerdo da linha que
queremos que tenha um break:

O ponto a vermelho assinala o break. A setinha a amarelo indica a linha onde o programa est
parado.

-Mensagens de debug:
Para outros IDEs onde isto ou algumas coisas no sejam possveis uma boa maneira de saber o
que se vai passando no cdigo com mensagens de debug. Fazer uns printf para mostrar os
valores de variveis ou saber se o cdigo passou por uma seco que no devia ou coisas do
gnero. Desse modo tambm fcil de saber o que se passa de errado com um cdigo e assim
corrigi-lo.

Vous aimerez peut-être aussi