Baixe o app para aproveitar ainda mais
Prévia do material em texto
PROGRAMAÇÃO C ( Avançado ) Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 2 ÍNDICE INTRODUÇÃO........................................................................................................................................ 3 CONCEITO.............................................................................................................................................. 3 ESTRUTURA BÁSICA DE UM PROGRAMA C .................................................................................4 TIPOS BÁSICOS ..................................................................................................................................... OPERADORES ARITMÉTICOS DE ATRIBUIÇÃO........................................................................... 11 OPERADORES RELACIONAIS............................................................................................................... COMANDOS DE SELEÇÃO .................................................................................................................... O COMANDO if ........................................................................................................................................ OPERADORES LÓGICOS........................................................................................................................ O COMANDO switch ................................................................................................................................ O COMANDO break.............................................................................................................................. 16 OPERADOR CONDICIONAL TERNÁRIO ( ? : ).................................................................................... LAÇOS DE REPETIÇÕES ........................................................................................................................ Estrutura de Repetição:............................................................................................................................... Laço for ...................................................................................................................................................... O LAÇO WHILE........................................................................................................................................ Estrutura do laço while : ............................................................................................................................. WHILE X FOR........................................................................................................................................... O LAÇO do-while ...................................................................................................................................... O COMANDO continue ............................................................................................................................. A Função exit() ........................................................................................................................................... FUNÇÕES / MÓDULOS / SUB-ROTINAS .......................................................................................... 24 FUNÇÕES.............................................................................................................................................. 25 VARIÁVEL GLOBAL........................................................................................................................... 26 O COMANDO return ............................................................................................................................. 26 PASSANDO DADOS PARA FUNÇÕES.............................................................................................. 27 USANDO VÁRIAS FUNÇÕES............................................................................................................. 28 RECURSIVIDADE................................................................................................................................ 29 ARRANJOS............................................................................................................................................ 30 ARRANJOS MULTIDIMENSIONAL................................................................................................... 32 STRING.................................................................................................................................................. 34 REGISTROS E ESTRUTURAS ........................................................................................................... 37 Conjunto de Estruturas ........................................................................................................................... 39 Uniões..................................................................................................................................................... 40 Argumentos argv e argc.......................................................................................................................... 40 PONTEIROS.......................................................................................................................................... 42 Operadores.............................................................................................................................................. 42 MATRIZES E PONTEIROS.................................................................................................................. 44 Streams ................................................................................................................................................... 47 Arquivos .................................................................................................................................................47 Referências ............................................................................................................................................. 53 Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 3 INTRODUÇÃO O objetivo desta trabalho é introduzir os conceitos básicos essenciais para um bom habito de programar, utilizando como ferramenta de programação a linguagem de programação C. Criada por Dennis M. Ritchie e Ken Thompson no laboratório Bell em 1972, baseada na linguagem B de Ken Thompson, que era uma evolução da antiga linguagem BCPL. “B” foi nomeada como a primeira letra de BCPL e C como a segunda. Embora o termo linguagem estruturada em blocos não seja rigorosamente aplicável a C, ele é normalmente referida simplesmente como linguagem estruturada. A razão pela qual C não é, tecnicamente, uma linguagem estruturada em blocos, é que essas linguagens permitem que procedimentos e funções sejam declarados dentro de procedimentos e funções. No entanto, como C não permite a criação de funções dentro de funções, não pode ser chamada formalmente de uma linguagem estruturada em blocos. ( Schildt ) CONCEITO O tipo de um dado determina o conjunto de valores a que uma constante pertence, ou que podem ser assumidos por uma variável, uma expressão ou gerados por uma função. Uma linguagem de programação representa um computador abstrato capaz de interpretar os termos utilizados nesta linguagem, os quais podem englobar um certo nível de abstração em relação aos objetos utilizados pela máquina física (Niklaus Wirth) Tipo Abstrato de Dados é um modelo matemático com um conjunto de operações definidas sobre o modelo. Algoritmo é um procedimento para resolver um problema matemático em um número finito de passos, que freqüentemente envolve repetição de operações. Um algoritmo é um procedimento computacional bem definido que toma alguns valores como entrada e produz alguns valores como saída. Programar é estruturar dados econstruir algoritmos. Analisar um algoritmo significa predizer quais recursos o algoritmo vai demandar quando executar. Programa: Forma de comunicação entre o programador e o computador Programas são ‘traduzidos’ através de outros programas “especiais”: para a Linguagem de máquina “ binário” (compiladores e interpretadores.) Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 4 ESTRUTURA BÁSICA DE UM PROGRAMA C consiste em uma coleção de funções forma geral main ( ) // primeira função a ser executada { // início da função } // fim da função As interpretações abaixo são as mesmas, porem para uma melhor legibilidade vamos adotar a primeira definição para a estrutura de uma função. main ( ) { } main ( ) { } main() { } Blocos de Comandos Blocos de comandos são simplesmente grupos de comandos relacionados que são tratados como uma unidade. Os comandos que constituem um bloco estão logicamente conectados. Um bloco começa e termina com uma chave ( { } ). Um bloco de comando geralmente pode ser interpretado como um programa completo, uma função completa, a parte verdadeira ou falsa de uma condição if-else ou o conteúdo de um laço de repetição. A FUNÇÃO main ( ) A função main() deve existir em algum lugar do programa e marca o ponto de início da execução do programa. As chaves limitam o corpo da função. Toda instrução deve ser encerrada por ponto e vírgula ( ; ) Comentários Comandos ( “ /* */ ” “ // “ ) Informação acrescentada ao código para facilitar sua compreensão É ignorado pelo compilador (não faz parte do código objeto) Comentário de Bloco, começa com ( /* ) terminando com ( */ ) Comentários de linha // , começa com ( // ) terminando no final da linha. A FUNÇÃO printf ( ) A função printf() é uma das funções de I/O ( entrada e saída) que é usada em C. Ela não faz parte da definição da linguagem, mas todos os ambientes de programação que suportam a linguagem de programação C tem uma versão da função printf() definida em suas bibliotecas. Função de E / S ( definida no cabeçalho padrão de entrada e saída stdio.h ) Uma função pode receber uma informação (argumento) Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 5 Sintaxe: printf (“expressão de controle”,lista de argumentos); main ( ) { int x = 2; // declaração de variáveis local a função printf (" O número %d",x); //printf recebe a informação x e //imprime-a na tela como forma de saída. } OBS.: ( %d ) código de formatação utilizado pela função printf() na impressão dos dados. Outras utilizações de printf main ( ) { printf ("\r %s está a %d km de Caratinga \n \r ou a %d metros”, “Ipatinga”, 98, 98000); } Saída: Ipatinga está a 98 km de Caratinga ou a 98000 metros. \ n : é um caractere de controle que indica uma mudança de linha. \ r : é um caractere de controle que indica retorno do cursor ( <enter> ). main ( ) { printf("a letra %c",’a’ ); //a letra b sera interpretadas como char. printf (" vem antes de %c", ‘b’); } Saída: a letra a vem antes de b CARACTERES DE CONTROLE Código Descrição \n nova linha \r retorno do cursor (enter) \t tabulação ( tab ) \b retrocesso ( backspace ) \“ aspas \ \ Barra \0 Nulo CÓDIGO DE FORMATAÇÃO Código Descrição %c car c caractere %x Hexadecimal %d Decimal %e Notação científica %f ponto flutuante %o Octal %s cadeia de caracteres (string) %u Decimal sem sinal Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 6 EXPLORANDO A FUNÇÃO printf Tamanho de campos: É possível estabelecer o tamanho mínimo para a impressão de um campo main ( ) { printf (" os alunos são %2d \ n", 350); printf (" os alunos são %4d \ n", 350); printf (" os alunos são %5d \ n", 350); } Saída: os alunos são 350 os alunos são 350 os alunos são 350 3 5 0 3 5 0 3 5 0 main ( ) { printf (" %3.1f \ n", 3456.78); printf (" %10.3f \ n",”3456.78); } Saída: 3456.8 3456.780 CONSTANTES E VARIÁVEIS Constantes Constantes referem-se a valores fixos que o programa não pode alterar. “Objeto” que tem valor fixo e inalterável . Ex: ‘c’, 8, “primeiro programa” Variáveis Uma variável é uma posição nomeada de memória, que é usada para guardar um valor que pode ser modificado pelo programa. um “objeto” que pode assumir diferentes valores es . espaço de memória de um certo tipo de dado associado a um nome para referenciar seu conteúdo. Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 7 INICIALIZANDO VARIÁVEIS A combinação de uma declaração de variáveis com o operador de atribuição. /* O programa abaixo faz a demonstração de alguns códigos de formatação. */ main ( ) { int evento = 5; char corrida = ‘A’; float tempo = 27.25; printf ("O melhor tempo da eliminatória %c",corrida); printf ("\n do evento %d foi % f", evento, tempo); } Saída: O melhor tempo da eliminatória A do evento 5 foi 27.25 main ( ) { int idade; // declaração da variável. Idade = 30; // inicializando a variável printf (" A idade mínima é : %d", idade); } Saída: A idade mínima é : 30 NOMES DE VARIÁVEIS Quantos caracteres quiser (até 32). Comece com letras ou sublinhado: seguidos de letras, números ou sublinhados ‘'C'’ é sensível ao caso: => peso ¹ Peso ¹ PESO ¹ pESo Não podemos definir um identificador com o mesmo nome que uma palavra chave. Ex.: int char, int while, int for, int int. Declaração de variáveis em um programa na sua forma mais simples: tipo nome-da-variável; tipo nome1, nome2, ... nomeN; O Tipo é uma instrução utilizada para reservar uma quantidade de memória para um certo tipo de dado, indicando o nome pela qual a área será referenciada (int, char, float...). Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 8 TIPOS BÁSICOS Determina um conjunto de valores e as possíveis operações realizadas sobre os mesmos. Informa a quantidade de memória (bytes). tipo Bytes escala char 1 -128 a 127 int 2 -32.768 a 32.767 float 4 3.4e-38 a 3.4e+38 double 8 1.7e-308 a 1.7e+308 void 0 sem valor Modificadores de tipos long int ( 4 bytes) unsigned char ( 0 a 255 ) unsigned int ( 0 a 65.535 ) Obs.: int tem sempre o tamanho da palavra da máquina. A FUNÇÃO scanf( ) A função scanf() é uma das funções de I/O ( entrada e saída) que é usada em C. Ela não faz parte da definição da linguagem, mas todos os ambientes de programação que suporta a linguagem de programação C tem uma versão da função scanf() definida em suas bibliotecas. Função de E / S ( Biblioteca : stdio.h ) Complemento de printf( ) Sintaxe scanf( “expressão de controle ”,lista de argumentos) expressão de controle : % lista de argumentos : &variável main ( ) { int num; printf("Digite um número\n"); //o programa escreverá na tela scanf("%d", &num); printf(" numero digitado foi %d ",num); // saída do programa. } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 9 OBS. : Logo que o usuário atender à mensagem o número será lido pela função scanf(), sendo que o operador & indicará o endereçode memória da variável indicada. /* A única diferença do programa abaixo é que uma letra será lida pelo scanf(). */ main ( ) { char letra; printf(" Digite uma letra\n"); scanf ("%c", &letra); printf(" A letra digitada foi %c",letra); } O OPERADOR DE ENDEREÇO (&) O nome da variável é associado a um endereço de memória pelo computador Toda variável ocupa uma área de memória e seu endereço é identificado pelo primeiro byte por ela ocupado com o deslocamento do tamanho da variável Quando usamos & precedendo uma variável, estamos falando do endereço da mesma na memória main ( ) { int num; num = 2; printf (" valor = %d, endereço = %u", num, &num); // %d valor decimal e %u é um endereço de memória da variável. } Saída valor = 2, endereço = 1230 CÓDIGO DE FORMATAÇÃO scanf( ) Código Descrição %c Caracter %d Inteiro %e Número ou notação científica %f Ponto flutuante %o Octal %x Hexadecimal %u Decimal sem sinal ( endereço de memória) %s String (cadeia de caracteres) %lf Double /* O programa abaixo relaciona um caracter com o seu valor decimal da tabela ASCII, seu valor octal e hexadecimal. */ main ( ) { char a ; printf ( “digite um caracter” ); scanf ( “ % c”, &a ); printf (“ \n %c = %d em decimal”, a, a); printf (“%o em octal, %x em hexadecimal”, a, a); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 10 Digitando m: m = 109 em decimal, 155 em octal, 6d em hexadecimal LENDO E ESCREVENDO CARACTERES getchar( ) Lê um caracter do teclado, sem a obrigatoriedade de pressionar < enter >, ou seja, após a digitação do caracter. putchar() Escreve um caracter na tela a partir da posição atual do cursor. #include <stdio.h> /* Função usando getchar e putchar */ void main ( void ) { char ch; printf(" Digite um caracter: " ) ; ch = getchar( ); // o caracter está sendo lido do teclado. putchar(ch); // impressão do caracter na tela. } OPERDORES ARITMÉTICOS binários: = + - * / % unário: - main ( ) { int resto, divisor, dividendo; printf(“entre com 2 números”); scanf(“ %d %d” , ÷ndo, &divisor); resto = dividendo % divisor; // % resto da divisão entre dois num. printf(“o resto da divisão inteira de %d”, dividendo); printf(“por %d = %d”, divisor, resto); } Saída: entre com 2 números 10 4 o resto da divisão inteira de 10 por 4 = 2 O % como resto da divisão só aceita números inteiros. OPERADORES DE INCREMENTO E DECREMENTO Incrementam / decrementam uma unidade de seu operando. pré - fixado (--x) pós -fixado (x++) ex.: int n; n = 0; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 11 n++; n=0, inicialmente a variável terá valor zero e depois será pós-fixada em 1. n = 0; ++n; Neste caso a variável será primeiramente incrementada. É como se fosse 1 + 0 = 1, n = 1. main( ) { int num = 0; printf (" %d \n", num); printf (" %d \n", num++); printf (" %d \n", num); printf (" %d \n", ++num); } Saída: 0 0 1 2 main ( ) { int num = 0; printf (" %d \n",num); printf (" %d \n", ++num); printf (" %d \n", num++); printf (" %d \n",num); } Saída: 0 1 1 2 PRECEDÊNCIA ++ -- * / % + - (binário) = Ou seja: x = 3 * a++ - b = (3 * (a++)) - b y = 3 * --a - b = (3 * (--a)) - b z = a * b++ = a * (b ++) Obs.: ++, -- só podem ser usados com variáveis inteiras. CUIDADO COM printf( ) Ex.: n = 5; printf (“ %d %d %d \n”, n, n + 1, n++); saída: 5 6 5 (avaliação feita à esquerda) Ex.: main ( ) { int n, i = 3; n = i * (i + 1) + (++i); printf ("n = %d", n); } OBS. : i tem valor 3 que somado com 1 no primeiro parêntese será 4 e incrementado no segundo continuará com o valor 4, logo 3*(4) + (4) = 24. Saída: n = 24 Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 12 OPERADORES ARITMÉTICOS DE ATRIBUIÇÃO +=, -=, *=, /=, %=. Atribuir um novo valor à variável dependendo do operador e da expressão a direita. A sintaxe: x op = exp é equivalente a x = (x) op (exp) Ex.: i += 2 → i = i + 2; x *= y + 1 → x = x * (y + 1) t /= 4 → t = t / 4 p %= 6 → p = p % 6 h -= 3 → h = h - 3; OPERADORES RELACIONAIS Usados para comparações Operador Descrição > Maior > = Maior ou igual < Menor < = Menor ou igual == Igualdade != Diferença Em C não existe o tipo "booleano". 0 falso. Valor diferente de zero (0) é verdadeiro. main ( ) { int verdadeiro, falso; verdadeiro = (15 < 20); falso = (15 == 20); printf (“Verd. = %d, falso = %d”, verdadeiro, falso); } Saída: Verd. = 1 falso = 0 /* Definição de verdadeiro ou falso para um programa.*/ #define true = 1 #define false = 0 /* Para que este programa funcione devemos usar a biblioteca stdio.h. Quando usamos o comando define estamos definindo que a variável terá um valor que por sua vez será constante. */ main ( ) { int verdadeiro, falso; verdadeiro = true; falso = false; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 13 printf (“Verd. = %d, falso = %d”, verdadeiro, falso); } Saída: Verd. = 1 falso = 0 Precedência: ! - ++ - - * / % Aritméticos + - < > <= >= Relacionais == != && | | Lógico = += -= *= /= %= Atribuição COMANDOS DE SELEÇÃO No desenvolvimento de um programa muitas vezes se faz necessário o conhecimento de uma resposta para podermos decidir qual bloco de comando deve ser executado. Isto é alcançado através dos comandos de decisões disponíveis na linguagem de programação. Permitir testes com uma variável para decidir qual bloco de comando será executado. if, if - else, switch e Operador Condicional Ternário ( ? : ). O COMANDO if Estrutura : if ( condição ) instrução; main ( ) { char ch; ch = getchar ( ); // obtém o caracter digitado. if (ch == ‘p’) // compara o caracter digitado coma letra p. printf (" você pressionou a tecla %c ",ch); } MÚLTIPLAS INSTRUÇÕES Estrutura: if ( condição ) { comando 1; comando 2; } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 14 if ANINHADOS Se um comando if está dentro de outro if, dizemos que o if interno está aninhado main ( ) { char ch; printf (“ digite uma letra entre A e Z”); ch = getche ( ); //obtém o próximo caracter a ser considerado. if (ch >= ‘A’) //faz o primeiro teste, se for verdadeiro faz o segundo. //As duas condições têm que ser verdadeiras. if (ch < = ‘Z’) printf (“você digitou uma letra maiúscula”) } /* Aprimorando o programa anterior. */ main ( ) { char ch; printf (" Digite uma letra entre A e Z: "); ch = getche ( ); if (( ch >= 'A')&&(ch <= ' Z')) // && operador lógico and. printf (" Você acertou\n"); // tem que ser satisfeita. } O COMANDO if - else Comandoif só executa as instruções que fazem parte do primeiro bloco, caso a condição de teste seja verdadeira, nada será feito se a expressão for falsa. Comando else executará um bloco de instruções se a expressão de teste for falsa. Estrutura: if( condição ) { instrução1; // condição instrução2; // verdadeira } else { instrução3 // condição instrução4 // falso } main ( ) { if (getchar ( ) == ‘c’) printf (" Você digitou c "); else printf (" Você não digitou c"); } if - else ANINHADOS Estrutura:if( condição1 ) instrução else if( condição2 ) instrução else if (condicao3) ... Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 15 main ( ) { int numero; printf("Digite um número \n"); scanf (" %d",&numero); if ( numero < 0 ) printf (" número menor que zero\n"); else if ( numero < 10) printf ("“número ³ 0 e < 10\n"); else if ( numero < 100) printf (" número ³ 10 e < 100 \n") else printf ("“número ³ 100”\n"); } else é sempre associado ao if mais interno (mais próximo) Note a diferença: /* Neste bloco o comando else está associado ao primeiro if, pois o if foi fechado antes de else, descartando assim a possibilidade de relacionamento com o segundo if. */ if (n > 0) { if (a > b) z = a; }else z = b; OPERADORES LÓGICOS ( && , | |, ! ) Comando Descrição && and ( e ) | | ou ( ou ) ! not ( não ) Ex.: (1 || 2) (x && y) (a > 10) && (x < 10) !( x > 0) (10 < = a) && (a < = 100) EXEMPLOS: if (10 < a) && (a < 100) / * 10 < a < 100 * / Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 16 main ( ) { int numero; printf("Digite um número:"); scanf (" % d", &numero); if( numero < 0 ) printf (" Número menor que zero"); else if ((numero > 0) && (numero < 10) ) printf (" Número > 0 e < 10"); else if (( numero >= 10) && ( numero < 100) ) printf (" Número > = 10 e < 100"); else printf (" Número > = 100" ); } Contando caracteres e dígitos de uma frase: main ( ) { char c; int car = 0, dig = 0; printf ("Digite uma frase e encerre-a com <enter>\n" ); while ( ( c = getchar ( ) ) != ‘\r’ ) { car++; if ( ( c >= ‘0’)&&( c < = ‘9’) ) dig++; } printf ("“Número de caracteres %d", car); printf (" Número de dígitos %d", dig); } Para se formular um pergunta podemos utilizar o unário ! Isto é possível porque na linguagem C ZERO é falso e qualquer valor positivo é verdadeiro. if (nota = = 1) if ( nota ) if (nota = = 0) if ( !nota ) O COMANDO switch Construções if-else facilitam a escrita de programas que devem escolher uma entre duas alternativas. Algumas vezes, entretanto, o programa necessita escolher uma entre várias alternativas. Embora construções else-if possam executar testes de vários modos, elas não são de maneira nenhuma elegantes. O código pode ficar difícil de ser seguido e confundir até mesmo seu autor num momento futuro. Para estes casos, C oferece a construção switch. Forma de substituir o comando if - else ao se executar vários testes. Similar ao if - else com maior flexibilidade e formato limpo. Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 17 ESTRUTURA SWITCH: switch ( expressão ) { case constante1: instruções; break; // O break é usado para forçar a saída do case. case constante2: instruções break; default: //será executado se a opção digitada for inválida. instruções } /* No programa abaixo o break é usado para forçar uma saída imediata do case ao qual pertence. Se não colocarmos o break, a segunda opção será executada sem que seja solicitada. */ main ( ) { char op; float num 1, num 2; while ( 1 ) { printf (" Digite um n, um operador e um n”); scanf ( "%f %c %f ",&num1,&op,&num2); switch ( op ) { case '+ ': printf ("= %f", num 1 + num 2); break: case '-':: printf ("= %f", num 1 - num 2); break; default: printf ( " Operador inválido"); } } } O COMANDO break O comando break é um dos comandos de desvio em C. Você deve usá-lo juntamente com o comando switch. Quando um break é encontrado em um switch, a execução do programa salta para a linha de código seguinte ao comando switch. O comando break pode ser usado em qualquer estrutura C. ( switch ou laço ). Causa a saída imediata do bloco em que se encontra. Quando estiver presente em laços aninhados afetará somente o laço que o contém (e os internos, obviamente). Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 18 O OPERADOR CONDICIONAL TERNÁRIO (? : ) Forma composta de expressar uma instrução if – else Estrutura... ( Condição ) ? valor para caso verdadeiro : valor para caso falso ; max = (num1 > num2) ? num1 : num2; Note: if (num1 > num2) max = num1; else max = num2; Os dois exemplos são equivalentes. Exemplo: main( ) { int num, resultado; printf ("Digite um número \n"); scanf ("%d",&num); resutado = abs ( ( num < 0 ) ? -num: num ); printf (" O valor absoluto do número é :",resultado); } LAÇOS DE REPETIÇÕES Comando de repetições permitem que um conjunto de instruções ( bloco de instruções) seja executado até que ocorra uma certa condição. Essa condição pode ser predefinida ( como no laço for) ou como o final aberto ( como nos laços while e do-while ) main ( ) { printf (" 1 " ); printf (" 2 " ); : : : printf (" 10 "); } Saída: 1 2 3 4 ... 10 Como imprimir os 1000 primeiros números a partir de 1? Solução 1: main ( ) { printf ( "1"); printf ( "2"); : : : printf ("1000"); } Solução 2: Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 19 main ( ) { int i; for (i = 1; i < 1000; i++) //Nesta linha ocorre a predefinição do //laço, sendo que a condição //de parada é i > 1000. printf ("%d",i); } for, while, do-while Estrutura de Repetição: Inicialização: expressão de atribuição. sempre executada uma única vez. Teste: condição que controla a execução do laço. é sempre avaliada a cada execução. verdadeiro continua a execução falso para a execução Incremento OU Decremento: define como a variável de controle será alterada para que o laço seja finalizado é sempre executada após execução do corpo do laço Laço for Estrutura: for(inicialização ; teste ; incremento/decremento ) { instrução; // corpo do laço } O laço for permite muitas variações. Entretanto, a inicialização é, geralmente, um comando de atribuição que é usado para colocar um valor na variável de controle do laço. O teste é uma expressão relacional que determina quando o laço acaba. O Incremento/Decremento define como a variável de controle do laço varia cada vez que o laço é repetido. IMPRIMINDO NÚMEROS PARES main ( ) { int número; for ( número = 2; número < 10; número += 2 ) printf (" %d", número); } Saída: 2 4 6 8 Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 20 FLEXIBILIDADEQualquer expressão de um laço for pode conter várias instruções separadas por vírgula. main ( ) { int x, y; for (x = 0, y = 0; (x + y) <= 100; x++, y++) printf ("%d", x + y); } Ex.: /* imprime as letras do alfabeto. */ main ( ){ char ch; int i; for (i = 1, ch = ‘a’; ch <= ‘z’; ch++,i++) printf ("%d letra = %c ascii = %d \n",i,ch,ch); } ascii = número da letra correspondente na tabela ASCII. Saída: 0 letra = a ascii = 97 1 letra = b ascii = 98 2 letra = c ascii = 99 3 letra = d ascii = 100 4 letra = e ascii = 101 5 letra = f ascii = 102 : : : 25 letra = z ascii = 122 Note o uso de funções nas expressões do laço. /* Neste laço for os caracteres digitados são lidos, ao mesmo tempo que são testados verificando se são diferentes de x e incrementados no printf ch + 1. */ main ( ) { char ch; printf( " Digite uma frase\n"); for (ch = getchar( ); ch!= ‘x’;ch=getch()) // A função getch() lê o caracter do teclado e não imprime na tela. printf ("%c", ch + 1); } Frase digitada : analise do problema em questão Saída: b o b m j t f ! e p ! q s p c m f n b ! f n ! r v f t u b p OBS.: Os caracteres digitados foram somados com um ( 1 ), de forma que a = b, b = c e assim sucessivamente. OBS.: Qualquer uma das 3 expressões pode ser omitida, permanecendo apenas os ( ; ; ) Reescrevendo o exemplo anterior: Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 21 main ( ) { char ch; printf(" Digite uma frase\n"); for ( ; (ch = getchar ( );)!=‘x’; printf (" %c", ch + 1); } CUIDADO Se a expressão de teste não estiver presente é considerada sempre verdadeira. main ( ) { for ( ; ; ) printf (“\n estou em loop infinito”); } main ( ) { int i; for ( i = 0; i < 100; i++ ) printf ("%d", i ); } Saída: 0 1 2 3 4...99 main ( ) { int i; for ( ; ; ){ printf (" %d", i ); i++; if ( i == 100 ) break; } main ( ) { int i=0; for ( ; i < 100 ; ){ printf (" %d", i ); i++; } LAÇOS ANINHADOS Quando um laço está dentro de outro, dizemos que o laço interior está aninhado main ( ) { int i, j; for (i = 1; i <= 3; i++) for (j = 1; j < = 2; j++) printf ("%d %d \n", i, j); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 22 O LAÇO WHILE Estrutura do laço while : Inicio while ( expressão de teste ) { instrução; inc / dec } Onde a instrução pode ser uma instrução simples ou um bloco de instruções. A expressão de teste pode ser qualquer expressão, sendo considerado verdadeiro qualquer valor diferente de zero. O laço se repete quando a condição for verdeira. Quando a expressão de teste for falsa, o controle do programa passa para a linha após o código do laço. “Instrução” só é executada se “expressão de teste” for verdadeira ( != 0 ) Expressão é sempre avaliada até que se torne falsa ( = 0) Ex.: main ( ) { int num; num = 0; while (num < 3) //enquanto o num for menor que 3 o laço se repetirá. printf("%d",num++); //saída do programa e inc da variável } Obs.: O corpo de um while pode ter: uma única instrução, várias instruções entre chaves e nenhuma instrução. WHILE X FOR for: Geralmente este laço é muito estável, sendo conhecido o inicio e o fim do laço. número de repetições é fixo; Muito útil para controle de vetor e matriz. while: não se sabe a princípio o número de iterações, o laço pode terminar inesperadamente. /* Contar o número de caracteres de uma frase até que <enter> seja digitado. */ main ( ) { int cont = 0; printf ( " Digite uma frase: \n"); while (getchar( ) != ‘\r’) //Os caracteres serão lidos até //que < enter > seja pressionado. cont++; printf ("“\n O número de caracteres é %d", cont); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 23 Whiles dentro de um laço while ( laço aninhado ) main ( ) { int num, vezes = 1; char continua = s;’ while (continua == s ) { printf ("\n Digite um número entre 1 e 1000" ); scanf (" %d", &num); while (num != 50) { printf ("%d incorreto.", num); printf(" Tente novamente \n" ); scanf ("%d", &num); vezes++; } printf (" \n Acertou em %d tentativa(s) ", vezes); printf (" \n Joga novamente? (s / n):”" ); continua = getche( ); } } /* A função getche() lê o caracter do teclado e permite que seja impresso na tela. */ O LAÇO do-while Cria um ciclo repetitivo até que a expressão seja falsa (zero). Evita duplicação de código. Executa o laço (pelo menos uma vez) mesmo que a condição seja falsa. Similar ao laço while ( a diferença está no momento em que a condição é avaliada ). Estrutura: inicio do { instrução; inc/dec ; }while(expressão de teste); / * O programa abaixo testa a capacidade de adivinhar uma letra */ main ( ) { char ch; int tentativas; do { printf (" Digite uma letra”\n"); tentativas = 1; while ( (ch = getchar ( ) ) != ‘t’) { printf (“"%c é incorreto \n”", c); tentativas++; printf ( " Tente novamente \n"”); } printf (" %c é correto", c); printf (" Acertou em %d vezes\n", tentativas); printf ("Continua? (s / n):"”); }while( getchar( )== ‘s’); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 24 O COMANDO continue O comando continue trabalha de uma forma um pouco parecida com a do comando break. Em vez de forçar a terminação, continue força que ocorra a próxima iteração do laço, pulando qualquer código intermediário ou imediatamente abaixo. Deve-se evitar o comando Continue, pois dificulta a legibilidade de um programa. A Função exit() A função exit() está definida na biblioteca padrão do C. Essa função provoca uma terminação imediata do programa inteiro, forçando um retorno ao sistema operacional. /* O programa abaixo relaciona os comandos: continue, break e exit( ). */ #include <stdio.h> void main( void) { int i; for(i = 0; i < 100; i++) { if ( i < 4 ) continue; if ( i == 20 ) break; if ( i == 15 ) exit(1); printf(“ %u”, i); } } FUNÇÕES / MÓDULOS / SUB-ROTINAS Funções são os blocos de construção de C. O tipo-de-retorno especifica o tipo do valor que o comando retorn da função devolve, podendo ser qualquer tipo válido. Se nenhum tipo é especificado, o compilador assume que a função devolve um resultado inteiro. A lista de parâmetros é uma lista de nomes de variáveis separados por vírgula e seuss tipos associados que recebem os valores dos argumentos quando a função é chamada. Quando a função não tem parâmetro, os parênteses ainda são necessários. Variáveis Locais static Quando o modificador static é aplicado a uma variável local ( ou declarada dentro de uma função ), o compilador cria armazenamento permanente para ela. Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 25 Variáveis Globais static Aplicar o especificado static a uma variável global informa ao compilador para criar uma variável global que é reconhecida apenas no arquivo no quala mesma foi declarada. Isso significa que, muito embora a variável seja global, rotinas em outros arquivos não podem reconhecê-la. Funções : abstrações de expressões ( Modulo ) Dividir uma tarefa complexa em tarefas menores, permitindo esconder detalhes de implementação Evita-se a repetição de um mesmo código Estrutura: tipo_de_retorno nome(lista de parâmetros ex. tipo var1, tipo var2..) { corpo da função } tipo_de_retorno nome (lista de parâmetros ex. var1, var2 ... ) tipo var1; tipo var2; { corpo da função } EM C UM PROCEDIMENTO É FEITO ATRAVÉS DE UMA FUNÇÃO SEM RETORNO “Funções” que não retornam valores void desenha( ) { int i; for (i = 0; i < = 10; i++) printf (“-”); } main ( ) { desenha ( ); printf (“ usando funções”); desenha ( ); printf (“ \n usando funções”); desenha(); } FUNÇÕES /* A função abaixo calcula o fatorial de um número retornando o resultado. */ int fatorial (int n){ int i, resultado = 1; for ( i = 1; i <= n; i ++) resultado *= i; // resultado = resultado * i. return resultado; } main ( ) { printf (“ o fatorial de 4 = %d”, fatorial(4) ); printf (“ o fatorial de 3 = %d”, fatorial(3) ); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 26 VARIÁVEIS LOCAIS Variáveis declaradas dentro de uma função são denominadas locais e somente podem ser usadas dentro do próprio bloco São criadas apenas na entrada do bloco e destruídas na saída (automaticamente) Ex.: void desenha ( ) { int a, i; . . . . . . } main ( ) { int a; desenha(); a = i; erro . . . } VARIÁVEL GLOBAL Variável que é declarada externamente podendo ser acessada por qualquer função int i; void desenha ( ) { int j; i = 0; . . . } void calcula ( ) { int m; i = 5; . . . } O COMANDO return Causa a atribuição da expressão a função, Forçando o retorno imediato ao ponto de chamada da função Exemplo /* Esta função retorna um caracter. */ char minúsculo ( ) { char ch; ch = getchar( ); if ( (ch >= ‘A’) && (ch <= ‘Z’)) return (ch + ‘a’ - ‘A’); else return (ch); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 27 main ( ) { char letra; printf (“ digite uma letra em minúsculo”); letra = minúsculo ( ); if (letra == ‘a’) // if (minúsculo( ) == ‘a’) printf (“ok”); } PASSANDO DADOS PARA FUNÇÕES Passagem de parâmetro por valor - uma cópia do argumento é passada para a função parâmetro se comporta como uma variável local Ex.: char minúsculo (char ch) parâmetro formal { If (( ch >= ‘A’) (ch <= ‘Z’)) return (ch + ‘a’ - , ‘A’); else return (ch); } main ( ) { printf (“ %c”, minúsculo (‘A’) ); parâmetro real } Exemplo.... Valor Absoluto /* Retornando o valor absoluta de um número */ int abs (int x) { return ( ( x < 0 ) ? -x : x ); } main ( ) { int num, b; printf (" Entre com um número "); scanf (" %d", &num ); b = abs (num); printf (" Valor absoluto de num = %d", b ); b = abs(-3); printf ("%d",b); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 28 PASSANDO VÁRIOS ARGUMENTOS Freqüentemente uma função necessita de mais de uma informação para produzir um resultado Podemos passar para a função mais de um argumento Ex. 1: float area_retangulo (float largura, float altura){ return (largura * altura); } Ex. 2: float potência (float base, int expoente) { int i; float resultado = 1; if (expoente == 0) return 1; for (i = 1; i <= expoente; i++) resultado *= base return resultado; } USANDO VÁRIAS FUNÇÕES Calcular a seguinte seqüência: S(x, n) = x/1! + x2/2! + x3/3! + ... + xn/ n! Solução: int fat(int n) { int i, resultado = 1; for ( i = 1; i <= n; i ++) resultado *= i; return resultado; } float potência (float base, int expoente) { int i; float resultado = 1; If (expoente == 0) return 1; for (i = 1; i <= expoente; i++) resultado *= base; return resultado; } float serie (float x, int n) { int i; float resultado = 0; for ( i = 1; i <= n; i++) resultado += potência( x, i ) / fat( i ); return resultado; } void main( ) { float x; int termos; printf(" Entre com o numero de termos: "); scanf("%d", &termos); printf(" Entre com o valor de X: "); //x é o valor da base . scanf(" %f”" ,x); printf(" O valor de série = %f", serie(x, termos)); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 29 OBS.: No programa acima relacionado vemos a dependência entre as funções, isto nos informa que a tarefa de resolver a sequência foi dividida em problemas menores dentro das funções, sendo resolvida de forma mais simplificada. Então percebemos que a função facilita nosso trabalho. Note: Uma mesma função pode ser chamada várias vezes para resolver diversos problemas. RECURSIVIDADE A Recursividade é o ato da função chamar a si mesma com a finalidade de resolver determinado problema. A função é recursiva se um comando no corpo da função chama a própria função. Recursão é o processo de definir algo em termos de si mesmo e é, algumas vezes, chamado de definição circular. A idéia por trás da recursividade está em pegar um problema inicialmente grande, sabendo a solução para um problema pequeno, o ato de recursividade é transformar um problema grande em um problema pequeno para que o mesmo seja resolvido através da solução do problema pequeno. Vários problemas já são recursivos naturalmente. O problema do fatorial também pode ser utilizado para demonstrar a recursividade como segue: fat(0) = 1 fat(n) = n (fat(n-1)) para n > 0 0! = 1 1! = 1 * 0! 2! = 2 * 1! 3! = 3 * 2! 4! = 4 * 3! 5! = 5 * 4! ..... int fat( int n ) { if (n == 1) return 1; else return fat(n-1) * n; } O exemplo abaixo demonstra uma recorrência que também é recursiva. t(1) = 1 t(n) = 2 t(n-1) + 3n + 1 para n > 1 t(1) = 1 t(2) = 2 * t(1) + 3 * 2 + 1 t(3) = 2 * t(2) + 3 * 3 + 1 t(4) = 2 * t(3) + 3 * 4 + 1 ... int t( int n ) { if (n == 1) Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 30 return 1; else return 2* t(n-1) + (3 * n) + 1; } main() { int j; printf("“Digite um numero: "); scanf("%d",&j); printf(" O fatorial de = %d e’ %d ",j , f t(j)); printf(" A série de = %d e’ %d",j , t( j)); } ARRANJOS Um Arranjo é uma coleção de variáveis do mesmo tipo que é referenciado por um nome comum. Um elemento específico em uma matriz é acessado por meio de índice. Em C, todos os arranjos consistem em posições contínuas na memória. O endereço mais baixo corresponde ao primeiro elemento e o mais alto, ao último elemento. Um conjunto pode ser composto de uma dimensão, também conhecido como Vetor ou várias dimensões, ou matriz. Ex.: Ler a nota de 3 alunos e calcular a média int nota0, nota1, nota2; printf(“entre com a i nota”); scanf(“%d”, ¬ai ); : : : printf(“média = %f”, (nota0 + nota1 + nota2) / 3)); Arranjos: Unidimensional (VETOR) N-dimensional (MATRIZ) Informalmente: Cada variável é diferenciada por um índice int nota [ 4 ]; Vetorde inteiros nota [ 0 ], nota [ 1 ], nota [ 2 ], nota[ 3 ] Obs.: tamanho n índice 0 a (n - 1) ou ( 0 , 1, 2, 3 ) Inicializando Arranjos Considere uma variável inteira numero Podemos inicializar a variável numero: int numero = 0; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 31 numero = 0; scanf ("%d", &numero); Dado um arranjo int notas[5], podemos inicializá-lo: int notas[5] = {0,0,0,0,0} int notas[] = {0} notas[0] = 0; notas[1] = 0 ... notas [4] = 0; for ( i = 0 ; i < 5; i++) { notas[i] = 0; // ou printf(" Digite uma nota para inicialização"); scanf (" %d ", ¬as [ i ] ); } Obs.: Dado int notas [10] podemos fazer: notas [9] = 5; notas [0] = 50; as demais posições do vetor contêm “lixo” Programa utilizado para cálculo da média de no máximo 40 alunos. #define N_ALUNOS 40 int i; float notas[N_ALUNOS]; /* Removendo os conteúdos inválidos das posições indicadas de memória, colocando nestas posições o zero (0), evitando resultados indesejados. */ void limpeza( ) { for ( i = 0; i < N_ALUNOS; i++ ) notas [ i ] = 0; } /* Inicializa o vetor com os números digitados pelo usuário. */ void inicializa() { for ( i = 0; i < N_ALUNOS; i++ ) { printf (" Entre com a nota %d ", i+1); scanf (" %f ", ¬as[ i ]); } } /* i+1, para que a numeração das notas não inicie com zero (0). Ex.: nota 1, nota 2,...,nota n. */ /* Calcula a média das notas dos alunos. */ float media( ) { float media; for ( i = 0; i < N_ALUNOS; i++ ) { media += notas [ i ]; } return (media / N_ALUNOS); Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 32 } void imprime() { for ( i = 0; i < N_ALUNOS; i++ ) { printf (" %d", notas[i] ); } /* PROGRAMA PRINCIPAL */ main( ) { limpeza(); inicializa(); imprime(); printf ("\n Média = %f \n", media()); } tamanho de um arranjo tem que ser determinado em tempo de compilação. Solução: declarar um arranjo que suporte um número máximo de elementos. #define TAMANHO 100 main( ) { int quantidade, media = 0; float notas [ TAMANHO ]; // quantidade deve ser TAMANHO printf (" Quantas notas devo ler ?”"); scanf("%d", &quantidade); for ( i = 0; i < quantidade; i++) { printf ("Entre com a nota %d",i+1); scanf("%d",¬as[i]); } : : : for ( i = 0; i < quantidade; i++) media += notas [ i ]; : : : } RESULTADOS IMPREVISÍVEIS C não realiza verificação de limites em arranjos. Nada impede o acesso além do fim do arranjo faça sempre que necessário a verificação dos limites ARRANJOS MULTIDIMENSIONAL Um arranjo multidimensional consiste em um arranjo de linhas e colunas. 0 1 2 3 1 2 3 4 5 6 7 8 9 10 11 12 #define linha 3; #define coluna 4; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 33 int matéria [ linha ] [ coluna ]; interpretação : temos 3 linha e 4 colunas; temos 3 vetores de tamanho 4 Agora temos : int i, j, matéria [ linha ] [ coluna ]; for ( i = 0 ; i < linha; i++ ) { printf (“linha = %d”,i+1); for (j = 0; j < coluna; j++) { printf (“coluna = %d”, j+1); scanf (“%d”, matéria[i][j]); } } Inicializando Matrizes dado: #define linhas 3 #define colunas 4 int nota [linhas][colunas]; Uma das maneiras de inicializá-las. int nota[3][4] = {{0,0,0,0}, ...,{0,0,0,0}} nota[0][0] = 0; ... nota[0][3] = 0; : : : nota[2][0] = 0; ... nota[2][3] = 0; Uma outra forma de inicilizá-las de maneira mais eficiente é usando laços for : for(i = 0;i < linhas; i++ ) for(j = 0; j < colunas; j++ ) nota[i][j] = 0; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 34 STRING A linguagem de programação C não existe um tipo de dados string. Este tipo é definido através da utilização de um vetor de caractere, com um caractere especial “ \0 nulo “ indicando o final deste vetor. Um valor nulo é especificado como “\0” e geralmente é zero. Por esta razão, você precisa declarar matrizes de caracteres como sendo um caractere mais longo e de maior string necessária. é uma seqüência de caracteres delimitada por aspas duplas. Ex.: printf("Isto é um teste"); printf("%s",”Isto é um teste”); OBS.: visto pelo compilador: “" Isto é um teste\0"” '\0'’ ( null ) = '0'’ ‘'\0'’indica para as funções o fim de um string.. Variável String matriz do tipo char terminada pelo caractere null ‘\0. cada caractere de um string pode ser acessado individualmente. Ex.: char string[10] = "exemplo"; char string[10] = {"exemplo"}; char string[10] = {'e','x','e','m','p','l','o','\0'}; printf ( "%s", string ); for( i = 0; i < 10; i++) printf ( "%c", string [i]); Lendo Strings scanf () lê o string até que um espaço em branco seja encontrado. main ( ) { char nome[40]; printf(“Digite seu nome: “); scanf(“%s”, &nome[0]); printf(“Bom dia %s”,nome ); } Saída: Digite seu nome: Ciro Gomes Bom dia Ciro Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 35 gets() lê caracteres até encontrar ‘'\n'.’ substitui ‘'\n'’ '\0'.. é a função ideal para ler um string. Exemplo: main ( ) { char nome[40]; printf("Digite seu nome \n"); gets(&nome[0]); printf ("Bom dia %s !",nome); } Saída: Digite seu nome: Ciro Gomes Bom dia Ciro Gomes! Imprimindo Strings printf() puts() complemento de gets() puts() imprime uma única string por vez e cada string impressa por ele termina com um caracter de nova linha ( \n ). Ex.: main ( ) { char nome[40]; printf ( “Digite seu nome: “ ); gets ( &nome[ 0 ] ); puts ( “Bom dia ” ); puts ( nome ); } Saída: Digite seu nome: Ciro Gomes Bom dia Ciro Gomes Lembre-se Sempre que uma função espera receber um apontador podemos passar: o endereço da primeira posição do vetor/matriz o próprio vetor/matriz Exemplo: Observe as equivalências. char nome[40]; gets(&nome[0]) = gets(nome) scanf("%s", nome[0]) = scanf("%s",nome[0]) puts(&nome[0]) = puts(nome) Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 36 main ( ) { char nome[40]; printf ("Digite seu nome: "); gets (&nome[0]); printf ("%s\n", &nome[3]); printf (" %s \n",&nome[0]); printf (" %s \n",nome); } FUNÇÕES DE MANIPULAÇÃO DE STRINGS Função Descrição strlen(s1) Retorna o tamanho de s1. strcpy(s1,s2) Copia s2 em s1. strcat(s1,s2) Concatena s2 no final de s1. strcmp(s1,s2) Retorna 0 se s1 e s2 são iguais; menor que 0 se s1 < s2; maior que 0 se s1 > s2. strchr(s1,ch) Retorna um ponteiro para a primeira ocorrência de ch em s1. Procura uma letra em uma palavra. strstr(s1,s2) Retorna um ponteiro para a primeira ocorrência de s2 em s1. Procura uma palavra em uma frase. strncmp(s1,s2,n) igual strcmp, porém a comparação é feita a partir de n em s1. OBS.: ch = 1 caracter, s1, s2 e n são strings. strlen(s1) retorna o tamanho do string - não conta '\0'. Ex.: main ( ) { char nome[40]; printf ("Digite seu nome:" ); gets ( nome ); printf ("Tamanho = %d", strlen(nome) ); } Saída: Digite seu nome: Ciro Gomes Tamanho = 10 strcat(s1,s2) concatena s2 ao final de s1. dado s1 + s2 tem que caber em s1 + \0, ou seja, o tamanho de s1 teem que ser suficiente para ele e para s2. Ex.: main ( ) { char nome[40]="Ciro ", sobrenome[30] ="Gomes"; strcat(nome,sobrenome); puts (nome); } Saída: Ciro Gomes Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 37 strcmp ( s1, s2 ) Compara dois strings retornando: negativo se s1 < s2; 0 se s1 = s2; positivo se s1 > s2; a comparação é feita por ordem alfabética . main ( ) { char nome[40] = "Ciro", sobrenome[30] = "Gomes"; if (strcmp(nome,sobrenome )) puts ("Os strings são diferentes" ); else puts (" Os strings são idênticos " ); } REGISTROS E ESTRUTURAS Registros são conjunto de dados logicamente relacionados, mas de tipos diferentes. Uma estrutura é uma coleção de variáveis referenciadas por um nome, fornecendo uma maneira conveniente de se ter informações relacionadas agrupadas. Uma definição de 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 ou atributos da estrutura. Uma ficha de cadastro de aluno, precisa-se de atributos que identifique um aluno, um aluno pode ser identificado pelo Nome, Endereço, Identidade, CPF, etc. Estrutura .. /* Mostrando o uso de Estrutura. */ // Definindo o tipo de dado. struct nome_estrutura { char nome[30]; char endereço[30]; char cidade[15]; int idade; char CPF[15]; }var_estrutura ; // var_estrutura é do tipo nome-estrutura. OUTRA FORMA DE DECLARAÇÃO DE ESTRTURA struct nome_estrutura { char nome[30]; char endereço[30]; char cidade[15]; int idade; char CPF[15]; }; criando uma variável do tipo estrutura struct nome_estrutura var_estrutura; Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 38 Note que a declaração termina com um ponto e virgula( ; ). Nome_estrutura identifica essa estrutura de dados e Var_estrutura é a variável do tipo Nome_estrutura. #include <stdio.h> struct tipo_endereco { char rua[20]; int numero; char bairro[20]; char cidade[15]; char estado [2]; char CEP[9]; }; struct nome_estrutura { char nome[30]; struct tipo_endereco ende ; //ende é uma var do tipo tipo_endereço. int idade; char CPF[15]; } var_estrutura ; /* " . " operador de estrutura faz a conexão entre o nome da estrutura e o nome do membro. Ex.: var_estrutura.nome. nome da estrutura nome do membro da estrutura */ void main( void ) { // ler as informações printf("\n Digite seu nome"); gets(var_estrutura.nome); printf("\n Digite nome da rua"); gets(var_estrutura.ende.rua); printf("\n Digite numero da casa"); scanf("%d",&var_estrutura.ende.numero); printf("\n Digite nome do bairro"); fflush(stdin); gets(var_estrutura.ende.bairro); printf("\n Digite idade"); scanf("%d",&var_estrutura.idade); printf("Digite numero do CPF"); fflush(stdin); gets(var_estrutura.cpf); // imprimir as informações. puts(var_estrutura.nome); puts(var_estrutura.ende.rua); printf("%d",var_estrutura.ende.numero); puts(var_estrutura.ende.bairro); printf("%d",var_estrutura.idade); puts(var_estrutura.cpf); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 39 Conjunto de Estruturas Talvez o uso mais comum de estruturas seja em vetor de estruturas. Para declarar um vetor de estruturas, você deve primeiro definir uma estrutura e, então declarar uma variável vetor desse tipo. Para declarar um vetor de estruturas com 500 elementos do tipo nome_estrutura. struct nome_estrutura regs[500] #include <stdio.h> #define lim 2 struct tipo_endereco { char rua[20]; int numero; char bairro[20]; char cidade[15]; char estado [2]; char CEP[9]; }; struct nome_estrutura { char nome[30]; struct tipo_endereco ende; int idade; char CPF[15]; }var_estrutura[lim]; /* No programa abaixo teremos um laço for que será responsável pela repetição de todas as informações contidas neste bloco. */ void main( void ) { int i; for(i=0;i < lim;i++) { // ler as informações printf("\n Digite seu nome"); gets(var_estrutura[i].nome); printf("\n Digite nome da rua"); gets(var_estrutura[i].ende.rua); printf("\n Digite numero da casa"); scanf("%d",&var_estrutura[i].ende.numero); printf("\n Digite nome do bairro"); fflush(stdin); gets(var_estrutura[i].ende.bairro); printf("\n Digite idade"); scanf("%d",&var_estrutura[i].idade); printf("Digite numero do CPF"); fflush(stdin); gets(var_estrutura[i].cpf); } // imprimir as informações. for( i = 0; i < lim; i++) { puts(var_estrutura[i].nome); puts(var_estrutura[i].ende.rua); printf("%d",var_estrutura[i].ende.numero); puts(var_estrutura[i].ende.bairro); printf("%d",var_estrutura[i].idade); puts(var_estrutura[i].cpf); } } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 40 Uniões Imaginemos um caso onde tenhamos um programa muito grande em que precisaremos executá-lo sem que possamos fazer qualquer redução em suas estruturas. Caso pudermos usar o mesmo local de memória para armazenarmos duas variáveis distintas, resolveremos nosso problema. Exemplo: union data { int dia; int mes; int ano; } ; main() { union data d; d.dia = 30; printf(“%d\n”,d.dia); d.mes = 3; printf(“%d\n”,d.mes); printf(“%d\n”,sizeof(d)); } Argumentos argv e argc argc : Tem o número de argumentos contidos nas linha de comando ( necessariamente maior ou igual a um, pois o próprio programa já é considerado um argumento pelo O.S.). argv : É um ponteiro que acomodará os caracteres digitados. /* O número mínimo de argumentos que o programa abaixo aceitára será dois: 1 é o próprio programa executável e o outro é o arquivo solicitado. #include <stdio.h> #include <stdlib.h> void main(int argc, char **argv ) { int x; if ( argc != 2 ) { printf("\n Este comando reg tem 2 parâmetro:"); exit(1); } x = atoi(argv[1]) * 5; // a função atoi tranforma um caracter em inteiro para multiplicar por 5. printf(" Comando = %s Valor = %d",argv[0],x); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 41 Exemplo 1: Este programa recebe 2 parâmetro de linha de comando um nome e um valor e escreve na tela o nome e o valor multiplicado por 5. #include “stdio.h” main( int argc, char *argv ) { char nome[10]; if (arg != 2) { printf(“Digite o Nome do Arquivo e a senha \n”); exit(1); } if ( !strcmp(“spep”,argv[1]) { printf(“ Senha correta \n”); printf(“ Você esta autorizado a utilizar este programa \n”); printf(“ Digite seu nome \n”); scanf(“%s”,nome) printf(“ Obrigado %s por utilizar nosso sistema “,nome \n”); exit(1); } esle { printf(“ Senha INCORRETA \n”); printf(“ Você NÃO esta autorizado a utilizar este sist\n”); exit(1); } Exemplo 2: Este programa recebe 2 parametro o nome e uma senha. Prof.: Ciro M. Santos Programação C/ 2005-1 Versão 0.05 Página 42 PONTEIROS O correto entendimento e uso de ponteiro é crítico para uma programação bem sucedida em C. Há três razões para isso: Primeiro: Os ponteiro fornecem os meios pelos quais as funções podem modificar seus argumentos; segundo: Eles são usados para suportar as rotinas de alocação dinâmica de C, e terceiro: O uso de ponteiros pode aumentar a eficiência de certas rotinas Ponteiros são endereços, isto é, são variáveis que contém um endereço de memória. Se uma variável contém o endereço de outra, então a primeira (o ponteiro) aponta para a segunda. “ pt ” o “ponteiro” aponta para o “inteiro” x Operadores & ( i comercial ) que fornece o endereço de determinada variável. Não confundir com o operador lógico de operações de baixo nível, de mesmo símbolo. Atribui o endereço de uma variável para um ponteiro. * ( asterisco ) que acessa o conteúdo de uma variável, cujo endereço é o valor do ponteiro. Não confundir com o operador aritmético de multiplicação de mesmo símbolo. Devolve o valor endereçado pelo ponteiro. Exemplos ..... main() { int *pont, cont, val; cont = 100; pont = &cont; val = *pont; printf(“%d”,val); /* 100 */ } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 43 main() { char a,b,*p; b = ‘c’; p = &a; *p = b; printf(“%c”,a); /* c */ } main() { int x, y,*px,*py; x = 100; px = &x; /* px tem o endereco de x */ py = px; /* py tem o endereco de x */ y = *py; /* y vale 100, pois recebe o conteúdo de x , através do ponteiro py */ printf(“%d %d”,x, y ); } #include “stdio.h” main() { int i, k, *pi, *pk; char a; i = 2; k = 0; puts(“Qual será o valor de k? “); pk = &k; pi = &i; *pk = i; printf(“para *pk = i, temos k= %d\n”, k); k = *pi; printf(“para k = *pi, temos k= %d\n”,k); } PONTEIROS - CONCEITOS DE ENDEREÇOS Aritmética de Ponteiros São válidas as operações de soma e subtração, sendo que seu resultado depende do tipo de variável apontada pelo ponteiro. Supondo que ... int *p, x; char *q, a; se q = &a; p = &x; e ainda que ... a endereço 100 x endereços 101 / 102 q++ q “ apontará ” para o endereço 101 p++ p “ apontará ” para o endereço 103 incrementa um tipo (*p)++ incrementa o conteúdo do endereço apontado por p. Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 44 Este conceito é particularmente importante no que se refere a matrizes pois como se sabe, matriz nada mais é que um conjunto de variáveis do mesmo tipo, dispostas seqüencialmente em memória. Por conterem endereços, ponteiros permitem apenas as operações de soma e subtração. Supondo que: int i, *pi; ( pi = i ) #2340 char c, *pc; ( pc = c ) #2345 float f, *pf; ( pf = f ) #2350 Supondo ainda que pi, pc e pf apontem para i, c e f que estariam com os seguintes endereços: 2340, 2345 e 2350. Se pc = pc + 1, então pc valerá 2346, pois variáveis caracteres possuem apenas 1 byte. pi = pi + 1, então pi valerá 2342 , pois variáveis inteiras ocupam 2 bytes. pf = pf + 5, então pf valerá 2370 , pois variáveis pt. flutuante ocupam quatro bytes. Velocidade .... O acesso aos elementos da matriz é mais rápido quando feito através de endereços do que seria caso fosse executado pela maneira convencional, porém expressões que envolvam cálculos para se obter um elemento específico da matriz devem ser feitas preferencialmente pelo método convencional, pois expressões complexas envolvendo ponteiros são processadas em velocidade semelhante àquelas feitas pelo modo convencional, que apresenta a vantagem de ser mais facilmente compreendido. MATRIZES E PONTEIROS Em C você pode indexar um ponteiro como se este fosse uma matriz! Exemplo .... main() { int i,*p,vet[] = { 10, 20, 30, 40, 50}; p = vet; for (i=0; i<5; i++) printf(“%d %d \n ”,vet[i],*(p+i)); } main() { int i,*p,vet[5]; for (i=0; i<5; i++) { printf(“Digite o %d elemento”,i); scanf(“%d”,&vet[i]); } p = vet; for (i=0; i<4; i++) printf(“%d %d %d \n ”,vet[i], p[i], *(p+i)); } Passagem de Variáveis ou Valores através Funções Quando desejamos que uma função altere o valor de uma variável da função que a chamou, passamos para a função chamada o endereço desta variável (passagem de parâmetro por referência). Quando somente precisamos do valor da variável e não pretendemos alterá-lo na rotina (passagem de parâmetro por valor), passamos diretamente a variável, conforme visto a seguir: Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 45 Passagem por Valor (a mantém seu valor) int soma( int z) { int x = 5; x = x + z; z = 0; return(x); } main() { int a,r; printf(“Digite um valor: “); scanf(“%d”,&a); r = soma(a); printf(“%d, e %d”,a,r); } Passagem por Referência (a muda seu valor) int soma( int *z) { int x=5; x = x + *z; *z = 0; return(x); } main() { int a,r; printf(“Digite um valor: “); scanf(“%d”,&a); r = soma(&a); printf(“%d, e %d”,a,r); } Uso de ponteiros em funções. swap(int *a, int *b) { int t; t = *a; *a = *b; *b = t; } main() { int a,b; a = 100; b = 20; swap(&a, &b); printf(“A = %d e B = %d “,a,b); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 46 /* procedimento utilizando parâmetro ( POR REFERENCIA ) */ void func100r ( int *x) { *x = *x + 100; } void multMIN(int a, int b, int *mult, int *min) { *mult = a * b; *min = ( a < b)? a: b; } void main ( void ) { int n,x,y,rx,ry, *ptx, pty; /* procedimente utilizando parametro ( POR REFERENCIA ) */ n = 50; func100r(&n); printf(" \n Valor de func100r() = %d",n); x = 3; y = 5; multMIN(x,y, &rx, &ry); printf(" \n Mult %d MIN %d ",rx,ry); x = 3; y = 5; ptx = ℞ pty = &ry; multMIN(x,y, ptx, pty); printf(" \n Mult.. %d MIN.. %d ", *ptx, *pty); } Função que retorna um ponteiro ... #include <stdio.h> main() { int *pt, x ; pt = &x; *pt = 100; printf(“Valor do ponteiro“,*pt); } #include <stdio.h> int *retorno() { int x; return(&x); } main() { int *pt; pt = retorno(); *pt = 100; printf(“ Valor do ponteiro “,*pt); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 47 Entradas e Saídas em Dispositivos - Arquivos A linguagem C não contém nenhum comando de I/O. Todas as operações de I/O ocorrem mediante chamadas a funções da biblioteca C padrão. O padrão C ANSI define um conjunto completo de funções de I/O que pode ser utilizada para ler e escrever qualquer tipo de dado. Streams O sistema de I/O do C fornece uma interface consistente ao programador C, independente do dispositivo real que é acessado. isto é, o sistema de I/O de C provê um nível de abstração entre o programados e o dispositivo utilizado. Essa abstração é chamada de stream e o dispositivo real é chamado de arquivo. O sistema de arquivo de C é projetado para trabalhar com uma ampla variedade de dispositivos, incluindo terminais, acionadores de disco e acionadores de fita. Streams de Texto Uma stream de texto é uma seqüência de caracteres. O padrão C ANSI permite que uma stream de texto seja organizada em linhas terminadas por um caractere de nova linha,o caracteres e nova linha é opcional. Streams Binárias Uma stream binária é uma seqüência de bytes com uma correspondência de um para um. não ocorrendo nenhuma tradução de caracteres. Arquivos Em C, um arquivo pode ser qualquer coisa, desde um arquivo de disco até um terminal ou uma impressor. Você associa uma stream com um arquivo específico realizando uma operação de abertura. Uma vez o arquivo aberto, informações podem ser trocadas entre ele e o seu programa. Funções para manipulação de arquivo: Nome Descrição fclose() Fecha uma fila feof() Devolve se fim de fila ferror() Devolve Verdadeiro se um erro tiver ocorrido fopen() Abre uma fila fprint() Saída fscanf() Entrada ftell() Retorna a distancia inicio/fim a posição atual do arquivo fseek() Procura um byte especificado na fila getc() Lê um caracter na fila outc() Grava um caracter na fila remove() Apaga o arquivo fread() ler uma quantidade de registro em um arquivo binário frwrite() Escreve uma quantidade de registro em um arquivo binário rewind() Reposiciona o ponteiro do Arquivo em seu início Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 48 Tabela códigos para abertura de arquivos: Código Descrição “r” Abre Arquivo de Texto para Leitura “w” Cria Arquivo de Texto para Gravação “a” Anexa a um Arquivo de Texto “rb” Abre Arquivo Binário para Leitura “wb” Cria Arquivo Binário para Gravação “ab” Anexa a um Arquivo Binário “r+” Abre Arquivo de Texto para Leitura/Gravação “w+” Cria Arquivo de Texto para Leitura/Gravação “a+” Abre ou Cria Arquivo de Texto para Leitura/Gravação “r+b” Abre Arquivo Binário para Leitura/Gravação “w+b” Cria Arquivo Binário para Leitura/Gravação “a+b” Abre ou Cria Arquivo Binário para Leitura/Gravação “rt” Idem a “r” “wt” Idem a “w” “at” Idem a “a” “r+t” Idem a “r+” “w+t” Idem a “w+” “a+t” Idem a “a+” Funções Básicas para Manipulação de Arquivo Texto: Função Descrição fclose() Fecha uma fila feof() Devolve se fim de fila fopen() Abre uma fila getc() Lê um caracter na fila putc() Grava um caracter na fila “r” Abre Arquivo de Texto para Leitura “w” Cria Arquivo de Texto para Gravação #include <stdio.h> char ch; void ler ( void ) { if ( ( fp = fopen("c:\saida.txt","r")) == NULL ) { puts("não foi possível abrir o arquivo para leitura"); exit(1); } while ( (ch = getc(fp)) != EOF ) printf("%2c",ch); fclose(fp); } void escreve ( void ) { if ( ( fp = fopen("c:\saida.txt","w")) == NULL ) { puts("não foi possível abrir o arquivo para escrita"); exit(1); } while ( (ch = getchar()) != '.' ) putc(ch,fp); fclose(fp); } void main ( ) { escreve(); ler(); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 49 Funções Básicas para Manipulação de Arquivo Binário: Função Descrição fclose() Fecha uma fila feof() Devolve se fim de fila fopen() Abre uma fila fprintf() Escreve um registro em um arquivo binário tipos básicos ( int, char, ..) fscanf() Ler um registro em um arquivo binário tipos básicos ( int char, ... fread() ler uma quantidade de registro em um arquivo binário fwrite() Escreve uma quantidade de registro em um arquivo binário “wb” Cria Arquivo Binário para Gravação “ab” Anexa a um Arquivo Binário #include <stdio.h> FILE *fp; void escreva2( void ) { int i; float valor; if ( ( fp = fopen("sb2.dat","wb")) == NULL ) { puts("nao foi possivel abrir o arquivo para escrita"); exit(1); } for (i=0;i<5;i++) { printf("\nDigite o salario do aluno"); scanf("%f",&valor); fprintf(fp,"%d %f ",i,valor); } fclose(fp); } void ler2( void ) { float valor; int i; if ( ( fp = fopen("sb2.dat","rb")) == NULL ) { fputs("nao foi possivel abrir o arquivo para escrita",stdin); exit(1); } while ( !feof(fp) ) { fscanf(fb2,"%d %f ",&i,&valor); printf("\n Numero = %d Valor = %5.2f",i,valor); } fclose(fp); } void main ( ) { escreva2(); ler2(); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 50 #include <stdio.h> struct aluno { int código; char nome[10]; int idade; }; FILE *fp; FILE *fpb; struct aluno alu; void lerBinario( void ) { if ( ( fpb = fopen("c:\saidab.txt","rb")) == NULL ) { puts("não foi possível abrir o arquivo para escrita"); exit(1); } while ( (fread(&alu,sizeof(alu),1,fpb)) != NULL ) { puts(alu.nome); printf("Código = %d Idade = %d",alu.codigo,alu.idade); } fclose(fp); } void escreveBinario( void ) { int i; if ( ( fpb = fopen("c:\saidab.txt","wb")) == NULL ) { puts("não foi possível abrir o arquivo para escrita"); exit(1); } for (i=0;i<2;i++) { puts("Digite o codigo do aluno"); scanf("%d",&alu.codigo); puts("Digite o nome do aluno"); fflush(stdin); gets(alu.nome); puts("Digite a idade do aluno"); scanf("%d",&alu.idade); fwrite(&alu,sizeof(alu),1,fpb); } fclose(fp); } void main ( ) { escreveBinario(); lerBinario(); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 51 #include “stdio.h” main(int argc, char *argv) { FILE *in, *out; char ch; if (arg != 3) { printf(“Digite o Nome dos Arquivos\n”); exit(1); } if ((in = fopen(argv[1],”rb”)) == NULL) { printf(“Arquivo origem não existe\n”); exit(1); } if ((out = fopen(argv[2],”wb”)) == NULL) { printf(“Arquivo destino não existe\n”); exit(1); } while (! feof(in)) putc(getc(in),out); /* esta é a cópia propriamente dita */ fclose(in); fclose(out); } // este programa remove.c e executado e recebe um parametro que sera interpretado destro do programa. #include <stdio.h> FILE *arq; void main ( int argv, char **argc) { char str[50]; if ( argv > 1 ) { if ( argv == 3 ) { remove(argc[1]); printf("\n Opcao %s para remover arquivo", argc[2]); if ( (arq = fopen(argc[1],"r")) == 0 ) printf("\n Remocao do aq %s sucesso", argc[1]); } else { arq = fopen(argc[1],"r"); if ( arq ) { fgets(str,50,arq); printf(" arquivo %s aberto com sucesso ", argc[1]); printf(" conteudo : %s ",str); } else { arq = fopen(argc[1],"w"); printf("\n arquivo %s criando com sucesso ", argc[1]); fprintf(arq,"\n arquivo %s criando ", argc[1]); } } } else printf(" parametros incorreto entre novamente"); fclose(arq); } Prof.: Ciro M. Santos Programação C / 2005-1 Versão 0.05 Página 52 Programa para leitura de nome de arquivo atraves de uma função que r ecebe este nome por referencia. #include <stdio.h> #define MAX 10 FILE *fp; void ler (int M[MAX][MAX], int *lim, char **arquivo) { int i, v, a, x, y; printf(“\n %s”,*arquivo); if ( ( fp = fopen(*arquivo,”r”) ) == NULL ) { printf(“\n Arquivo não foi encontrado”); exit(1); } fscanf(fp, “%d %d \n”,&v, &a); for ( i=0; i < a; i++) { fscanf(fp, “%d %d \n”,&x, &y); M[x-1][y-1] = 1; M[y-1][x-1] = 1; } *lim = v; } void imprime ( int M[MAX][MAX], int lim ) { int i, j; for ( i=0; i < lim; i++) { printf(“\n”); for ( j=0; j < lim; j++) { printf(“%3d”, M[i][j]); } } int main ( int argv, char **argc ) { int M[MAX][MAX]; int lim, i, j; if ( argv != 2 ) { printf(“\n parametros incorretos”); printf(“\n digite o nome do programa
Compartilhar