Introdução

Primeiro Programa
main(){ /* função obrigatória */ printf("oi"); }
● ●

A Forma Geral de um Programa
declarações das variáveis globais declarações dos protótipos das funções tipo-devolvido main (lista-de-parâmetros){ sequência-de-comandos; } tipo-devolvido f1 (lista-de-parâmetros){ sequência-de-comandos; } tipo-devolvido f2 (lista-de-parâmetros){ sequência-de-comandos; } ... tipo-devolvido fn (lista-de-parâmetros){ sequência-de-comandos; } Obs.: f1() até fn() representam as funções definidas pelo usuário.

● ● ●

Criada em 1972 por Dennis Ritchie no centro de Pesquisas da Bell Laboratories. Existem várias versões de compiladores C oferecidas por várias empresas. O C é mais utilizada para escrever compiladores, bancos de dados, editores de texto, etc. Segue quase todos os conceitos da PE (programação estruturada). Linguagem de Médio Nível. Possui recursos de baixo nível. Gera código eficiente

● ●

Um programa em C consiste de um ou várias funções. A única função que necessariamente precisa estar presente é a main(). É a primeira função a ser chamada quando a execução de um programa começa. As chaves indicam o início e término de um bloco de comandos. Toda isntrução deve ser finalizada com um ponto-e-vírgula. printf() é uma das funções da linguagem C, que detalharemos adiante.

Tipos Básicos de Dados
● ● ● ● ●

Declaração de Variáveis
main(){ int idade; idade = 30; printf(“A idade é %d\n”, idade); }

Escopo de Variáveis – Variáveis Locais

Caractere (char) Inteiro (int) Ponto flutuante (float) Ponto flutuante de precisão dupla Sem valor (void)

(double)

São declaradas dentro de uma função e seu escopo é o bloco de código onde foram declaradas. Ocupam espaço na memória somente durante a execução do bloco de código a que pertence.

As duas primeiras instruções poderiam ser substituídas por: int idade = 30; C é case sensitive, ou seja, as letras maiúsculas diferem das minúsculas. Em C pode-se declarar variáveis em qualquer parte do programa.

void f (){ int t scanf(“%d”,&t); if (t ==1){ char s[80]; printf(“entre com o nome: “); gets(s); /* faz alguma coisa... */ } } ● A variável t pode ser referenciada em qualquer ponto do bloco de código da função f(). ● A variável s só pode ser referenciada dentro do bloco de código em que fora declarada, ou seja, dentro do comando if.

Escopo de Variáveis – Parâmetros Formais

Escopo de Variáveis – Variáveis Globais

Operadores Aritméticos
● ● ● ● ● ● ● ●

Se uma função usa argumentos, ela deve declarar variáveis que receberão os valores dos argumentos. Essas variáveis são denominadas parâmetros formais da função. Possuem o comportamento como qualquer outra variável local dentro da função a que pertence. Deve ser declarada após o nome da função dentro dos parênteses.

● ● ●

Soma( int x, int y){ ... }

São reconhecidas pelo programa inteiro e podem ser referenciadas em qualquer ponto do código. Ocupam espaço na memória durante toda a execução do programa. Devem ser declaradas fora de qualquer função. Um dos objetivos do programador é a modularização, ou seja, fazer com que o programa seja dividido em módulos com funções específicas. Conseguimos este objetivo através do uso de variáveis locais e funções. Portanto devemos evitar o uso de variáveis globais devido a dependência criada entre os módulos. Qual função abaixo é mais adequada? Porque?

Atribuição Multiplicação Divisão Adição Subtração Módulo (Resto) Incremento de 1 Decremento de 1

= * / + % ++ --

● ●

soma(int x, int y){ return(x+y); } int x,y; soma(){ return(x+y); }

Operador pré-fixado: A variável é incrementada antes de seu valor ser usado. Exemplo: ++n Operadro pós-fixado: A variável é incrementada depois de seu valor ser usado. Exemplo: n++ i += 2 i *= y +1 i /= 2 i %= 2 i -= 2 equivale a equivale a equivale a equivale a equivale a i=i+2 i = i * (y + 1) i=i /2 i=i%2 i=i–2

● ● ● ● ●

Operadores Lógicos
● ● ●

Operador Vírgula

A Função printf()
● ●

&& || !

e ou negação

É usado para encadear diversas expressões. Exemplo: x = (y=3,y+1)

Sintaxe: printf(“string de controle”, lista de argumentos); Exemplo: printf(“A idade é %d\n”, idade); O primeiro argumento contém caracteres e códigos de formatação: % + letra, conforme abaixo:
– – – – – –

● ●

Exp1 && Exp2: O resultado será verdadeiro se as duas expressões forem verdadeiras. Exp1 || Exp2: O resultado sera verdadeiro se pelo menos uma expressão for verdadeira. !Exp1: O resultado sera verdadeiro se a Exp1 for falsa e viceversa.

Primeiro atribui o valor 3 a y e, em seguida, atribui o valor 4 a x.

Qual a saída produzida pela instrução destacada abaixo?

/* virgula.cpp */ #include <stdio.h> #include <conio.h> main(){ int x,y; x = (y=3,y+1,y*10); printf("%d",x); getch(); }

%c caractere simples %d decimal %f ponto flutuante %s cadeia de caracteres %u decimal sem sinal %e notação científica

● ●

● ●

O segundo argumento apresenta o valor a ser exibido Deve haver tantos argumentos após a string de controle quantos forem os códigos de formatação. \n é um código de formatação especial que força a mudança de linha. \t permite realizar tabulação.

Exercício
Qual a saída produzida pelo programa abaixo? /*tabulacao.cpp*/ #include <stdio.h> #include <conio.h> main(){ printf("\ncodigo\tquantidade\tpreco"); printf("\n1\t250\t\t3,55"); printf("\n2\t10\t\t8,00"); getch(); }

A Função scanf()

A Função getche() e getch()

