Na Secção 9.3. vimos um excerto de código que imprime os elementos de um array de inteiros.
Por ser uma ação muito usual nos programas que vamos fazer neste curso, pois é uma forma de irmos verificando o efeito das ações dos nossos programas, vamos criar um método que, dado um qualquer array de inteiros, imprime-o no standard output.
x/**
* Imprime os elementos de um dado vetor de inteiros no standard output
* @param v - O vetor a imprimir
* @requires v != null
*/
static void imprimeVetor(int[] v) {
for (int i = 0 ; i < v.length ; i++) {
System.out.print(v[i] + " ");
}
}
Como não sabemos nada acerca do array, a não ser que os seus elementos são inteiros, temos que usar o seu atributo length
para conhecermos quantos elementos tem.
O método main
seguinte cria um array com oito inteiros aleatórios no intervalo [0,10], usando a função vetorDeAleatorios
da secção anterior, e imprimem esses valores no standard output, invocando o procedimento imprimeVetor
.
xxxxxxxxxx
public static void main (String [] args) {
Random meuGerador = new Random();
int[] valores = vetorDeAleatorios(8, 10, meuGerador);
imprimeVetor(valores);
}
O método imprimeVetor
não modifica os elementos do array.
Experimente executar o programa completo. Repare no estado da memória em várias fases da execução:
No fim da execução da função vetorDeAleatorios
, na altura de executar a instrução return vetor;
,
gerador
da função referencia o mesmo objeto que a variável meuGerador
do main
, vetor
.Quando a instrução int[] valores = vetorDeAleatorios(8, 10, meuGerador);
acaba de ser executada, o conteúdo da variável valores
, do main
, é uma referência ao mesmo array que foi criado e devolvido pela função vetorDeAleatorios
No início da execução do método imprimeVetor
, o seu parâmetro v
contém uma cópia do conteúdo da variável valores
, do main
, que é uma referência ao array já existente.
Já depois do método imprimeVetor
ter sido executado, o conteúdo da variável local valores
, do main
, tem exatamente o mesmo conteúdo que tinha antes da invocação do método.
Em muitas ocasiões precisamos de calcular o maior ou menor valor de um dado conjunto de valores. Para calcular, por exemplo, o máximo valor contido num array de inteiros, temos que percorrer todos os elementos do array e determinar qual é o maior.
Como não conseguimos olhar para todos os elementos de um array ao mesmo tempo, temos que ir um a um e tentar perceber se o valor dele é importante ou não para o nosso objetivo. O valor de um elemento é importante se for maior do que todos os que já inspecionámos até lá chegar.
Se for maior que todos os outros que já inspecionámos, então ele passa a ser "o maior que vimos até agora" e é esse valor que deverá ser usado quando inspecionarmos o elemento seguinte do array.
No fim, quando já inspecionámos todos os elementos do array, o máximo será o valor do atual "o maior que vimos até agora".
Só falta decidir que valor terá esse "o maior que vimos até agora" logo no início, quando ainda não inspecionámos nenhum elemento do array. O que podemos decidir é que, quando inspecionamos o elemento de índice 1 do array, "o maior que vimos até agora" é o elemento de índice zero, o primeiro elemento do array.
Segue-se uma solução:
xxxxxxxxxx
/**
* O maximo de um dado vetor de inteiros
* @param v - O vetor em questao
* @requires v != null && v.length > 0
*/
static void maximo(int[] v) {
int maiorAtehAgora = v[0];
for (int i = 1 ; i < v.length ; i++) {
if (v[i] > maiorAtehAgora){
maiorAtehAgora = v[i];
}
}
return maiorAtehAgora;
}
Repare na pré-condição. Além de exigir que o parâmetro v
tenha um valor diferente de null
, precisamos também de exigir que o array tenha pelo menos um elemento (v.length > 0
) – não tem sentido calcular o máximo de um vetor vazio, além de que iria dar erro de execução quando, na primeira instrução do corpo do método tentássemos aceder ao elemento v[0]
.
Como um parâmetro de tipo array recebe uma referência a um objeto, então é possível modificar esse objeto através dessa referência. Há casos em que isso é desejável.
Para um dado array v
e um dado valor do seu parâmetro val
, o método seguinte altera para o valor val
cada elemento do array v
que tenha um valor inferior a val
.
xxxxxxxxxx
/**
* Altera os elementos de um dado vetor de inteiros
* que sao menores que um dado valor para esse valor
* @param v - O vetor a considerar
* @param val - O valor de referencia
* @requires v != null
*/
static void alteraValoresInferiores (int[] v, int val) {
for (int i = 0 ; i < v.length ; i++) {
if(v[i] < val) {
v[i] = val;
}
}
}
A cada invocação do método para um dado vetor e um dado inteiro, é copiada para o parâmetro v
a referência ao vetor dado e para o parâmetro val
o valor do inteiro dado; de seguida, todos os elementos desse vetor que tinham valores inferiores ao dado inteiro ficam com um valor igual a esse inteiro.
As instruções seguintes criam um array com oito inteiros aleatórios no intervalo [0,20] e de seguida alteram os valores desse array que são menores que 10 para o valor 10. Imprimem os elementos do array antes e após essa alteração.
xxxxxxxxxx
Random meuGerador = new Random();
int[] valores = vetorDeAleatorios(8, 20, meuGerador);
imprimeVetor(valores);
alteraValoresInferiores(valores, 10);
imprimeVetor(valores);
De seguida exemplificamos o estado da memória em várias fases de uma possível execução das instruções acima:
Quando o método alteraValoresInferiores
começa a ser executado, o seu parâmetro v
contém uma cópia do conteúdo da variável valores
, do main
, que é uma referência ao array já existente.
Quando o ciclo termina, no método alteraValoresInferiores
, os elementos do array referenciado por v
já estão alterados.
Quando o controle de execução volta ao main
, após a execução do método alteraValoresInferiores
; o array referenciado pela variável valores
já está alterado (claro! é o mesmo que foi usado no método).
Anterior: 9.5. Funções cujo resultado é um array
Seguinte: 9.7. Arrays multi-dimensionais