Universidade Estadual do Maranhão Curso de Engenharia da Computação Mestrado em Engenharia da Computação e Sistemas Notas de Aulas Sub-rotinas Prof. Dr. Luís Carlos Costa Fonseca São Luís – 2013 Universidade Estadual do Maranhão Curso de Engenharia da Computação Mestrado em Engenharia da Computação e Sistemas Geralmente, problemas complexos exigem algoritmos complexos, mas sempre é possível dividir um problema grande em problemas menores. Assim, cada subproblema pode ter um algoritmo mais simples chamado de sub-rotina. Quando uma sub-rotina é chamada por um programa principal, ela é executada e, ao seu término, o controle de processamento retorna automaticamente para a primeira linha de instrução após a linha que efetuou a chamada. Também é possível dividir uma sub-rotina em várias outras sub-rotinas (recursividade). Variáveis Globais e Locais As variáveis utilizadas em programas podem ser de dois tipos: globais e locais. Globais: são declaradas na seção de declaração do programa principal. Isso permite que essas variáveis possam ser empregadas em todo o programa, inclusive dentro das sub-rotinas, pois todo o programa é capaz de “enxergálas”. Locais: são declaradas na seção de declaração da sub-rotina, fazendo que somente essa sub-rotina possa utilizá-las. O restante do programa não reconhece essas variáveis. Passagem de Parâmetro Os parâmetros têm por finalidade servir como um ponto de comunicação entre uma sub-rotina e o programa principal, ou entre sub-rotinas. A passagem de parâmetro é a forma pela qual as sub-rotinas recebem valores de outras sub-rotinas. Os parâmetros funcionam como se fossem variáveis locais e são declarados normalmente entre parênteses, ao lado do nome da função/procedimento. Na declaração dos parâmetros, devemos definir seu tipo e o nome que ele terá dentro da referida sub-rotina. Esses parâmetros podem ser passados de duas formas: por valor e por referência. void verifica_valor(int valor){ } No exemplo em C, o procedimento verifica_valor recebe um parâmetro inteiro chamado valor. A palavra void no início da declaração do cabeçalho indica que esse procedimento não retornará valor algum. Universidade Estadual do Maranhão Curso de Engenharia da Computação Mestrado em Engenharia da Computação e Sistemas Ao chamarmos um procedimento, devemos passar um valor do mesmo tipo do solicitado na definição do parâmetro. Esse valor pode ser absoluto ou pode estar em uma variável. Exemplo: A seguir, o procedimento definido anteriormente está sendo chamado e o valor 5 está sendo enviado, para ser recebido pelo parâmetro valor: verifica_valor(5); ou int v = 5; verifica_valor(v); variável v. //Utilizando o valor acumulado na Importante: quando enviamos um valor, apenas indicamos o próprio valor ou o nome da variável que o contém, ao passo que, quando declaramos um parâmetro, devemos indicar seu tipo. Caso o subprograma retorne um valor, trata-se de uma função, cuja sintaxe é apresentada a seguir: int soma(int a, int b){ return a + b; } No exemplo apresentado, a função chamada soma retorna um valor inteiro (indicado pela palavra integer no final do cabeçalho da função). Esse valor é retornado pelo nome da função, isso se dá em C pelo uso da palavra reservada return. Passagem de Parâmetro por Valor Esse foi o tipo de passagem de parâmetro apresentado nos exemplos anteriores, nos quais apenas um valor entra na função por meio de um parâmetro e este pode ser utilizado somente pela função. Isso significa que a função não pode alterar o valor passado, mandandoo de volta para quem chamou a função. Para que isso ocorra, é necessário que se utilize passagem de parâmetro por referência. Passagem de Parâmetro por Referência Universidade Estadual do Maranhão Curso de Engenharia da Computação Mestrado em Engenharia da Computação e Sistemas Nesse tipo de passagem de parâmetro, o que é recebido não é apenas o valor, mas a variável enviada, ou seja, sua localização na memória. Isso possibilita que a função acesse essa posição de memória, utilize e altere seu conteúdo. A linguagem C recebe diretamente o endereço de memória do argumento e trabalha nessa posição de memória, acessando e trabalhando diretamente na posição de memória do argumento passado. O resultado final é semelhante aoda passagem de parâmetro por referência, tratando-se apenas de uma diferença conceitual. Para que uma função em C possa acessar a posição de memória do argumento passado, utiliza-se um parâmetro ponteiro. Porém, se o argumento a ser passado já é um ponteiro, define-se o parâmetro como ponteiro de ponteiro, conforme o exemplo a seguir: void nova_arvore(TNo no, TArvore **arv){ } Porém, ao declararmos um parâmetro como ponteiro de ponteiro, devemos utilizar o operador * (asterisco) sempre que for utilizado o parâmetro, indicando o conteúdo da referida posição de memória, conforme o exemplo a seguir: void nova_arvore(TNo no, TArvore **arv){ (*arv) = (TArvore*)malloc(sizeof(TArvore)); (*arv)->reg = no; (*arv)->esq = NULL; (*arv)->dir = NULL; } Como passar os argumentos no momento da chamada dessa função? Nos parâmetros que são ponteiros, se o argumento não for uma variável ponteiro, deve-se utilizar o operador & para fornecer seu endereço de memória. Se o parâmetro for ponteiro de ponteiro e o argumento apenas um ponteiro, também é necessário empregar o operador & no argumento passado. Exemplo de chamada da função citada anteriormente: nova_arvore(no, &dicionario); Neste exemplo, o parâmetro no está sendo passado por valor, enquanto o parâmetro dicionário está sendo passado por referência. Universidade Estadual do Maranhão Curso de Engenharia da Computação Mestrado em Engenharia da Computação e Sistemas Exercícios 1. A mediana de um vetor de números é o elemento m do vetor, tal que metade dos números restantes no vetor é maior ou igual a m e metade é menor ou igual a m, se o número de elementos no vetor for ímpar. Se o número de elementos for par, a mediana será a média dos dois elementos, m1 e m2, tal que metade dos elementos restantes é maior ou igual a ml e m2, e metade dos elementos é menor ou igual a m1 e m2. Escreva uma função em C que aceite um vetor de números e retorne a mediana dos números no vetor. 2. A MODA de um vetor de números é o número m no vetor que é repetido com maior freqüência. Se mais de um número for repetido com freqüência máxima igual, não existirá uma moda. Escreva uma função em C que aceite um vetor de números e retorne a moda ou uma indicação de que a moda não existe. 3. Uma matriz quadrada inteira é chamada de "quadrado mágico" se a soma dos elementos de cada linha, a soma dos elementos de cada coluna e a soma dos elementos das diagonais principal e secundária são todos iguais. Exemplo: A matriz abaixo representa um quadrado mágico: 8 4 3 0 5 10 7 6 2 Escrever uma função que verifica se uma matriz de n linhas e colunas representa um quadrado mágico