Permite a leitura de dados formatados do teclado, após pressionar Enter. Sintaxe: scanf (“string de controle”, lista-argumentos); Exemplo: printf("Digite a distancia:"); scanf("%d",&centimetro); Os argumentos de scanf devem ser endereços de varíaveis, ou seja, o nome da variável precedido pelo símbolo &. Um endereço é inteiro sem sinal, portanto para mostrar o endereço de uma variável, seria assim:
printf("centimetro esta no endereco %u\n",&centimetro);

A Funcao getche(): Lê e retorna um caracter do teclado sem esperar Enter e permite que o mesmo seja impresso na tela. A Funcao getch(): Lê e retorna um caracter do teclado sem esperar Enter e não permite que o mesmo seja impresso na tela. Protótipos:

int getch(void) int getche(void)

Comandos de Repetição - for
Sintaxe: for (inicialização; condição; incremento){ instruções; }

Comandos de Repetição - for

Comandos de Repetição - for

O programa a seguir permite que o usuário escreva na tela até que tecle x.

Variações do Comando For:

Exemplo: for (int i=1; i <10; i++){ printf("%d\n",i); }
● ●

#include <stdio.h> #include <conio.h> main(){ char c; printf("\nDigite uma frase. Ao terminar tecle x\n"); for (c = getche(); c != 'x';c = getche()){ } } A instrução for do programa anterior poderia ser assim: for (; (c = getche()) != 'x';)
● ●

for (x=0, y=0; x+y<10; ++x) ... }

Podemos utilizar a vírgula para permitir que duas ou mais variáveis controlem a repetição.

● ●

A inicialização é uma instrução de atribuição e é sempre executada uma única vez antes do comando ser iniciado. A condição é avaliada a cada repetição. Se for falsa a repetição é finalizada. O incremento define a maneira como a variável de controle será alterada a cada repetição. Nenhuma das três definições são obrigatórias. Exemplo:

Execute o programa anterior e substitua a função getche() por getch() e veja a diferença. Se desejar interromper uma repetição use o comando break.

for(;;) { printf("loop infinito\n"); }

Exercícios

Comandos de Repetição – while e do...while

Exercícios

Codificar um programa que mostre para o usuário a mensagem: “Você está preso, para sair tecle x”, para qualquer tecla pressionada. A mensagem só não será mostrada quando o usuário teclar x e consequentemente o programa deverá ser finalizado. (break.cpp) Codificar um programa que solicite ao usuário dois caracteres em ordem alfabética crescente e imprima o número de caracteres que estão entre eles. (qtletras.cpp)

Sintaxe:

while (condicao){ instrucoes; } do{ instrucoes; } while (condicao);

Codificar um programa que calcule a quantidade de caracteres digitados pelo usuário. O programa deverá solicitar a digitação de uma frase e ser finalizado quando o usuário teclar Enter. (qtcaracteres.cpp) Escreva um programa que cause uma pausa até que o usuário digite a letra 'A'. (pausaatea.cpp) Faça um programa que solicite caracteres ao usuário e imprima seus códigos decimais. O programa deve terminar quando o usuário pressionar a tecla ESC. (codigodecimais.cpp)

As instruções serão executadas enquanto a condição for verdadeira.

Exercícios

Comando Condicional - if

Exercícios

Construa o seguinte jogo: O computador sorteia uma letra e o usuário deverá adivinhá-la. Quando o usuário acertar, o jogo deverá mostrar o número de tentativas realizadas e permitir ao usuário jogar mais uma vez ou finalizar o jogo. (qualletra.cpp) Dica: A função rand() retorna um inteiro aleatório entre 0 e 32.767. Para sortear um número entre 0 e 25 faça: rand() % 26 Para sortear uma letra entre a e z faça: char x = rand() % 26 + 'a' Se rand() % 26 resultar em 0, x receberá o caractere a. Se rand() % 26 resultar em 1, x receberá o caractere b. Se rand() % 26 resultar em 25, x receberá o caractere z.

Sintaxe:

if (condicao){ instrucoes; }else{ instrucoes; }

Codificar um programa capaz de verificar se uma divisão de a por b poderá ser realizada. Lembre-se que o denominador (b) não pode ser zero. Não utilize a expressão if b > 0. (divzero.cpp) Codificar um programa para calcular a quantidade de algarismos e caracteres digitados pelo usuário. (qtalgacaracteres.cpp)

A cláusula else é opcional. Em uma instrução if você não fica restrito a expressões envolvendo os operadores lógicos e relacionais. O programa simplesmente precisa chegar a um valor zero (falso) e não zero(verdadeiro).

● ● ●

Exercícios

Exercícios

Comando Condicional - switch

Codificar um programa que conte o número de palavras de uma frase informada pelo usuário. (contapalavras.cpp). Dicas:

1. Para ler uma string do teclado use a função gets(): printf("\nDigite uma frase: "); gets(frase); Ao utilizar gets() você deve incluir a instrução: #include <string.h> 2. A variavel que receberá a string deverá ser um vetor e declarada da seguinte forma: char frase[30];

Codificar um programa que mostre os caracteres digitados pelo usuário na tela. A tecla Enter deve ser usada para configurar se os caracteres devem ser mostrados em maiúsculas ou minúsculas. A tecla Esc servirá para finalizar o programa. (maiusculasminusculas.cpp) Dicas: – islower(c): Retorna um número diferente de zero se c é uma letra minúscula, e 0 caso contrário. – isupper(c): Retorna um número diferente de zero se c é uma letra maiúscula, e 0 caso contrário. – toupper(c): Retorna o equivalente maiúsculo de c se c é uma letra, caso contrário, c é devolvido sem alteração. – tolower(c): Retorna o equivalente minúsculo de c se c é uma letra, caso contrário, c é devolvido sem alteração. – Inclua: #include <ctype.h>

Sintaxe:

switch (expressao inteira ou caracter) { case constante1: instrucoes; case constante2: instrucoes; ... default: instrucoes; }

● ●

● ●

Cada case pode ter várias instruções. Estas instruções não devem estar entre chaves. Se um caso for igual ao valor da expressão a execução comeca nele. O comando break causa a saida do comando switch. Se nao existir um comando break seguindo as instruções de um caso, o programa segue executando as instruções dos casos seguintes. Se nenhum caso for satisfeito a execução comeca no default. O cláusula default é opcional.

