Baixe o app para aproveitar ainda mais
Prévia do material em texto
PROGRAMAÇÃO ESTRUTURADA G A B R I E L A L V E S , G U I L H E R M E M E N D E S , I G O R M O N T E I R O & S I L V A N O M O N T E I R O Este e-book tem como propósito conhecer a programação estruturada com a linguagem C. Os assuntos abordados aqui são vistos de forma introdutória/básica, mas são de bom proveito para quem está começando a ver a programação mais estrutural. Bons estudos! Uma estrutura de dados composta homogênea, ou vetor, é um arranjo de elementos (dados) armazenados na memória do computador, sendo estes dados organizados de forma eficiente um após o outro, sob um mesmo identificador, cujas regras são as mesmas para criar um identificador de uma variável simples, que possui capacidade de guardar somente um valor. Um vetor é uma estrutura de dados homogênea que pode ser acessado de forma aleatória (qualquer posição que seja necessário). Deve-se se atentar a algumas regras na criação e utilização de um vetor: Todos valores são do mesmo tipo de dado (homogênea) Exemplo: todos os valores devem ser do tipo "INT" ou "FLOAT" por exemplo. Possui um único nome (identificador da variável) Sintaxe: Declaração => tipo nomeDoVetor[tamanho]; Preenchimento => tipo nomeDoVetor[tamanho] = {valor1, ..., valorn}; "tipo": Refere-se ao tipo de dado(int, char, etc); "nomeDoVetor": Identifica o nome do vetor; "[tamanho]": Quantidade de elementos que o vetor armazenará; "{valor1, ..., valorn}": lista de valores a serem armazenados, sendo um para cada posição. Vetor é uma variável composta homogênea unidimensional porque tem somente uma dimensão, ou seja, cresce somente em um sentido. Já uma matriz corresponde a uma variável composta homogênea multidimensional, pois ela pode crescer em vários sentidos. Ela pode variar de matriz bidimensional até N-dimensional, ou seja, projeta de 2 ou mais direções. Para entendermos uma matriz bidimensional (duas dimensões), será utilizado o cenário de uma plateia de um teatro. O teatro é formado por um palco e uma plateia de 20 cadeiras. Esta plateia é composta por cinco fileiras de quatro cadeiras ou quatro arquibancadas de cinco cadeiras. Fazendo outra comparação para haver uma melhor compreensão, iremos utilizar novamente o cenário de um edifício, só que, agora, cada andar terá vários apartamentos. Digamos que um edifício tenha três apartamentos por andar, sendo quatro andares. Sintaxe: Declaração => tipo nomeDaMatriz[quantLinhas] [quantColunas]; Preenchimento => tipo nomeDaMatriz[quantLinhas][quantColuhas] = {{x1,y1}, ..., {xn,yn}}; Observação: tanto para percorrer vetor e matriz, é necessario usar laços de repetição. Veja os exemplos: Um edifício, em que, cada andar terá vários apartamentos. Digamos que um edifício tenha três apartamentos por andar, sendo quatro andares. E no terceiro apartamento do segundo andar tem 4 pessoas. Represente isso usando uma matriz Neste exemplo, primeiramente foi declarado a matriz, com o numero se andares como sendo as linhas, e o numero de quartos como as colunas. Na segunda linha povoamos apenas o apartamento em que havia pessoas. Uma fila para conquestar umpremio num parque de diversões esta cheia de participantes, cada uma com seu determinado numero de pontos. O primeiro esta com 45 pontos, o segundo esta com 60, o terceiro com 30, e o quarto com 54. Monte um vetor representando as posiçoes de cada participante com seus respectivos pontos. Nesse exemplo declaramos e povoamos o vetor ao mesmo tempo, esse tipo de solução tam bem é possivel, dependendo da situação Faça um programa para gerar automaticamente números entre 0 e 99 de uma cartela de bingo. Sabendo que cada cartela deverá conter 5 linhas de 5 números, gere estes dados de modo a não ter números repetidos dentro das cartelas. O programa deve exibir na tela a cartela gerada. Faça um programa para corrigir uma prova com 10 questões de múltipla escolha (a, b, c, d ou e), em uma turma com 3 alunos. Cada questão vale 1 ponto. Leia o gabarito, e para cada aluno leia sua matrícula (número inteiro) e suas respostas. Calcule e escreva: Para cada aluno, escreva sua matrícula, suas respostas, e sua nota. Escreva também o percentual de aprovação, assumindo média 7.0. Faça um programa que leia dois vetores de 10 elementos. Crie um vetor que seja a intersecção entre os 2 vetores anteriores, ou seja, que contém apenas os números que estão em ambos os vetores. Não deve conter números repetidos. Peça ao usuário para digitar dez valores numéricos e ordene por ordem crescente esses valores, guardando-os num vetor. Ordene o valor assim que ele for digitado. Mostre ao final na tela os valores em ordem. O ASCII é um código que foi proposto como uma solução para unificar a representação de caracteres alfanuméricos em computadores. Antes de 1960 cada computador utilizava uma regra diferente para representar estes caracteres e o código ASCII nasceu para se tornar comum entre todas as máquinas. A tabela de caracteres ascii, possui o total de 127 caracteres, sendo do 0 ao 33, caracteres que não podem ser impressos, do 34 ao 126 podem. Os intervalos mais importantes para se decorar são os de letras. Eles são muito usados para criação de funções de transformação de texto, por exemplo. intervalo de 65 a 90 representam as letras MAIÚSCULAS. intervalo de 97 a 122 representam as letras MINÚSCULAS. Ao trabalhar com os caracateres referentes às letras, você vai se deparar com problemas como " transforme 'a' em 'A'", e nesse caso você não precisa se preocupar, a uma dica para este caso: A diferença entre a mesma letra maiúscula e minúscula é 32. Ou seja se quiser transformar "a" para "A" você diminui, caso contrario. Como é mostrado a seguir: Receba seu primeiro nome minúsculo e transforme apenas as 3 primeiras letras em maiúsculo: Primeiro declare a variável do tipo vetor e a receba o valor, depois percorra esse nome com uma estrutura de repetição e identifique as três primeiras letras e faça a transformação: ATENÇÃO Se você está atento perceberá que apesar do código funcionar, ele está parcialmente correto pois para nomes menores de 3 caracteres irá imprimir lixo ( algo que não era pra ser impresso). Isso se dá pelo fato de que como alocamos um vetor de 10 espaços, qualquer nome com menos que isso irá sobrar. Para resolver, é necessário colocar manualmente um caractere '\0' no fim do vetor para designar o fim ou pode-se usar a biblioteca Strings nos casos de manipulação de textos. Com o "\0": Faça um programa que recebe uma data no formato xx/xx/xxxx e verifique se é uma data que está no formato e também verifique se a data existe ou não. (faça a verificação dos caracteres usando a tabela ASCII). Faça um programa que recebe um texto e altere cada caractere do texto pela letra seguinte a cada uma. (use ASCII) Faça um programa que recebe um nome completo e transforme as letras iniciais de cada nome em maiúsculas e o restante em minúsculas. Se o nome possuir um caractere que não é letra ou espaço, avise ao usuário e termine o programa. Crie um programa que receba um texto e converta cada letra em um número, e some todos esse número. Ao final mostre o valor total da soma. A diretiva #define é a construção da linguagem de programação que especifica como o compilador ou montador deve processar o código fonte. No caso, ela permite definir constantes sem consumir memória durante a execução e também não necessitam do atributo "=". As constantes que são definidas podem ser desde uma variável comum, protótipo de função, até trechos grandes de código. Vamos aos exemplos: Trechos de código: Função: STRINGS Uma string em C nada mais é do que um vetor de caracteres. Porém, podemos dizer que outra característica que as identifica é que , obrigatoriamente um dos caracteres do vetor deve ser o caractere nulo, ou seja, o '\0' que deve ser vir após o último caractere da string. Assim como vimos em codificação ASCII, uma string é declarada e lida da seguinte forma: Porser um vetor de caracteres, não se pode igualar as variáveis como normalmente é feita, por exemplo: Como o processo de mexer com textos é repetitido nos ambientes de desenvolvimento, a linguagem possui a biblioteca string.h que possui várias funções de manipulação de strings prontas para uso. Vejamos algumas delas: gets (nome_da_string): A função gets() lê uma string do teclado. fgets (nome_da_string, tamanho_buffer, stdin): A função fgets() lê uma string até que um caracter de nova linha seja lido ou tamanho-1 caracteres tenham sido lidos. Se o caracter de nova linha ('\n') for lido, ele fará parte da string, o que não acontecia com gets. A string resultante sempre terminará com '\0'. puts(nome_da_string); A função puts() escreve uma string na saída padrão. strcpy(string_destino, string_origem); A função strcpy() copia o conteúdo da string_origem para a string_destino. strlen(string): A função strlen() retorna o comprimento da string fornecida. O terminador nulo não é contado. strcat(string_destino, string_origem): A função strcat() concatena a string_destino com a string_origem. A string_origem permanecerá inalterada e será anexada ao fim da string_destino. strcmp(string1, string2): A função strcmp() compara a string1 com a string2. Se as duas forem idênticas a função retorna zero. Se elas forem diferentes a função retorna não-zero. Construa um programa que leia duas strings fornecidas pelo usuário, através da entrada padrão, verifique se estas possuem o mesmo tamanho, caso possuam, as compare. Se forem iguais, retorne uma mensagem na saída padrão indicando este fato. Caso não possuam o mesmo tamanho, concatene-as e retorne o resultado desta operação na saída padrão. Crie um programa que calcula o comprimento de uma string (não use a função strlen). Construa um programa que leia duas strings fornecidas pelo usuário e verifique se a segunda string lida esta contida no final da primeira, retornando o resultado da verificação. Faça um programa que, dada uma string, diga se ela é um palíndromo ou não. Lembrando que um palíndromo é uma palavra que tenha a propriedade de poder ser lida tanto da direita para a esquerda como da esquerda para a direita. Crie um programa que conta o total de palavras de um texto. Lembre-se de verificar casos de duplicidade consecutiva do caractere branco ' ', ou seja, que ocorra mais de uma vez seguida. Funções são o bloco de construção de C e o local onde toda a atividade do programa ocorre. Elas são uma das características mais importantes de C. Sua declaração é: TIPO NOME_DA_FUNÇÃO (PARÂMETROS) { CORPO DA FUNÇÃO } Exemplo: Outro ponto importante de destacar é que existe mais de um tipo de se chamar uma função, chamada por Valor e por Referência. Um exemplo de chamada por referência com ponteiro, é necessário declarar os parâmetros como do tipo ponteiro: C usa a chamada por valor para passar argumentos em geral, isso significa que você não pode alterar as variáveis usadas para chamar a função. Aqui podemos ver que há um protótipo de função declarado como "void display (int num[10]);" é colocado dessa forma para que ao iniciar o código, todos os protótipos sejam pré carregados , para que assim, caso uma função dependa de outra, não haja problemas, todas as funções são lidas previamente ao compilar o código. Implemente a função primo que retorna 1 se o valor passado como parâmetro for primo, e 0 caso contrário. Imprima o resultado após receber o valor. Faça uma função que receba um número inteiro e positivo N como parâmetro e retorne a soma dos N números inteiros existentes entre o número 1 e esse número. Escreva uma função que dado um número real passado como parâmetro, retorne a parte inteira e a parte fracionaria deste número. Escreva um programa que chama esta função. Crie uma função que calcule o Nº da sequência de fibonacci. Nº deverá ser inserida pelo usuário. (pesquise o que é a sequência de fibonacci caso não saiba) Poteiros se tratam de variáveis que armazenam o endereço de memória de outra variável que foi armazenada na memória RAM e que possuem tipo também. Uma característica de um ponteiro é que antes do nome da variável sempre possui um "*". Sua declaração é a seguinte: TIPO_VARIAVEL *NOME_VARIAVEL Exemplo: Outro ponto importante de destacar é o operador & pois é ele fornece o endereço de memória de uma variável. Por exemplo, se eu quiser armazenar o endereço de A em *B: Caso você queira modificar o valor da variável pelo ponteiro, basta fazer: Os ponteiros são geralmente usados quando se quer acessar uma variável mesmo não estando no escopo onde está sendo alterado, como em funções: Se você rodar o código acima, perceberá que mesmo não fazendo a alteração de a e b na main, foi possível fazer a operação visto que a o valor foi passado para por referência. Escreva uma função que receba um vetor de inteiros, uma variável "min" e outra "max" do tipo ponteiro que estarão guardando o endereço das variáveis na main. Primeiro declare o protótipo da função: próximo passo é escrever o comportamento principal do programa, a main: Por último, a função: Implemente uma função que calcule a área da superfície e o volume de uma esfera de raio R. Essa função deve obedecer ao protótipo: void calc_esfera(float R, float *area, float *volume); Elabore uma função que receba duas strings como parâmetros e verifique se a segunda string ocorre dentro da primeira. Use aritmética de ponteiros para acessar os caracteres das strings. Crie um programa para manipular vetores. O seu programa deve implementar uma função chamada inverte_vetor, que recebe como parâmetro dois vetores V1 e V2, ambos de tamanho N. A função deve copiar os elementos de V1 para V2 na ordem inversa. Protótipo: int inverte_vetor(int *v1, int *v2, int n); Crie uma função que receba como parâmetros três vetores de inteiros: x1, x2 e x3. A função deverá armazenar em x3 a UNIÃO de x1 e x2, e retornar quantos elementos foram utilizados em x3. protótipo: int uniao(int *x1, int *x2, int *x3); Assim como na maioria das linguagens de programação, em C também existe o conceito de recursividade. Recursividade nada mais é de que uma função fazendo a chamada de si mesmo. A recursividade tem como benefício principal, a criação de código menores, e mais eficientes. Entretanto, quando feito de uma maneira incorreta, torna o programa lento e pode consumir muita memória do computador. Por isso, todo cuidado é pouco ao se fazer funções recursivas. A primeira coisa a se providenciar é um critério de parada. Este vai determinar quando a função deverá parar de chamar a si mesma. Isto impede que a função se chame infinitas vezes. Uma rotina que pode geralmente ser simplificada com a recursividade pode ser calcular o fatorial que nada mais é do que a multiplicação de todos os números de uma quantidade especificada. por exemplo: fatorial de 5 = 5*4*3*2*1 ---------- sempre até o número 1. O código desse problema, na forma estrutural, se faz da seguinte forma: O código a seguir é a versão do de cima só que aplicando recursividade. Logo depois na página de exemplo você entenderá melhor. Recursividade para achar o fatorial de um número: O código mostrado anteriomente foi esse: A condição de parada é o número ser maior que 1, senão ele retorna 1. Depois vemos que o trecho de código onde realmente ocorre a recursividade. Esse trecho pode ser interpretado da seguinte forma, vamos usar 5 para o N como exemplo: retorne 5 x fat (5-1) , ou seja seu anterior. Só que o programa precisa saber o fatorial do anterior, então novamente a função chama a sí mesma, veja o exemplo: fat(5) = 5 x fat(4) = ? fat(4) = 4 x fat(3) = ? fat(3) = 3 x fat(2) = ? fat(2) = 2 x fat(1) = ? fat(1) = 1 Como o fatorial de 1 é a base, é retornado o valor 1. Então, o processo inverso é feito, já que agora é possível calcularo fatorial de cada número: fat(5) = 5 x 24 = 120 ( resultado final) fat(4) = 4 x 6 = 24 fat(3) = 3 x 2 = 6 fat(2) = 2 x 1 = 2 fat(1) = 1 Faça a função da sequência de fibonacci usando recursividade. Leia um vetor de números e realize a soma de todos eles usando recursividade. Structs, também conhecidas como Registros, definem tipos de dados que agrupam variáveis sob um mesmo tipo de dado. A ideia de usar uma struct é permitir que, ao armazenar os dados de uma mesma entidade, isto possa ser feito com uma única variável. Por exemplo, se for preciso armazenar a altura, o peso e a idade de uma pessoa, pode-se criar uma struct chamada Pessoa e agrupar os dados em um único tipo de dado, conforme o exemplo a seguir. Aos dados agruados em uma struct dá-se o nome de campos(fields). Após o tipo ser declarado, pode ser usado como qualqer outro tipo de variável (int, float, char por exemplo). Como vemos no exemplo abaixo: Para acessar os campos de uma struct, usa-se a sintaxe NomeDaVariavel.NomeDoCampo, conforme o exemplo a seguir. Construa uma struct para conter os dados de um funcionario de uma empresa. Repare que foi utilizado varios tipos de variaveis, int, double, char. Esta é umas das vantagens de um Struct, podesse guardar dentro de uma unica variável diferentes tipos de variáveis. Agora atribua valores para esta struct: Faça um programa que leia os dados de 10 alunos (Nome, matricula, Media Final), armazenando em um vetor. Uma vez lidos os dados, divida estes dados em 2 novos vetores,o vetor dos aprovados e o vetor dos reprovados, considerando a media míınima para aprovacão como sendo 5.0. Exibir na tela os dados do vetor de aprovados, seguido dos dados do vetor de reprovados. Crie uma struct que tenha nome, idade e sexo de pessoas. Leia dados de 5 pessoas e busque por qual tem a maior e menor idade. Ao final mostre o nome e idade da pessoa mais velha e mais nova. Crie uma struct de notícias, tendo nela titulo, autor, corpo da mensagem. Cadastre 5 notícias, se houver algum dado em branco ou o título ser igual a um outro existente, peça pra inserir novamente. Ao final mostre todas as noticias. Utilizando uma estrutura, fac ̧a um programa que permita a entrada de nome, endereço e telefone de 5 pessoas e os imprima em ordem alfabetica. A declaração de variáveis pode ser muito custosa para o computador. Ao declarar uma variável para guardar um nome , você define o vetor com 100 posições mas não as usa completamente, pode ser um exemplo. Por isso, existe o conceito de alocação dinâmica: permitir solicitar memória em tempo de execução, ou seja, só vai alocar memória quando necessitar. As funções que contribuem para a aalocação estão presentes na biblioteca stdlib.h. Algumas são: Função para alocar memória: malloc(num_bytes) Retorna o endereço de memória da região alocada ou retorna zero se não for possível alocar. Função para liberar a memória: free(endereco_regiao_alocada) A região fica disponível para outras variáveis/alocações. Função para realocar a memória: realloc(endereco_regiao_alocada, quantidade_para_realocar * num_bytes) permite modificar o tamanho de uma região alocada, conservando os dados previamente armazenados. No caso de um aumento de tamanho, realloc tenta utilizar bytes adjacentes à região já alocada, mas caso não seja possível, uma nova região é alocada, e os dados armazenados na antiga região são copiados Antes de executar nosso código com alocação dinâmica, temos que fazer uma modificação, já que por padrão a função de alocação retorna um valor void(vazio), precisamos definir o tipo de dado que queremos que seja retornado, por exemplo: (int *) malloc (5). Vejamos que há o "(int *)" antecedendo a função malloc, que está alterando o tipo de dado que será retornado. Aloque um ponteiro do tipo inteiro, verifique se foi alocado, atribua o valor 3 ao espaço e depois libere a memória: Aloque um ponteiro do tipo de registro , verifique se foi alocado, atribua o valor 3 ao espaço referente à idade e depois libere a memória: Aloque um ponteiro do tipo inteiro para guardar 1 vetor de 3 casas , verifique se foi alocado, atribua os valores ao vetor e depois libere a memória: Aloque um ponteiro do tipo inteiro para guardar 1 vetor de 3 casas , verifique se foi alocado, atribua os valores ao vetor, depois realoque o ponteiro para guardar 4 ao invés de 3 e em seguida repita o processo de verificar se foi possível alocar, atribua valor ao último item do vetor e por último libere a memória da variável. Crie um vetor de registros alocado dinamicamente para diversos alunos contendo as informações: nome, média e faltas. Em seguida, imprima as informações lidas na ordem decrescente das médias dos alunos. crie um vetor alocado dinamicamente de acordo com a quantidade informada pelo usuário e zere os valores menores que 5. Construa um programa (main) que aloque em tempo de execução (dinamicamente) uma matriz de ordem m x n (linha por coluna), usando 2 chamadas a função malloc. Agora, aproveite este programa para construir uma função que recebendo os parametros m e n aloque uma matriz de ordem m x n e retorne um ponteiro para esta matriz alocada. Crie ainda uma função para liberar a área de memória alocada pela matriz. Finalmente, crie um novo programa (main) que teste/use as duas funções criadas acima. Crie uma função que receba como parâmetros dois vetores de inteiros, v1 e v2, e as suas respectivas quantidades de elementos, n1 e n2. A função deverá retornar um ponteiro para um terceiro vetor, v3, com capacidade para (n1 + n2) elementos, alocado dinamicamente, contendo a união de v1 e v2. Por exemplo, se v1 = {11, 13, 45, 7} e v2 = {24, 4, 16, 81, 10, 12}, v3 irá conter {11, 13, 45, 7, 24, 4, 16, 81, 10, 12}. FIM
Compartilhar