Pré-processador C

A Diretiva #define
● ●

A Diretiva #define

O pré-processador C é um programa que examina o programa-fonte em C e executa certas modificações nele, baseado em instruções chamadas diretivas. É executado compilação. automaticamente antes da

Substitui determinados códigos pré-definidos pelo usuário. Sintaxe: #define nome expressao. Onde nome é o símbolo a ser trocado e expressao é qualquer expressão. O pré-compilador substitui todas as ocorrências de nome no codigo fonte pela expressao fornecida. Não uitlize ponto-e-virgula no comando #define. Se for utilizado, o pre-compilador incluira o pornto-e-virgula na substituição. O comando pode continuar em mais de uma linha utilizando-se a barra invertida (\) para indicar a continuação na linha de baixo.

Se desejarmos usar a palavra VERDADEIRO para o valor 1 e a palavra FALSO para o valor 0, devemos declarar:

#define VERDADEIRO 1 #define FALSO 0

Isto faz com que o compilador substitua por 1 ou 0 toda vez que encontrar VERDADEIRO ou FALSO no seu arquivo fonte. Por exemplo, a instrução abaixo mostra 0, 1 e 2 na tela:

printf((“%d %d %d”, FALSE, TRUE, TRUE + 1);

#define tx 1.25 ● No exemplo acima definimos tx como 1.25. isto significa que em todas as ocorrências do programa, tx sera trocada por 1.25.

Qual a saída produzida pela instrução em destaque abaixo:

#define MSG "Mensagem Padrão !!!!!" ... printf(MSG);

A Diretiva #define com argumentos (macro)
● ● ●

Exercícios

Matrizes
● ●

Uma diretiva #define com argumentos é chamada de macro. Macro é semelhante a uma função. Sintaxe: #define nome(arg1,arg2,...) expressão Exemplo:

Quais as saídas do programa abaixo:

/* macro.cpp */ #define abs1(a) (a)<0 ? -(a) : (a) #define abs2(a) a<0 ? -a : a #include <stdio.h> #include <conio.h> main(){ printf("Valor absoluto de -1 = %d", abs1(-1)); printf("\nValor absoluto de 1 = %d", abs1(1)); printf("\nValor absoluto de 10-20 = %d", abs1(10-20)); printf("\nValor absoluto de -1 = %d", abs2(-1)); printf("\nValor absoluto de 1 = %d", abs2(1)); printf("\nValor absoluto de 10-20 = %d", abs2(10-20)); getch(); }

/* macropegaproximo.cpp */ #define pega_proximo(x) x+1 #include <stdio.h> #include <conio.h> main(){ printf("\nProximo no. após 1 = %d", pega_proximo(1)); getch(); }

Matrizes (vetores = variáveis indexadas = array) É uma coleção de variáveis do mesmo tipo que é referenciada por um nome comum. Um elemento específico da matriz é acessado por meio de um índice. Uma matriz ocupa posições contíguas da memória. O endereço mais baixo corresponde ao primeiro elemento e mais alto ao último. Em C, toda matriz tem 0 como o índice do seu primeiro elemento. Matrizes podem ter uma ou várias dimensões.

Exercícios: Codificar um programa para calcular a area de um circulo. Utilize a diretiva #define para guardar o valor de PI e para o cálculo da área. (diretivadefine.cpp)

Declaração de Matriz Unidimensional
● ● ●

Exercícios

Limites da Matriz

Sintaxe: tipo nome-variável[tamanho] Exemplo: double a[7]; No exemplo acima é declarada um matriz de nome a com 7 elementos do tipo double.

Preencher uma matriz de 10 elementos inteiros de forma que cada elemento receba o dobro da posição correspondente.

/* preenchematrizdobro.cpp */ #define MAX 10 #include <stdio.h> #include <conio.h> main(){ int n[MAX]; for (int i=0; i < MAX; i++){ n[i]=i*i; } for (int i=0; i < MAX; i++){ printf("\n%d",n[i]); } getch(); }

A linguagem C não realiza verificação de limites em matrizes. Se durante uma operação o limite for transposto, acarretará resultados imprevisíveis e nenhuma mensagem de erro do compilador avisará o que está ocorrendo. O programador tem a responsabilidade de providenciar a verificação dos limites.

Strings
● ●

Funções de Manipulação de Strings
● ● ● ●

Em C não existe o tipo string. Em C uma string é definida como uma matriz de caracteres que é terminada com um nulo (###BOT_TEXT###). Por esta razão, você precisa declarar matrizes de caracteres como sendo um caractere mais longo que a maior string que elas devem guardar. Você não precisa adicionar o nulo no final das constantes string manualmente. O compilador C faz isso por você automaticamente.Por exemplo: para guardar uma string de 10 caracteres, devemos escrever: char str[11]; Com isso reservamos espaço para o nulo no final da string. Embora C não tenha o tipo de dado string, ela permite constantes de strings. Exemplo: “ctu”

strcpy(s1,s2): copia s2 em s1. strcat(s1,s2): concatena s2 ao final de s1. strlen(s1): retorna o tamanho de s1. strcmp(s1,s2): retorna 0 se s1=s2, numero negativo se se s1<s2 e numero positivo se s1>s2. strchr(s1,ch): retorna um ponteiro para a 1a. ocorrência de ch em s1. strstr(s1,s2) retorna um ponteiro para a 1a. ocorrência de s2 em s1. Necessitam da instrução: #include <string.h>

Exercícios

Se você rodar o programa abaixo e digitar as strings “alo” e “alo”, qual será a saída produzida?

/* funcoesparastring.cpp */ #include <stdio.h> #include <string.h> #include <conio.h> main(){ char s1[80], s2[80]; gets(s1); gets(s2); printf("comprimentos: %d %d\n", strlen(s1), strlen(s2)); if (!strcmp(s1,s2)){ printf("As strings são iguais\n"); } strcat(s1,s2); printf("%s\n",s1); strcpy(s1,"Isso e um teste.\n"); printf(s1); if (strchr("alo",'o')){printf("o esta em alo\n");} if (strstr("alo aqui","alo")){printf("alo encontrado\n");} getch(); }

Exercícios
/* funcoesparastring.cpp */ #include <stdio.h> #include <string.h> #include <conio.h> main(){ char s1[80], s2[80]; gets(s1); gets(s2); printf("comprimentos: %d %d\n", strlen(s1), strlen(s2)); if (!strcmp(s1,s2)){ printf("As strings são iguais\n"); } strcat(s1,s2); printf("%s\n",s1); strcpy(s1,"Isso e um teste.\n"); printf(s1); if (strchr("alo",'o')){printf("o esta em alo\n");} if (strstr("alo aqui","alo")){printf("alo encontrado\n");} getch(); } respostas: ● Comprimetos: 33 ● As string são iguais ● aloalo ● Ísso é um teste ● o está em alo ● alo encontrado

Exercícios

Matrizes Bidimensionais
● ●

Codificar um programa capaz de verificar se duas strings são iguais. (comparastrings.cpp) Faça um programa que obtenha um número do teclado e mostre na tela os números compreendidos entre ele (inclusive) e zero (exclusive), conforme exemplo abaixo (imprimetrianguloretangulo.cpp):
Número: 8 8, 7, 6, 5, 7, 6, 5, 4, 6, 5, 4, 3, 5, 4, 3, 2, 4, 3, 2, 1 3, 2, 1 2, 1 1 4, 3, 2, 1 3, 2, 1 2, 1 1

● ●

C suporta matrizes multidimensionais. A forma mais simples de matriz multidimensional é a matriz bidimensional (uma matriz de matrizes unidimensionais) Declaração: int notas [45] [4]; Para acessar a 31o Linha (ou linha de número 30) e 3o coluna (ou coluna de número 2): notas[30][2];

Matrizes de Strings
● ●

Inicialização de Matrizes
● ● ●

Inicializando uma Matriz Multidimensional
int quadrados[10][2] = { 1,1, 2,4, 3,9, 4,16, 5,25, 6,36, 7,49, 8,64, 9,81, 10,100 };

Usa-se uma matriz bidimensional de caracteres. O tamanho do índice esquerdo indica o número de strings. O tamanho do índice direito especifica o comprimento máximo de cada string. Declaração de uma matriz de 30 strings, cada qual com um comprimento máximo de 79 caracteres: char str [30][80]; Para acessar uma string individual da matriz anterior, específicamos apenas o índice esquerdo: a instrução gets(str[2]) acessa a terceira string. Para acessar um caractere de uma string individual da matriz anterior, específicamos da seguinte forma: a instrução printf(“%c”,str[2][5]) mostra o sexto caractere da terceira string.

C permite inicializarmos uma matriz no momento da declaração. Exemplo: int i[10]={1,2,3,4,5,6,7,8,9,10} Isto siginifica que i[0] terá o valor 1 e i[9] terá o valor 10. Matrizes de caracteres que contêm strings permitem uma inicialização abreviada:
char str[30] = “Colegio Tecnico Universitario”;

Isso é o mesmo que:
Char str[30] = {'C','o','l','e',...,'o','###BOT_TEXT###'};

Lembre-se de adicionar o terminador nulo. Só quando se trata de constante string é que o compilador insere o terminador nulo automaticamente. Por isso que dimensionamos a matriz str com tamanho 30 apesar de Colegio Tecnico Universitario só possuir 29 caracteres.

Matriz Não Dimensionada

Matriz Não Dimensionada
/* matriznaodimensionada */ #include <conio.h> #include <stdio.h> main(){ char str1[30] = "Colegio Tecnico Universitario"; char str2[] = "Colegio Tecnico Universitario"; printf("\nTamanho de str1 (%s) e %d",str1,sizeof(str1)); printf("\nTamanho de str2 (%s) e %d",str2,sizeof(str2)); getch(); }

Capacidade e Tamanho de Variáveis

Se, em um comando de inicialização de matriz, o tamanho da matriz não é especificado, o compilador C cria uma matriz grande o bastante para conter todos os inicializadores presentes. Isto é chamado de matriz não-dimensionada.

A funcao sizeof() calcula o comprimento em bytes de um tipo de dado. Pode receber como argumento um tipo de dado ou a própria variável.

As saídas do programa acima serão: Tamanho de str1 e 30 Tamanho de str2 e 30

● ●

/* funcaosizeof */ #include <stdio.h> #include <string.h> #include <conio.h> main(){ char mat1[10]; char mat2[] = "Colegio Tecnico Universitario"; printf("mat1 tem capacidade = %d\n",sizeof(mat1)); printf("mat2 tem capacidade = %d\n",sizeof(mat2)); printf("mat2 tem tamanho = %d\n",strlen(mat2)); getch(); }

Saídas:

mat1 tem capacidade = 10 / mat2 tem capacidade = 30 mat2 tem tamanho = 29

Capacidade dos Tipos Básicos
/* tamanhodostipos.cpp */ #include <stdio.h> #include <string.h> #include <conio.h> main(){ char c; int i; float f; double d; char matc[10][20]; int mati1[10]; int mati2[10][20]; printf("c tem comprimento de %d\n",sizeof(c)); printf("i tem comprimento de %d\n",sizeof(i)); printf("f tem comprimento de %d\n",sizeof(f)); printf("d tem comprimento de %d\n",sizeof(d)); printf("matc tem comprimento de %d\n",sizeof(matc)); printf("mati1 tem comprimento de %d\n",sizeof(mati1)); printf("mati2 tem comprimento de %d\n",sizeof(mati2)); printf("Todo int possui comprimento de %d\n",sizeof(int)); getch(); }

Exercícios

Ponteiros
● ● ●

Codificar um programa para ler um nome (máximo de 50 caracteres) e abreviar os nomes do meio. Exemplo: Joaquim José da Silva Xavier, ficaria Joaquim J. d. S. Xavier. (abrevianomes.cpp) Codificar um programa que faça a reserva de lugares em um teatro sendo que:
– – – – – – – –

Um ponteiro é uma variável que contém um endereço de memória. Este endereço é a posição de outra variável na memória. Se uma variável contém o endereço de uma outra, dizemos que a primeira aponta para a segunda.
Endereço Conteúdo na Memória 1000 1003 1001 1002 1003 1004 1005 1006

O teatro tem 10 fileiras de cadeiras (A, B, C, ... J), cada uma com 50 cadeiras. Os lugares são identificados com uma letra (coluna) e um número (fila). Exemplo: A-4, B-23, etc. O programa deverá solicitar do usuário qual lugar ele deseja ocupar. Caso o lugar indicado não esteja vago, o programa deverá avisar ao usuário para que escolha um novo lugar. Caso o lugar indicado esteja vago, este deverá ser reservado ao usuário. Sempre que uma dada fileira (1a., 2a., 3a., etc) estiver totalmente ocupada, o programa deverá informar ao usuário antes que ele efetue a escolha. Ao final de cada reserva o programa deverá indicar o total de lugares ocupados e o total de lugares vagos. O programa finalizará se: ● O usuário teclar Esc ● Não existir mais lugares vagos (reservalugar.cpp)

● ●

● ●

Declaração: tipo_base *nome; Onde tipo_base é qualquer tipo válido em C e nome é o nome da variável ponteiro. O tipo_base define que tipo de variáveis o ponteiro pode apontar. Exemplo: int *p //p aponta para um inteiro

Operadores de Ponteiros
● ●

Exercícios

Exercícios

& *

devolve o endereço na memoria da variável que o segue. devolve o valor da variável localizada no endereço que o segue

Qual a saída produzida pelo trecho de código abaixo:

Qual a saída produzida pelo trecho abaixo?

Para entender melhor: suponha que a variavel contador usa a posicao de memoria 2000 para armazenar seu valor. Tambem assuma que contador tem o valor 100.
/* m e um ponteiro para o tipo int */ /* m recebe o endereco de contador */ /* q recebe o valor que esta no endereco de m */

int *m; m = &contador; q = *m

int destino, fonte, *m; fonte = 10; m = &fonte; destino = *m; printf(“%d”, destino);

int x, *p1, *p2; x = 10; p1 = &x; p2 = p1; printf("%d", p2);

● ●

1a. instrucao: A variavel m não é do tipo int, mas aponta para um valor do tipo int. Após a 2a. Instrução m terá o valor 2000. Após a 3a. Instrução q terá o valor 100.

Resposta: mostra o endereço de x, não seu valor

Exercícios

Problemas com Ponteiros – Parte 1

Problemas com Ponteiros – Parte 2

Quais as saídas produzidas pelo programa abaixo?

Analise o código abaixo:

Analise o código abaixo:

ponteiro2.cpp #include <stdio.h> #include <conio.h> main(){ int a=1, b=2; int *pa, *pb; printf("a=%d b=%d\n",a,b); pa=&a; pb=&b; *pa+=5; *pb+=5; printf("a=%d b=%d\n",a,b); getch(); }

main(){ int x, *p; x = 10; *p=x; }

//o certo seria p = &x

main(){ int x, *p; x = 10; p=x; printf(“%d”,*p); }

O problema do código acima é que estamos atribuindo o valor da variável x para alguma posição da memória desconhecida. Desconhecida porque p nunca recebeu um valor. Quando o seu programa é pequeno a probalidade deste endereço ser seguro, ou seja, que não esteja sendo utilizado, é grande. Contudo, quando o seu programa cresce, a probalidade de p apontar para algo vital aumenta e seu programa pode parar de funcionar. Solução: ter certeza de que um ponteiro está apontando para algo válido antes de usá-lo.

A instrução printf() não imprime o valor de x, que é 10. Imprime algum valor desconhecido porque a instrução em destaque está errada. O certo seria: p=&x;

Aritmética de Ponteiros

Aritmética de Ponteiros

Aritmética de Ponteiros

Existem apenas duas operações aritméticas que podem ser utilizadas com ponteiros: adição e subtração. a = 100; int *p; p=&a p++; p=p+10

Existem apenas duas operações aritméticas que podem ser utilizadas com ponteiros: adição e subtração. (I) a = 100; int *p; p=&a; p++; p=p+10

Vejamos uma comparação entre um ponteiro para int e outro para char.

(I)

char *c = 3000; int *i = 3000;

(II) (III)

Efeito da Instrução I

Efeito da Instrução II p

Efeito da Instrução III p

(II) (III)

Cada vez que um ponteiro é incrementado, ele aponta para a posição de memória do próximo elemento de seu tipo base. O mesmo raciocínio quando decrementado. Vamos analisar as instruções I, II e III: (I) Vamos imaginar que p passe a apontar para o endereço 2000. (II) Partindo do princípio que cada elemento do tipo int ocupa 2 bytes, o próximo elemento do tipo int está na posição 2002, então p passa a conter 2002 e não 2001. (III) Estando p apontando para a posição 2002, ao incremetar 10, p passa a conter 2022.

Endereço Valor na Memória 2000 2001 2002 2003 ... 2022 2023 100

p

● ● ●

Exercicios

Comparação de Ponteiros

Ponteiros e Matrizes

Supondo que a variável a ocupará o endereço 2293572 e que o tipo int ocupa 4 bytes, quais as saídas produzidas pelo trecho abaixo:

Cuidado! O conteúdo das variáveis abaixo são endereços de memória.

/* ponteiro3.cpp */ #include <stdio.h> #include <conio.h> main(){ int a=10,*pa; pa=&a; printf("pa=%d\n",pa); printf("&a=%d\n",&a); printf("*pa=%d\n",*pa); pa++; a++; printf("\npa=%d\n",pa); printf("&a=%d\n",&a); printf("a=%d\n",a); pa=pa+10; printf("\npa=%d\n",pa); getch(); }

/* comparaponteiros*\ #include <stdio.h> #include <conio.h> main(){ int a,b,*p,*q; a=10; b=10; p=&a; q=&b; if (p==q) { printf("Valores iguais.\n"); }else{ printf("valores diferentes.\n"); } getch(); }

Em C, o nome de uma matriz sem índice retorna o endereço inicial da matriz, que é o primeiro elemento. No trecho de código abaixo, p recebe o endereço do 1o. elemento da matriz frase.

char frase[80], *p; p = frase;
P

frase 0 1 ... 79

Diferentes Formas de Acessar uma Matriz

Diferentes Formas de Acessar uma Matriz
/* ponteiro1.cpp */ #include <stdio.h> #include <conio.h> main(){ int mat[]={10, 20, 30,40,50}; /* Se o nome da matriz sozinho é um ponteiro para o 1o. elemento, então *(mat) faz referência ao conteúdo deste endereço. */ for (int i=0; i < 5; i++){ printf("%d\n",*(mat+i)); } getch();

Diferentes Formas de Acessar uma Matriz
/* p receberá o endereço do 1o. elemento, então *(p) faz referência ao conteúdo deste endereço. */ int *p=mat; for (int i=0; i < 5; i++){ printf("%d\n",*(p+i)); } getch(); /* forma tradicional de se referenciar a um matriz. */ for (int i=0; i < 5; i++){ printf("%d\n",mat[i]); } getch();

C fornece dois métodos para acessar os elementos de matrizes: indexação de matrizes. aritmética de ponteiros.

Para acessarmos o 5o. elemento da matriz frase do exemplo anterior usamos uma das formas abaixo:
frase 0 1 2 3 4 ... 79

frase[4] *(p+4) *(frase + 4) p[4]

Diferentes Formas de Acessar uma Matriz
/* Em C qualquer ponteiro pode ser indexado como se fosse uma matriz. */ for (int i=0; i < 5; i++){ printf("%d\n",p[i]); } getch(); }

Exercícios

Matrizes de Ponteiros

Codificar um programa que gere a seguinte matriz: “colegio tecnico universitario”. O programa deverá ter duas funções: uma que mostre todos os elementos da matriz (um de cada vez) utilizando o método de indexação de matrizes e outra que utiliza aritmética de ponteiros. acessavetor.cpp Dica: putchar(): mostra um caractere.

Ponteiros podem ser organizados em matrizes como qualquer outro tipo de dado. A declaração de uma matriz de 10 ponteiros int: int *x[10]; Para atribuir o endereço de uma variável int, chamada num, ao 5o. elemento da matriz de ponteiros: x[4]=&num; Para acessar a mesma posição seria: *x[4]

Matrizes de Ponteiros
/* matrizponteiro.cpp */ #include <stdio.h> #include <conio.h> #include <string.h> main(){ static char *lista[] = { "Monica", "Caroline", "Paulo", "Michelle", "Wanda" }; char nome[20]; printf("Digite um nome: "); gets(nome); int achou=0; for (int i=0; i < 5; i++){ if (strcmp(lista[i],nome) == 0){ achou = 1; } printf("%s\n",lista[i]); } if (!achou){ printf("Nome nao cadastrado!!!"); }else{ printf("Nome presente na lista"); } getch(); }

Funções

Funções

Permitem dividir um programa grande em pequenas partes. Pemitem utilizar partes de programas desenvolvidas por outras pessoas, sem que se tenha acesso ao código-fonte. Um exemplo: você até agora utilizou a função printf() sem conhecer detalhes de sua programação. Devemos utilizar diversas pequenas funções, ao invés de poucas e grandes funções. Vantagens: – Reaproveitamento de código. – Facilita encontrar erros. – Trabalho em equipe.

Sintaxe da Função:

tipo nome_funcao(argumentos){ declaração de variáveis comandos }

Onde: – tipo determina o tipo do valor de retorno (se omitido, é assumido int). – nome representa o nome pelo qual a função será chamada (invocada). – argumentos são informações externas transmitidas para a função (opcional)

Invocando (Chamando) uma Função

Invocando (Chamando) uma Função
/* funcao.cpp */ #include <stdio.h> #include <conio.h> int soma; void total(int x); void mostra(); int triplo(int r); main(){ int cont; for (cont=0; cont < 10; cont++){ total(cont); mostra(); printf("O triplo de %d e %d\n", cont, triplo(cont)); printf("\n", cont, triplo(cont)); } getch(); } void total(int x){ soma+=x; } void mostra(){ printf("Soma atual: %d\n",soma); } int triplo(int r){ return r*r*r; }

Ordem das Funções em um Programa

Todo programa em C é composto de funções. A execução é iniciada pela função main(). Para executar uma função, ela deve ser chamada no corpo de uma outra função, exceto a função main(), que é executada ao iniciar o programa.

Você reparou que no programa anterior as funções foram declaradas primeiro e que só após a função main() é que aparece suas implementações. Se você colocar as implementações das funções antes da função main() não será necessário declará-las.

Argumentos de uma Função
● ●

Argumentos para main()

Argumentos para main()

São utilizados para transmitir informações para a função. Se uma função usa argumentos, ela deve declarar variáveis que aceitem os valores dos argumentos. Estas variáveis são chamadas de parâmetros formais. Os parâmetros formais se comportam como quaisquer outras variáveis locais dentro da função. Uma função pode receber qualquer número de argumentos, inclusive nenhum. No caso de uma função sem argumentos pode-se escrevê-la de duas formas: deixando a lista de argumentos vazia (mantendo-se entretanto os parênteses) ou colocando o tipo void entre parênteses.

Para passar informações para um programa ao executá-lo utilizamos argumento de linha de comando. Argumento de linha de comando é a informação que segue o nome do programa na linha de comando do sistema operacional. Para executar o programa abaixo digitamos: argumentosparamain Jose seguindo de enter.

/* argumentosparamain.cpp */ #include <stdio.h> #include <stdlib.h> #include <conio.h> main(int argc, char *argv[]){ if (argc !=2){ printf("Voce esqueceu de informar o nome.\n"); getch(); exit(1); } printf("Ola %s",argv[1]); getch(); }

int triplo(int r){ return r*r*r; } void mostra(){ //ou void mostra(void) printf("Soma atual: %d\n",soma); }

O primeiro parâmetro (argc) é um inteiro que contém o número de parâmetros da linha de comandos. Ele é sempre pelo menos 1, porque o nome do programa será o primeiro argumento. O segundo argumento (argv) é um ponteiro para uma matriz de ponteiros para caractere. Cada elemento nessa matriz aponta para um argumento da linha de comando. argv[0] aponta para a primeira string, que é sempre o nome do programa, argv[1] aponta para o primeiro argumento e assim por adiante. Os nomes dos argumentos (argv e argc), são arbitrários mas tradicionais.

main(int argc, char *argv[]){ if (argc !=2){ printf("Voce esqueceu de informar o nome.\n"); getch(); exit(1); } printf("Ola %s",argv[1]); getch(); }

Valor de Retorno

Passando Argumentos por Valor

Passando Argumentos por Valor
/* porvalor.cpp */ #include <stdio.h> #include <conio.h> int quadrado(int x); main(){ int t=10; printf("%d %d", quadrado(t), t); getch(); } int quadrado(int x){ x = x * x; return x; }

É o valor que uma função retorna para a função que a chamou. O tipo de retorno é fornecido no cabeçalho da função antes de seu nome.

int triplo(int r){ return r*r*r; }

O comando return faz com seja retornado o valor especificado e faz com com a função termine. Se uma funcao não retorna nada, seu tipo de retorno deve ser definido como void.

Copia o valor de um argumento no parâmetro formal da função. Assim alterações no parâmetro formal da função não tem nenhum efeito nos argumentos usados na chamada da função.

void mostra(){ printf("Soma atual: %d\n",soma); }

O comando return pode ser utilizado numa função com tipo de retorno void. Neste caso, o comando nao deve retornar nenhum valor: return void. O comando return pode ser utilizado também para indicar a saída imediata da função, basta colacarmos o comando return sozinho. Se o tipo de retorno da função não é explicitamente declarado, o compilador C atribui automaticamente o tipo padrão, que é int.

Passando Argumentos por Referência

Passando Argumentos por Referência
/* porreferencia.cpp */ #include <stdio.h> #include <conio.h> void troca(int *x, int *y); main(){ int a=10; int b=20; troca(&a,&b); printf("%d %d", a,b); getch(); } void troca(int *x,int *y){ int temp; temp=*x; *x=*y; *y=temp; }

Exercícios

O endereço de um argumento é copiado no parâmetro formal da função. Dentro da função o endereço é usado para acessar o argumento real utilizado na chamada da função. Isto significa que alterações feitas nos parâmetros formais afetam os argumentos usados na chamada da função.

Codificar uma função que recebendo um ponteiro para uma frase retorne o tamanho (quantidade de caracteres) da frase. ponteirotamanhofrase.cpp

Locais de Declaração de Variáveis

Matrizes como Argumento para uma Função
● ●

Matrizes como Argumento para uma Função
/* varrematrizcomaritmeticadeponteiros.cpp */ #include <stdio.h> #include <conio.h> int numeros[5]; void mostra(int *p){ for (int i=0; i<5; i++){ printf("\n%d",*(p++)); // ou printf("\n%d",p[i]) } } main(void){ for(int i=0;i<5;i++){ numeros[i]=i*10; } mostra(numeros); getch(); }

Existem 3 lugares em um programa em C onde as variáveis podem ser declaradas: Fora de todas as funções, inclusive a função main(). A variável assim declarada é chamada de variável global e pode ser usada em qualquer parte do programa. Uma variável global é criada quando o programa inicia e é destruída quando o programa é finalizado. Dentro de uma função. A variável assim declarada é chamada de variável local e só pode ser usada dentro desta função. Uma variável local é criada quando a função é invocada e destruída quando a função é finalizada. Na lista de parâmetros formais de uma função, para receber os argumentos que são passados para a função. Variável declarada como parâmetro formal de uma função é criada quando a função é invocada e destruída quando a função é finalizada.

Em C, quando uma matriz é usada como um argumento para uma função, apenas o endereço da matriz é passado, não uma cópia da matriz inteira. Quando você chama uma função com um nome de matriz como argumento, um ponteiro para o primeiro elemento da matriz é passado para a função.

int i[10]; func1(i);

Podemos declarar o parâmetro formal de três formas:
como um ponteiro como uma matriz dimensionada como uma matriz não dimensionada

1. void func1(int *x) 2. void func1(int x[10]) 3. void func1(int x[])

Podemos verificar que o comprimento da matriz não importa para a função, porque C não realiza verificação de limites. Portanto void func1(int x[30]) também funcionaria, porque o compilador C instrui func1 a receber um ponteiro, ele não cria realmente uma matriz de 10 ou de 30 elementos.

Matrizes como Argumento para uma Função

Função Retornando Ponteiro

Exercícios

Quando uma matriz bidimensional é usada como argumento para uma função, apenas um ponteiro para o primeiro elemento é realmente passado. Porém, uma função que recebe uma matriz bidimensional como parâmetro, deve definir pelo menos o comprimento da 2a. Dimensão. Isto ocorre porque o compilador C precisa saber o comprimento de cada linha para indexar a matriz corretamente. Exemplo: Uma função que recebe uma matriz bidimensional de inteiros 10 x 10 é declarada desta forma: void func (int x[ ] [10]); É importante entender que, quando uma matriz é usada como um argumento para uma função, seu endereço é passado para a função. Portanto existe a possibilidade do conteúdo original da matriz ser alterado. Você pode gerar um ponteiro para o primeiro elemento de uma matriz simplesmente especificando o nome da matriz, sem nenhum índice.

Indicamos que uma função retornará um ponteiro inserindo um * antes do nome da função.

Codificar um programa que implemente o jogo da forca. jogoforca.cpp Codificar uma função para receber um caractere como argumento e, se for uma letra minúscula, retorne-a em maiúscula, caso contrário retorne o próprio caractere. funcaomaiuscula.cpp Codificar um programa que solicite a digitação de 10 números e os coloque em uma matriz. Chame uma função que ordene os valores da lista e mostre os valores ordenados. ordenavetor.cpp

int *func();

Exercício: Codificar uma função que devolve um ponteiro para a primeira ocorrência de um caracter em uma string. Mostrar este caractere e todos apartir dele. retornandoponteiro.cpp

int *p; int teste[10]; p = teste /* p recebe o endereço do 1o. elemento de teste. */

Exercícios

Funções Recursivas
● ●

Funções Recursivas
int fatr(int n){ int x; if (n==1){ return(1); } x=fatr(n-1)*n; return(x); }

Codificar um programa para jogar o jogo da velha. Para o jogo da velha é utilizado uma grade de três linhas por três colunas. Os jogadores se alternam nas jogadas e marcam sucessivamente uma posição livre a cada jogada. Um jogador usa como marca um O e o outro um X. Vence o jogo quem conseguir preencher em primeiro lugar uma linha, uma coluna ou uma das diagonais da grade com a sua marca. O jogo acaba empatado se todos as posições tiverem sido preenchidas e nenhum dos dois jogadores chegou a satisfazer a condição de vitória. jogodavelha.cpp apresente as instruções do jogo sorteie o jogador que inicia o jogo (jogador O ou jogador X) enquanto não houver vencedor E existir posição desocupada faça apresente a grade do jogo para mostrar posições ocupadas e desocupadas posiçãoNãoVálida <- verdadeiro repita leia a localização da posição selecionada pelo jogador de quem for a vez se posição inválida OU posição já ocupada então apresente "Posição inaceitável - Selecione outra: " senão posiçãoNãoVálida <- falso fim-se enquanto posiçãoNãoVálida coloque na posição selecionada da grade a marca apropriada passe a vez para o outro jogador fim-enquanto apresente o vencedor se existir

Recursão é o processo de definir algo em termos de si mesmo. A função é recursiva se um comando no corpo da função a chama.

/* fatorial.cpp */ #include <stdio.h> #include <conio.h> int numero; int fat(int n); int fatr(int n); main(){ printf("\nNumero:"); scanf("%d",&numero); printf("\nFatorial: %d",fat(numero)); printf("\nFatorial: %d",fatr(numero)); getch(); } int fat(int n){ int x=1; for (int i=1; i<=n; i++){ x=x*i; } return(x); }

Alocação Dinâmica de Memória

Alocação Dinâmica de Memória

Alocação Dinâmica de Memória

● ●

É o meio pelo qual um programa pode obter memória enquanto está em execução. A função que aloca memória: malloc() Cada vez que é feita uma solicitação de memória por malloc(), uma porção da memória livre restante é alocada. A função malloc() devolve um ponteiro do tipo void, o que significa que você pode atribuí-lo a qualquer tipo de ponteiro (desde que faça o casting corretamente). Após uma chamada bem sucedida, malloc() devolve um ponteiro para o primeiro byte da região de memória alocada. Se não há memória disponível para satisfazer a requisição de malloc(), ocorre uma falha de alocação e malloc() devolve um nulo.

O trecho abaixo aloca 1000 bytes de memória:

char *p; p = malloc(1000) //p apontará p/ o 1o. dos 1000 bytes

Sempre que alocarmos memória devemos testar se o valor devolvido por malloc()não é nulo:

O trecho abaixo aloca espaço para 50 inteiros:

int *p; p = malloc(50 * sizeof(int))

p = malloc(1000) if (p == NULL){ printf(“Sem memória.”); ... }

Alocação Dinâmica de Memória

Alocação Dinâmica de Memória
● ●

Estruturas (struct) É uma coleção de variáveis referenciadas por um único nome, permitindo agrupar informações relacionadas. A definição de uma estrutura forma um modelo que pode ser usado para criar variáveis de estruturas. As variáveis que compreendem a estrutura são chamadas membros da estrutura (ou elementos ou campos).

A função free() libera memória previamente alocada ao sistema

int *p; p = malloc(500) ; free(p);

Exercício: Codificar um programa para alocar espaço para uma string (80 caracteres) dinâmicamente, solicitar a entrada do usuário e, em seguida, imprimir a string de trás para frente. matrizalocadadinamicamente.cpp 1)Alocar memória 2)Verificar se foi bem sucedida a operação 3)Solicitar a string 4)Mostrar a string de trás para frente 5)Liberar memória

Ao usar estas funções inclua: stdlib.h

Estruturas (struct)

Estruturas (struct)

Estruturas (struct)
atribuicaoestruturas.cpp #include <stdio.h> #include <conio.h> main(){

Definição de uma estrutura:

Referenciando Elementos de Estruturas

struct dados{ char nome[30]; char curso[20]; char turma; double nota; };

nome_da_estrutura

.nome_do_elemento

Exemplos:

struct { int a; int b; }x,y; x.a=10; y=x; printf("%d",y.a); getch(); }

O trecho de código anterior, não declarou nenhuma variável, apenas definiu a forma dos dados. Para declarar uma variável de nome aluno do tipo dados, escreva:

printf(“%s”, aluno.nome); gets(aluno.nome); aluno.nota = 100;

Toda informação contida em uma estrutura pode ser atribuída a outra estrutura do mesmo tipo.

struct dados aluno;

Estruturas (struct)

Exercícios: exemplo de uso de matriz de estruturas
matrizestrutura.cpp #define MAX 3 #include <stdio.h> Atenção #include <conio.h> p[i].nome struct dados{ p->nome char nome[30]; float nota; O operador -> é usado }; no lugar do operador struct dados alunos[MAX]; void inclui(struct dados *p); ponto quando se está acessando um void mostra(struct dados *p); elemento de estrutura main(){ inclui(alunos); por meio de um mostra(alunos); ponteiro para a getch(); estrutura. }

Estruturas (struct)
Exercício: Codificar um programa que mostre as horas, minutos e segundos na tela como se fosse um relógio digital. O programa deverá mostrar a hora no seguinte formato: hh:mm:ss. relogio.cpp

Matrizes de Estruturas: Para declarar uma matriz de estruturas, você deve primeiro definir uma estrutura e, então, declarar uma variável matriz desse tipo.

struct dados{ char nome[30]; char curso[20]; char turma; double nota; }; struct dados alunos[100]