Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

SDK, é a sigla de Software Development Kit, ou seja, Kit de Desenvolvimento de Software ou Kit de de Desenvolvimento de Aplicativos.

A linha Microsiga Protheus disponibiliza um extenso SDK para desenvolvimento de processos de negócio no sistema.

A documentação deste SDK pode ser utilizada pelos desenvolvedores, parceiros, terceiros e clientes da linha Microsiga Protheus.


Introdução

O intuito desse documento é explicar o uso da linguagem de programação AdvPL, a sua estrutura, os seus comandos e as suas funções na Linha Microsiga Protheus.

Essas informações permitirão que os usuários ou profissionais de informática conheçam a linguagem AdvPL e se capacitem no desenvolvimento de programas e funcionalidades que rodarão na Linha Microsiga Protheus

 
Os capítulos estão estruturados para que o leitor incremente o seu conhecimento gradualmente.


AdvPL - A linguagem do Microsiga Protheus

Uma das aplicações mais frequentes e úteis dos computadores e dos sistemas de informação é o armazenamento, o controle e o processamento de bases de dados. Uma linguagem de programação permite que esses dados sejam recuperados, processados, transformados em outras informações por meio de cálculos, gravados e mostrados aos usuários por meio de consultas ou relatórios.

Um dos sistemas de informação mais utilizados atualmente nas empresas é o ERP (Enterprise Resource Planning). Por meio de um ERP, todas as áreas de uma empresa são integradas, compartilhando as suas informações e permitindo maior agilidade e precisão na geração e na transmissão de informações entre as áreas e departamentos da empresa. Por exemplo, quando a área de Faturamento emite uma Nota Fiscal, automaticamente o sistema gera os respectivos títulos à receber na área Financeira.

O AdvPL é uma linguagem de programação completa para o desenvolvimento de aplicações no ERP Protheus, desenvolvido e comercializado pela TOTVS. A sua origem é baseada nas linguagem do padrão xBase.

O AdvPL é uma linguagem muito poderosa, flexível e completa. Por meio dela, é possível desenvolver novas aplicações para a Linha Microsiga Protheus, além de adaptar alguns processos às necessidades de cada empresa.

Com o AdvPL é possível desenvolver aplicações para:

  • Criar, relacionar e organizar um conjunto de dados;
  • Manipular os dados por meio de operações de inclusão, alteração e exclusão. Além disso, é possível visualizá-los de forma seletiva e de acordo com as especificações dos usuários;
  • Realizar operações matemáticas, lógicas e de decisão com os dados, gerando novos dados ou extraindo informações;
  • Criar telas para a manutenção e a visualização dos dados pelo usuário;
  • Criar relatórios para a visualização dos dados pelo usuário;
  • Permitir a interação do usuário com as aplicações por meio de páginas Web e de e-mails.


Com a linguagem AdvPL é possível trabalhar com diversos bancos de dados, tanto pagos quanto gratuito, como Microsoft SQL Server, Oracle, IBM DB2, IBM Informix, Postgres, MySql, entre outros.

Variáveis

Durante o processamento de um programa existem determinadas informações que necessitam ser armazenadas na memória do computador, para serem utilizadas à medida que as operações são executadas. Estas informações são armazenadas por meio de nomes identificadores, denominados variáveis, pois podem ter o seu conteúdo modificado durante o fluxo do processamento.

 

Portanto, uma variável é qualquer referência ou valor armazenado temporariamente na memória do computador por meio de um nome, e cujo conteúdo pode variar durante o processamento.

 

O nome da variável pode conter letras, algarismos ou o símbolo sublinhado. Pode ser formado por até 10 caracteres, sendo que o primeiro deve, obrigatoriamente, ser uma letra. Para tornar o programa mais claro e legível, uma das convenções das boas práticas de programação é iniciar o nome da variável com a letra que representa o tipo de dado que ela conterá. Essa convenção é explicada e aprofundada no item correspondente às Boas práticas de programação, contido nessa documentação.

 

Durante a execução de uma aplicação, é possível atribuir um mesmo nome para diferentes variáveis, desde que elas estejam em rotinas diferentes. Entretanto, recomenda-se enfaticamente que essa prática seja evitada. Caso contrário, o risco de ambiguidades dentro do programa será alto, impedindo que o compilador gere um código eficiente. Além disso, o programa poderá ficar tão confuso que, provavelmente, até o programador que o criou terá dificuldade para entendê-lo.

 

Para evitar ambiguidades e permitir que o compilador gere um código otimizado, referências a campos das tabelas de dados devem ser feitas explicitamente precedendo o seu nome com o operador de alias ( -> ), conforme exemplo abaixo:

// Nome do campo que armazena a quantidade do item da Nota Fiscal de Saída (Venda)
SD2->D2_QUANT

Esta sintaxe refere-se a um campo de uma tabela aberta na área de trabalho e designada pelo alias SD2.

 

Desta forma, qualquer ambiguidade é explicitamente evitada e uma variável poderá possuir, por exemplo, o mesmo nome de um campo de uma tabela de dados.

 

O AdvPL permite a definição de diferentes tipos de variáveis, conforme a natureza do dado armazenado nela. Além disso, as variáveis são organizadas em classes que determinam como a variável é armazenada, por quanto tempo ela estará ativa e onde, dentro de um programa, ela poderá ser utilizada (será visível). Cada classe de variável possui um comando específico que declara o seu nome e a cria durante a execução do programa.

Declaração de Variáveis

Declarar uma variável significa informar ao compilador os nomes e as classes das variáveis que existirão no programa. Com base nas declarações, a identificação já é realizada na fase de compilação, antes da execução das instruções e da aplicação.

Variáveis podem ser declaradas por meio dos seguintes comandos:

  • PUBLIC
  • PRIVATE
  • STATIC
  • LOCAL

A declaração é obrigatória para as variáveis das classes estática (STATIC) e local (LOCAL) e opcional para as classes privada (PRIVATE) e pública (PUBLIC). Porém, é recomendável sempre declarar as variáveis, independentemente da sua classe, para que o programa fique fácil de entender, otimizado e livre de ambiguidades.

Os comandos de declaração de variáveis não são executáveis. Ou seja, não desencadeiam nenhuma operação. Eles devem ser inseridos no programa antes de qualquer comando executável, pois o compilador precisa conhecer o nome e a classe das variáveis antes de executar qualquer operação com elas.

Como a declaração de variáveis é resolvida durante a fase de compilação, ela abrange certas unidades do código-fonte: programas (arquivos .PRW), rotinas/funções e blocos de código. Note que algumas dessas unidades estão incluídas em outras: rotinas/funções estão incluídas dentro de programas e blocos de código estão incluídos dentro de rotinas/funções ou de outros blocos de código.

Desta forma, uma declaração de variável que ocorra dentro de uma função aplica-se apenas nesta função e em qualquer bloco de código que ela contenha. Já uma declaração de variável que ocorra dentro de um programa (arquivo .PRW), antes do comando de definição das outras funções (FUNCTION), aplica-se a todas as funções nele contidos.

Uma declaração feita numa função interna a outra pode possuir variáveis com o mesmo nome. Neste caso, a declaração interna prevalece sobre a externa apenas durante a execução da função interna. Por exemplo, uma variável declarada num programa (função mais externa) pode possuir o mesmo nome que uma variável declarada em uma função contida neste programa. Durante a execução desta função interna, a variável declarada nela com o mesmo nome da declarada no programa poderá ter o seu valor modificado, sem que isso afete a outra variável que pertence ao programa. Ao término da função interna, a sua variável é descartada e a variável do programa permanece com o seu valor original.

Escopo/Visibilidade de variáveis

Durante a execução de um programa, uma variável passa a existir, ou é criada, quando uma parte da memória interna do computador é alocada para armazenar o seu valor. Algumas variáveis são automaticamente criadas pelo AdvPL, enquanto outras devem ser explicitamente declaradas pelo programador, conforme a necessidade do seu processamento.

 

Uma vez criada, uma variável continua a existir, contendo ou não um valor, até que a porção de memória alocada para ela seja apagada ou cancelada. Algumas variáveis são canceladas automaticamente pelo AdvPL, enquanto outras devem ser canceladas explicitamente pelo programa. Todavia, algumas variáveis nunca são canceladas durante a execução de uma aplicação. O tempo de existência de uma variável é muito importante para efeito de programação, sendo conhecido como tempo de vida.

 

A visibilidade refere-se às condições sob as quais uma variável pode ou não ser acessada por uma rotina durante a sua execução. Se a variável puder ser acessada, ela será visível àquela rotina.

Classe de variáveis

O AdvPL permite a declaração e a criação de 4 classes de variáveis, que se diferenciam de acordo com a sua visibilidade e tempo de vida dentro da aplicação. As classes de variáveis são:

  • Locais
  • Estáticas
  • Privadas
  • Públicas

Variáveis Locais

Variáveis locais devem ser explicitamente declaradas pelo comando LOCAL. As variáveis dessa classe são visíveis apenas para a função onde estão declaradas, e são descartadas após o término da sua execução.

Por exemplo, se declararmos variáveis locais numa função denominada Teste1(), elas poderão ser utilizadas somente por esta função, pois são visíveis apenas para ela, sendo descartadas quando a função for finalizada.

Bloco de código
FUNCTION Teste1()
LOCAL nNum := 12.97
LOCAL cNome := "LAERCIO"
LOCAL aMatriz := { 5, 5 }
// Instruções
Teste2()
RETURN .T.

Neste exemplo foram declaradas 3 variáveis locais: uma numérica, um caracter e um array. Essas variáveis serão visíveis apenas para a função Teste1(). Quando for executada a função Teste2(), invocada pela função Teste1(), as variáveis nNum, cNome e aMatriz ainda existirão, mas serão inacessíveis ou invisíveis para ela. Quando a execução da função Teste2() for finalizada e se retornar para a função Teste1(), as variáveis poderão ser utilizadas novamente. Contudo, assim que a execução da função Teste1() for finalizada, as variáveis serão descartadas.

 

Por outro lado, se existirem variáveis com os mesmos nomes na rotina que invocou a função Teste1(), nada lhes acontecerá. Ou seja, as variáveis da função principal que invocou a função Teste1 continuarão vivas e com o mesmo valor original.

 

As variáveis locais são criadas automaticamente cada vez que as rotinas nas quais foram declaradas são executadas. Elas existirão e manterão os dados nelas armazenados até a finalização destas rotinas. Além disso, caso uma rotina seja invocada recursivamente, cada execução da mesma criará um novo conjunto de variáveis locais. Apenas o conjunto de variáveis locais mais recente será visível para a rotina.

Variáveis Estáticas

Variáveis estáticas funcionam de maneira semelhante às variáveis locais. Contudo, ao contrário das locais, as estáticas são mantidas após o término da execução da função que as declarou. Além disso, podem ser iniciadas no momento da declaração. Para declarar uma variável da classe estática utiliza-se o comando STATIC.

 

A abrangência das variáveis estáticas está limitada à função nas quais foram declaradas. Se forem declaradas dentro de uma função, a sua abrangência limita-se àquela função. Se forem declaradas fora de uma função, o seu escopo será aplicado em todo o programa (arquivo .PRW).

 

Por exemplo, se variáveis estáticas forem declaradas numa função denominada Teste3(), estas serão visíveis somente para essa função. Porém, elas não serão descartadas ao término da função Teste3(), como ocorre com as variáveis locais.

Bloco de código
FUNCTION Teste3()
STATIC nNum := 1000
// Instruções
Teste4()
RETURN .T.

Neste exemplo, a variável nNum é declarada estática e iniciada com o valor numérico 1000. Quando a função Teste4() for executada, invocada pela Teste3(), a variável nNum continuará existindo, mas não será visível para ela. Porém, ao contrário do que ocorre com as variáveis locais, a variável nNum continuará existindo mesmo depois que a execução da função Teste3() for finalizada. Apenas as execuções subsequentes da função Teste3() poderão acessar novamente a variável.

 

As variáveis estáticas são criadas automaticamente, durante a compilação, antes da execução do programa. Elas continuam a existir e armazenar os seus valores durante toda a execução do programa, não sendo descartadas.

 

Um valor inicial pode ser atribuído às variáveis estáticas por meio do próprio comando STATIC. Caso contrário, elas serão automaticamente iniciadas com o valor NIL (ausência de dados).

Variáveis Privadas

Ao contrário das variáveis locais e estáticas, as variáveis privadas não precisam ser explicitamente declaradas. Contudo, as variáveis privadas poderão ser criadas pelo comando PRIVATE.

 

Caso seja atribuído um valor em uma variável inexistente, ou seja, não declarada, a mesma será automaticamente considerada como uma variável privada.

 

Quando uma variável privada é criada pelo comando PRIVATE e não é iniciada com nenhum valor, o AdvPL automaticamente lhe atribui o valor NIL (ausência de dados).

 

Uma variável privada é visível para a rotina que a criou e para todas as rotinas invocadas por ela. Uma vez criada, uma variável privada continua a existir e retém o seu valor até que a rotina que a criou seja finalizada, quando então será automaticamente descartada.

 

Uma variável privada pode ser criada com o mesmo nome de outra variável pública ou privada já existente, desde que isso ocorra em uma rotina de menor nível do que a rotina que criou a primeira variável homônima. Neste caso, a variável pública ou privada da rotina de maior nível ficará oculta e inacessível até que a nova variável privada seja descartada.

 

Portanto, uma variável privada é visível para a rotina que a criou e para todas as outras rotinas invocadas por esta. Caso uma rotina de menor nível, invocada pela rotina que criou a variável, crie uma nova variável privada com o mesmo nome, a primeira se tornará inacessível até que a segunda seja descartada. O exemplo a seguir ilustra essa condição:

Bloco de código
FUNCTION Teste5()
PRIVATE nNum := 200
// Instruções
Teste6()
RETURN .T.


Neste exemplo, a variável privada nNum é criada na função Teste5(), sendo atribuído o valor numérico 200. Quando a função Teste6() é executada, a variável nNum continua existindo e, ao contrário das variáveis locais, é acessível. Quando a função Teste5() for finalizada, a variável privada nNum será descartada. Caso exista uma rotina de nível superior, que invocou a função Teste5(), e que eventualmente também tenha criado uma variável privada com o mesmo nome, esta se tornará acessível.

Variáveis Públicas

Variáveis públicas são criadas durante a execução dos programas pelo comando PUBLIC. Uma vez criadas, podem ser acessadas por todos os programas, existindo e armazenando valores até o final da execução da aplicação.

 

Variáveis públicas podem ser criadas em qualquer rotina. Ao contrário das variáveis locais e privadas, as variáveis públicas não são descartadas ao final da rotina na qual foram criadas e o seu conteúdo pode ser acessado por qualquer rotina que compõem a aplicação desenvolvida. Com isso, evita-se a necessidade da passagem de parâmetros entre rotinas. Quando uma variável é declarada sem ser iniciada com um valor, o AdvPL lhe atribui automaticamente o valor lógico falso (.F.).

 

O AdvPL permite a criação de uma variável privada com o mesmo nome de uma variável pública. Neste caso, a variável privada oculta temporariamente a variável pública, que se torna inacessível até que a variável privada homônima seja descartada. Contudo, não é possível a criação de uma variável pública com o mesmo nome de uma variável privada já existente. O exemplo abaixo ilustra a criação de uma variável pública:

Bloco de código
FUNCTION Teste7()

PUBLIC nNum := 300
// Instruções
Teste8()
RETURN .T.

Neste exemplo, a variável pública nNum é criada e iniciada com o valor numérico 300 na função Teste7(). Quando a função Teste8() é executada, a variável nNum continua existindo e pode ser acessada por ela. Ao final da função Teste7(), a variável nNum ainda continua existindo e o seu conteúdo pode ser acessado e alterado por qualquer outra rotina da aplicação.

Tipos de Variáveis

Com o propósito da utilização em expressões, cada dado no AdvPL é identificado como um tipo. Dessa forma, para cada variável, constante, função ou campo de tabela é associado um tipo de dado, que depende da forma como cada um destes itens foi criado. Por exemplo, o tipo de dado de uma variável depende do valor nela armazenado, o tipo de dado de uma função depende do valor por ela fornecido e o tipo de dado de um campo depende da estrutura da tabela de dados correspondente.

Os tipos de dados possíveis na linguagem AdvPL são:

  • Caracter
  • Memo
  • Data
  • Numérico
  • Lógico
  • NIL (ausente)
  • Array
  • Bloco de Código

Caracter

Quando os valores armazenados formam cadeias de tamanho fixo, compostas por dígitos numéricos (0 - 9), letras alfabéticas(a - z ou A - Z) ou símbolos especiais (@, +, *, -, /, %, $, &, etc.), trata-se de um dado do tipo caracter.

Um dado do tipo caracter é formado por uma cadeia contendo de zero à 65.535 (64 Kbytes) caracteres da tabela ASCII. O conjunto completo de dados tipo caracter do AdvPL corresponde aos códigos ASCII 0 (nulo), 32 à 126 (caracteres imprimíveis) e 128 à 255 (caracteres gráficos).

Os valores ou constantes armazenados devem ser circunscritos por um par de delimitadores (abre e fecha), que pode ser aspas (" ") ou apóstrofos (' ').

O valor vazio para esse tipo de dado é o caracter ASCII 0 (nulo). Para representá-lo deve-se utilizar dois delimitadores contíguos. Ou seja, "" ou ''.

Dados tipo caracter são ordenados de acordo com o valor do seu código da Tabela ASCII.

Exemplos de dados do tipo caracter:

"O AdvPL é uma poderosa linguagem de programação"
"A taxa de juros é de 0,99 % ao mês, condicionada ao valor mínimo de R$ 100,00 da prestação"

Informações
titleLimites

Os campos do tipo Caracter são limitados a 1MByte até as build 2012 e à 4MByte para as builds superiores à 2013 do TOTVS|Appserver.

 

Memo 

Um dado tipo memo é equivalente ao dado tipo caracter. A única diferença é que um dado tipo memo não tem tamanho definido. Essa característica é possível porque os dados desse tipo são gravados em arquivos de dados.

O código que identifica o dado tipo memo é gravado no arquivo de dados proprietário da informação, como o Cadastro de Clientes, de Fornecedores, etc. Esse código identificador possui 10 posições e é responsável por identificar o conteúdo da informação gravado no arquivo de dados SYP.

No AdvPL, a função padrão MSMM() é responsável pela gravação e recuperação de dados do tipo memo.

Esse tipo de dado é importante para os casos em que a informação não pode se restringir em um determinado tamanho. Por exemplo, observações, laudos, etc.
 

Informações
titleLimites

Os campos do tipo Memo são limitados a 1MByte até as build 2012 e à 4MByte para as builds superiores à 2013 do TOTVS|Appserver.


Data

Este tipo de dado representa datas do calendário e permite a realização de várias operações com elas, como, por exemplo, a obtenção da diferença  entre duas datas, em número de dias, e a obtenção de uma nova data após a soma ou a subtração por um determinado número de dias.

Esse tipo de dado armazena os valores com 8 posições, constituídas por 8 dígitos numéricos de 0 até 9, intercalados por barras "/", no formato 99/99/9999.

Para a definição de dados tipo data é obrigatória a utilização da função CTOD(), que transforma dados tipo caracter em dados tipo data. Por exemplo:

Bloco de código
// Trata datas no formato dia/mês/ano
dNascim := CTOD("14/05/2012")

Com exceção dos campos tipo data das tabelas de dados, a única forma de se definir um dado tipo data é por meio da função CTOD().


Tanto os formatos americano quanto brasileiro são representados da seguinte forma:

  • O símbolo dd representa o dia. Dependendo do mês, deve estar entre 01 e 31.
  • O símbolo mm representa o mês. Deve estar entre 01 e 12.
  • O símbolo ss representa o século do ano. Deve estar entre 00 e 29.
  • O símbolo aaaa representa o ano. Deve se um ano válido.


Nos Bancos de Dados, o armazenamento das datas é feito no formato texto: ssaammdd. O software de interface entre o Protheus e os Bancos de Dados, chamado de Top Connect, converte essa informação de texto para data, conforme a configuração vigente no Protheus, quando a aplicação necessita da informação.


Na Linha Microsiga Protheus, a exibição da data pode ser configurada para o formato americano, representado pelos símbolos mm/dd/aa ou mm/dd/aaaa, ou para o formato adotado no Brasil, representado por dd/mm/aa ou dd/mm/aaaa.


Como padrão, o AdvPL trabalha com datas do século XX, suprimindo a sua indicação. Isto é, a indicação do século, representada pelo símbolo ss, não é apresentada.


Para que o AdvPL os aceite, os dados do tipo data devem ser datas válidas, compreendidas entre 01/01/0100 e 31/12/2999. O valor vazio para os dados tipo data é uma data em branco ou uma data vazia, que deve ser representada pelos comandos CTOD(""), CTOD(SPACE(8)) ou CTOD("  /  /  "). A função CTOD aceita somente datas válidas como argumento. Caso seja apresentada uma data inválida como argumento, o comando a converterá numa data nula.


Exemplos de datas inválidas:

  • 32/12/2012
  • 23/13/2012
  • 23/12/0099
  • 29/02/2012

Numérico

Quando um dado possui na sua composição somente algarismos numéricos de 0 até 9, os sinais + (mais) ou - (menos) e o ponto decimal, ele é do tipo numérico. Este tipo de dado destina-se à realização de cálculos matemáticos.


Por meio deste tipo de dado, o AdvPL é capaz de processar valores numéricos entre 10-308 e 10308. Um arquivo de dados pode armazenardados numéricos com no máximo 32 posições (30 algarismos numéricos, o sinal + ou - e o ponto decimal), com até 16 casas decimais de precisão garantida. Portanto, podemos ter um número com 32 posições inteiras, sem casas decimais, até um número com 15 posições inteiras, o ponto decimal e 16 casas decimais.


Um dado numérico não pode ser delimitado por nenhum símbolo. Caso contrário, será considerado caracter. O valor vazio ou nulo para um dado numérico é o valor zero ( 0 ).


O valor numérico no AdvPL segue o formato americano: o ponto decimal é representado pelo ponto ( . ) e a separação dos valores inteiros pela vírgula ( , ). Segue alguns exemplos baseados em valores monetários:

  • 43.53 (quarenta e três reais e cinquenta e três centavos)
  • 0.05 (cinco centavos)
  • 1,000,000.00 (um milhão)
  • 1.815 (um real e oitocentos e quinze milésimos)

 

Porém, no momento de exibir a informação para o usuário, seja na tela ou em relatório, é possível converter o valor numérico para o formato adotado no Brasil, onde o ponto decimal é representado pela vírgula ( , ) e a separação dos valores inteiros pelo ponto ( . ). Vejamos os mesmos exemplos acima no formato adotado no Brasil:

  • 43,53 (quarenta e três reais e cinquenta e três centavos)
  • 0,05 (cinco centavos)
  • 1.000.000,00 (um milhão)
  • 1,815 (um real e oitocentos e quinze milésimos)
Informações
titleLimites

Os campos do tipo Númerico são limitados a 15-16 digitos de precisão númerica e podem armazenar número entre 5*10**-324 e 1.7*10^308.


Lógico

Um dado do tipo lógico representa apenas dois estados possíveis, chamados de valores booleanos: falso ou verdadeiro. O seu conteúdo poderá ser apenas:

  • .T. ou .t. (True ou Verdadeiro)
  • .F. ou .f. (False ou Falso)


Os dados lógicos são, obrigatoriamente, delimitados por pontos, que equivalem aos delimitadores dos dados tipo caracter. Por exemplo:

  • lRetorno := .T.  // Verdadeiro
  • lRetorno := .F.  // Falso

NIL ou valores nulos

O tipo NIL permite a manipulação de variáveis declaradas, mas não iniciadas com a atribuição de algum valor. A representação deste tipo de dado é a sigla NIL, sem delimitadores.

Pode-se interpretar NIL como sendo ausência de dado, pois quando um valor não for atribuído para uma variável, array, elemento de array ou parâmetro esperado de uma função, o AdvPL automaticamente atribuirá o valor NIL.

A única classe de variáveis para a qual não se pode atribuir o valor NIL são os campos das tabelas de dados.

Informações
titleLimites

O retorno lógico de uma expressão Nula ( Nil ) é Falsa (.F.)

 

Array e Vetores

No AdvPL, matrizes e vetores podem ser considerados como um tipo de dado porque uma referência a uma matriz pode ser atribuída a uma variável, fornecida por uma função ou passada como argumento. Uma referência é um endereço da memória do computador no qual se localiza uma matriz. Devido às suas particularidades, trataremos esse tipo de dado mais adiante em um capitulo especifico.

Bloco de Código

São trechos de código compilado que, assim como os arrays, podem ser considerados como um tipo de dado porque uma referência a um bloco de código pode ser atribuída a uma variável, fornecida por uma função ou passada como argumento. Uma referência é um endereço da memória do computador no qual se localiza um bloco de código. Devido às suas particularidades, trataremos esse tipo de dado mais adiante em um capitulo especifico.

Array e Vetores

Um array pode ser definido como um conjunto de dados relacionados, chamados de elementos, armazenados com um mesmo nome e identificados e acessados por meio de um índice numérico. Em cada um destes elementos podem ser armazenados qualquer tipo de dados, exceto campos memo. Inclusive, um elemento de um array pode conter uma referência para outro array ou bloco de código.


Cada um dos elementos de um array é identificado pelo nome do mesmo e, entre colchetes, pelo seu índice. Por exemplo, considere um array chamado Tabela, formado por 5 linhas e 8 colunas, conforme esquematizado a seguir:

 

Esquema do Array Tabela 
1,11,21,31,41,51,61,71,8
2,12,22,32,42,52,62,72,8
3,13,23,33,43,53,63,73,8
4,14,24,34,44,54,64,74,8
5,15,25,35,45,55,65,75,8

 

O array Tabela é classificado como uma matriz de duas dimensões 5 x 8, pois possui cinco linhas e oito colunas. No esquema são apresentados os índices que identificam cada um dos seus elementos. Por exemplo, o elemento localizado na terceira linha da quinta coluna é identificado pelo índice 3,5. O elemento localizado na segunda linha da oitava coluna é identificado pelo índice 2,8. E assim por diante. Os índices são sempre números inteiros.

No AdvPL, um array é acessado por meio de uma referência. Ou seja, um endereço da memória no qual o array está localizado e por meio do qual pode ser acessado. Quando um array é criado, atribui-se um nome para esta referência, que passa a identificar o array.

Matrizes Multidimensionais

Matrizes multidimensionais são implementadas no AdvPL por meio de conjuntos de submatrizes unidimensionais intercaladas. Nesta arquitetura, cada elemento de uma matriz pode conter um dado ou então uma referência para outra matriz. Vejamos o exemplo abaixo:

 

Bloco de código
aFuncion := { "Marcos", 42, .T. }  // Array unidimensional com as seguintes informações: Nome do funcionário, Idade e indicação se é CLT

 

Porém, um dos elementos pode ser as informações dos dependentes do funcionário. Nesse caso, a estrutura do array seria:

 

Bloco de código
aFuncion := { "Marcos", 42, .T., aDepend }

 

Onde a estrutura do array aDepend seria Nome do Dependente, Grau de parentesco, Idade, Sexo:

 

Bloco de código
aDepend := { { "Cláudia", 1, 35, "F" };
                         { "Rian", 2, 7, "M" } }

 

Essa arquitetura do AdvPL permite que matrizes multidimensionais possam ser assimétricas. Isto acontece quando uma das matrizes intercaladas possui um número diferente de elementos das outras matrizes do mesmo nível ou da matriz na qual ela está inserida. Suponhamos que seja incluído o CPF no array de dependentes:

 

Bloco de código
aDepend := { { "Cláudia", 1, 35, "F", "27847307849" };
                         { "Rian", 2, 7, "M", "16668978119" } }

 

Neste exemplo, o array aFuncion contém 4 elementos em sua estrutura, enquanto o array aDepend contém 5 elementos. 
Ao invés de referenciar outro array, as informações dos dependentes também poderiam ser gravadas diretamente no array aFuncion, como um dos seus elementos:

 

Bloco de código
aFuncion := { "Marcos", 42, .T., { { "Cláudia", 1, 35, "F", "27847307849" },; 
{ "Rian", 2, 7, "M", "16668978119" } } }

 

Criação de Arrays

A declaração dos arrays é realizada pelos mesmos comandos das variáveis dos demais tipos de dados: PRIVATE, PUBLIC, LOCAL e STATIC.

 

O array pode ser criado com um tamanho definido ou não. Caso não seja criado com um tamanho pré-definido, as suas dimensões são definidas durante a execução do programa. Vejamos o exemplo abaixo:

Bloco de código
aExemp1 := { 10, 20, 30, 40, 50 }
aExemp2 := { "Clipper", aExemp1[3] + aExemp1[5], SQRT(a[1]), 1 + aExemp1[2] }

 

O exemplo abaixo é exatamente equivalente ao anterior:

 

Bloco de código
LOCAL aExemp1[5]
LOCAL aExemp2[4]

aExemp1[1] := 10
aExemp1[2] := 20
aExemp1[3] := 30
aExemp1[4] := 40
aExemp1[5] := 50

aExemp2[1] := "Clipper"
aExemp2[2] := aExemp1[3] + aExemp1[5]
aExemp2[3] := SQRT(aExemp1[1])
aExemp2[4] := 1 + aExemp1[2]

 

Um array pode ser utilizado em qualquer ponto de um programa, inclusive como um elemento de outro array. Desta forma, pode-se especificar um array multidimensional:

Bloco de código
 aExemp3 := { { 1, 2, 3 }, { "A", "B", "C" }, { .F., DATE(), .F. } }

 

Caso os elementos do array fossem mostrados para o usuário na tela, teríamos os seguintes valores:

Bloco de código
MSGALERT(aExemp3[1, 1])  // Resultado: 1
MSGALERT(aExemp3[2, 1])  // Resultado: "A"
MSGALERT(aExemp3[3, 3])  // Resultado: .F.


A função ARRAY() é usada para criar arrays com dimensões definidas. As dimensões do array a ser criado são especificadas como argumentos da função ARRAY(). Exemplo:

Bloco de código
LOCAL aTabela := ARRAY(5, 10)


Nesse exemplo, criou-se um array com 5 linhas e 10 colunas.

Um array vazio é definido como sendo uma matriz sem elementos. Para criar um array vazio utiliza-se a seguinte instrução:

Bloco de código
LOCAL aTabela := { }


Os arrays vazios são úteis quando não se sabe, a princípio, o número de elementos que eles possuirão. Posteriormente, poderão ser utilizadas as funções AADD() e ASIZE() para mudar a sua estrutura, adicionando o número de elementos que forem necessários para o processamento da rotina.

Para testar se um array existe ou foi criado, utiliza-se a função VALTYPE(), que fornecerá "A" caso o seu argumento for um array. Por exemplo:

Bloco de código
LOCAL aTabela := { }

IF VALTYPE(aTabela) == "A"
               MSGALERT("A variável é um array")
ENDIF

 

Para testar se um array está vazio, ou seja, não possui elementos, utiliza-se a função EMPTY(), conforme exemplo abaixo:

 

Bloco de código
IF EMPTY(aTabela)
        MSGALERT("O array está vazio")
ENDIF


O número de elementos de um array pode ser determinado por meio da função LEN():

Bloco de código
LOCAL aTabela[5, 8]
MSGALERT(LEN(aTabela))

 

A mensagem acima mostrará que o array aTabela possui 5 elementos.

Repare que a função LEN() fornece apenas o número de elementos da primeira dimensão do array aTabela. O motivo é que no AdvPL as matrizes multidimensionais são, na verdade, compostas por submatrizes unidimensionais intercaladas, contidas ou referenciadas por uma matriz principal. Ou seja, pode-se interpretar que o array aTabela possui uma dimensão com cinco elementos, onde cada um dos elementos desta dimensão contém uma referência a uma submatriz de oito elementos, formando, desta maneira, uma matriz de duas dimensões 5 x 8. É por este motivo que a função LEN(), quando aplicada ao array aTabela, fornece como resultado apenas cinco elementos.

Para determinar o número de elementos das submatrizes, ou seja, da segunda dimensão do array aTabela, deve ser aplicada a função LEN() ao primeiro elemento da matriz principal que contém a primeira submatriz, conforme o exemplo abaixo:

Bloco de código
MSGALERT(LEN(aTabela[1]))

 

Nesse caso, a mensagem mostrará que o primeiro elemento possui 8 colunas.

Caso a matriz avaliada esteja vazia, a função LEN() fornece o valor zero.

Elementos de Arrays

Para acessar um elemento de um array deve-se identificá-lo pelo nome do array e, em seguida, entre colchetes, pelos seus índices. Por exemplo:

Bloco de código
PRIVATE aTabela[5,8]  // Cria a matriz aTabela


Quando um array é criado sem os valores definidos, cada um dos seus elementos tem o valor NIL atribuído. Esse valor persiste até que os elementos sejam iniciados com outros valores. O exemplo abaixo demonstra a atribuição de diversos dados em alguns elementos do array aTabela.

Bloco de código
aTabela[1,1] := 100  // Equivale à aTabela[1][1] := 100
aTabela[2][3] := "AdvPL"
aTabela[5,4] := DATE()
aTabela[2][2] := .T.
aTabela[3,3] := aTabela[1,1] * 2
aTabela[4,4] := SQRT(aTabela[1,1])

Os índices que identificam os elementos de um array são sempre números inteiros e iniciam com o número 1. Os índices atribuídos aos elementos de um array devem ser compatíveis com as suas dimensões e com o número de elementos de cada dimensão. Caso isto não ocorra, será gerado um erro durante a execução do programa. Por exemplo:

Bloco de código
aTabela[6,1] := 1

A atribuição acima causará um erro, pois o array aTabela possui apenas 5 linhas.


O AdvPL também permite a criação e a iniciação de um array com base na estrutura de uma tabela de dados e das informações de uma pasta de arquivos contidas no servidor. Os respectivos comandos (DBSTRUCT e DIRECTORY) estão descritos no tópico Funções.

A função AFILL() é especialmente destinada à iniciação de elementos de arrays de uma única dimensão com um determinado dado. Por exemplo:

Bloco de código
LOCAL aVetor[20]

AFILL(aVetor, SPACE(10), 1, 10)  // Inicia os 10 primeiros elementos do array unidimensional aVetor com dez espaços em branco.
AFILL(aVetor, 0, 11, 20)  // Inicia os 10 últimos elementos do array unidimensional aVetor com o valor numérico zero.

Os elementos de um array podem ser iniciados com o resultado de qualquer expressão válida do AdvPL e com qualquer tipo de dado, incluindo blocos de código e referências a outros arrays. Uma vez iniciados, os elementos de um array podem ser utilizados como se fossem variáveis.


Como no AdvPL pode-se atribuir uma referência de um array para um elemento de outro array, a estrutura do array já existente pode ser alterada dinamicamente durante a execução do programa. Por exemplo:

Bloco de código
PRIVATE aTabela[5,5]  // O array foi criado com 5 linhas e 5 colunas.
aTabela[1, 1] := { 10, 20, 30, 50, 80 }  // A estrutura do array foi alterada em tempo de execução.

Caso o conteúdo do elemento aTabela[1, 1, 5] fosse mostrado, apareceria o conteúdo 80.

Entretanto, caso se tentasse mostrar o conteúdo dos elementos abaixo, ocorreria erro, pois não existem esses elementos na estrutura do array:

Bloco de código
aTabela[1, 2, 1]
aTabela[2, 1, 1]

Analisando esse exemplo, as três dimensões são válidas apenas para o elemento aTabela[1, 1], pois este passou a conter uma referência à outro array com uma dimensão. Este poderoso recurso do AdvPL permite que se explore recursos incríveis de programação. Contudo, como a estrutura de um array pode mudar dinamicamente, deve-se tomar cuidado com a sua utilização, pois existe o risco de se perder totalmente o controle de uma aplicação, tornando-a confusa e suscetível à erros.

Utilização de arrays como parâmetros de rotinas

Arrays podem ser passados como argumentos para funções. Quando a passagem é realizada por meio da sintaxe das funções, os arrays são, por definição, passados por valor. Isto significa que uma cópia da referência ao array é passada ao parâmetro que será recebido pela função invocada. Nessa situação, qualquer alteração realizada nos elementos do array pela função invocada se refletirá automaticamente no array original. Por exemplo:

Bloco de código
LOCAL aLista[20]  // O array é criado e todos os elementos recebem o valor NIL

AFILL(aLista, 1, 1, 10)  // Atribui o valor 1 aos 10 primeiros elementos
AFILL(aLista, 2, 11, 20)  // Atribui o valor 2 aos 10 últimos elementos

MSGALERT(aLista[1])  // Mostra o valor 1
MSGALERT(aLista[11])  // Mostra o valor 2

Dobro(aLista)  // Executa a função Dobro()

MSGALERT(aLista[1])  // Mostra o valor 2
MSGALERT(aLista[11])  // Mostra o valor 4

// Função Dobro()
FUNCTION Dobro(aMat)

LOCAL nElem := 0

FOR nElem := 1 TO LEN(aMat)
               aMat[nElem] := aMat[nElem] * 2
NEXT nElem

RETURN NIL

Neste exemplo, quando a função Dobro() é executada, uma cópia da referência ao array aLista é passada para o parâmetro aMat. A função Dobro() multiplica todos os elementos do array aLista por dois. Quando a função Dobro() é finalizada, a referência aMat é descartada, mas as alterações efetuadas nos valores dos elementos do array aLista são mantidas.

Um Array também pode ser fornecido como resultado de funções. Este recurso permite que uma função, que normalmente fornece apenas um único valor como resultado, forneça múltiplos valores através dos elementos de um array e pelo comando RETURN. Por exemplo:

Bloco de código
aTabela := CriaTb(5, 10, SPACE(10))

// Função CriaTB, que alimenta o array de acordo com o número de linhas e colunas, e o conteúdo.
FUNCTION CriaTb(nLinhas, nColunas, cConteudo)

               LOCAL aTab[nLinhas, nColunas]

               FOR nElem1 := 1 TO nLinhas

                         FOR nElem2 := 1 TO nColunas
                                   aTab[nElem1, nElem2] := cConteudo
                         NEXT nElem2

               NEXT nElem1

RETURN aTab

Funções e operadores especiais para a manipulação de arrays

O operador duplo igual ( == ) é usado para comparar dois arrays, verificando se eles apontam para a mesma referência. Por exemplo:

Bloco de código
LOCAL aTabela1 := { 1, 2, 3 }
LOCAL aLista := { 1, 2, 3 }
LOCAL aTabela2 := aTabela1 // Atribui a referência do array aTabela1 para aTabela2
IF aTabela1 == aTabela2
          // Resultado: .T. (verdadeiro)
          MSGALERT(“Os arrays aTabela1 e aTabela2 têm a mesma referência.”)
ENDIF
IF ! ( aTabela1 == aLista ) 
          // Resultado: .F. (falso)
          MSGALERT(“A referência dos arrays aTabela1 e aLista são diferentes”)
ENDIF
Nota

Importante : Mesmo que os arrays aTabela1 e aLista possuam o mesmo número de elementos e conteúdo de cada elemento seja o mesmo entre os arrays, eles são arrays independentes; isto é; um array não é referencia do outro, então o operador de igualdade entre os arrays retorna .F. . Se o tipo de comparação desejada for efetivamente de conteúdo entre dois arrays, você deve inicialmente verificar se o tamanho de ambos usando a função LEN() com cada um deles, e caso o tamanho seja o mesmo, você deve verificar se os seus elementos são iguais, onde caso um elemento do array seja outro array ( array multi-dimensional ), eles devem ser comparados da mesma forma.

 

O AdvPL possui duas funções para mudar as dimensões de um array já existente:

  • ASIZE( <array>, <elementos> )

 

A função ASIZE() redefine um array ( <array> ) de acordo com um novo número de elementos ( <elementos> ). Caso o novo número de elementos seja superior ao antigo, novos elementos serão adicionados, atribuindo-se o valor NIL para eles. Caso o novo número de elementos seja inferior ao antigo, os elementos que estiverem acima desse número serão removidos.

  • AADD( <array>, <expressão> )

 

A função AADD() adiciona um novo elemento no array ( <array> ) especificado, atribuindo-lhe o resultado da expressão ( <expressão> ) especificada. O novo elemento será o último do array.

 

Para inserir ou eliminar elementos de um array já existente, o AdvPL possui duas funções. Ao contrário das funções AADD() e ASIZE(), estas funções não alteram as dimensões do array, mas apenas o conteúdo dos seus elementos.

  • ADEL( <array>, <nº do elemento> )

 

A função ADEL() elimina o elemento do array ( <array> ) definido pelo número do elemento ( <nº do elemento> ). Todos os elementos localizados após o elemento eliminado são movidos uma posição para a esquerda. Ao último elemento é atribuído o valor NIL.

  • AINS( <array>, <nº do elemento> )

 

A função AINS() insere um elemento no array ( <array> ) na posição definida pelo argumento <nº do elemento>. Ao novo elemento é atribuído o valor NIL. Os elementos localizados após o elemento inserido são movidos uma posição para a direita e o último elemento do array será destruído.

 

Para efetuar operações de cópia de arrays, o AdvPL possui duas funções:

  • ACOPY()

 

Essa função copia um conjunto ou todos os elementos de um array origem para um array destino já existente. Caso o array origem contiver subarrays, o array destino conterá apenas referências a elas, e não cópias reais.

  • ACLONE()

 

Essa função duplica um array origem inteiro para um novo array destino, criando um novo array e realmente copiando os valores dos elementos do array origem para os elementos do novo array.

 

A ordenação de elementos de arrays pode ser realizada automaticamente pela função ASORT(). Ela permite a ordenação ou classificação de todos os elementos de um array ou de um determinado conjunto deles. O critério de ordenação pode ser especificado por meio de um bloco de código.

 

Para localizar um elemento de um array contendo um determinado valor, utiliza-se a função ASCAN(). Ela realiza uma pesquisa nos elementos do array para localizar o elemento que contém um determinado valor especificado através de uma expressão ou bloco de código. Esta função pode pesquisar todos ou apenas um determinado conjunto dos elementos do array. Caso o valor desejado for encontrado, a função retorna o índice correspondente ao elemento. Caso contrário, o valor retornado será zero.

Bloco de código
aFuncion := { "Marcos", 42, .T. }  // Array unidimensional com as seguintes informações: Nome do funcionário, Idade e indicação se é CLT

 

Porém, um dos elementos pode ser as informações dos dependentes do funcionário. Nesse caso, a estrutura do array seria:

Bloco de código
aFuncion := { "Marcos", 42, .T., aDepend }

 

Onde a estrutura do array aDepend seria Nome do Dependente, Grau de parentesco, Idade, Sexo:

Bloco de código
aDepend := { { "Cláudia", 1, 35, "F" };
                         { "Rian", 2, 7, "M" } }

Essa arquitetura do AdvPL permite que matrizes multidimensionais possam ser assimétricas. Isto acontece quando uma das matrizes intercaladas possui um número diferente de elementos das outras matrizes do mesmo nível ou da matriz na qual ela está inserida. Suponhamos que seja incluído o CPF no array de dependentes:

Bloco de código
aDepend := { { "Cláudia", 1, 35, "F", "27847307849" };
                         { "Rian", 2, 7, "M", "16668978119" } }

Neste exemplo, o array aFuncion contém 4 elementos em sua estrutura, enquanto o array aDepend contém 5 elementos.

Ao invés de referenciar outro array, as informações dos dependentes também poderiam ser gravadas diretamente no array aFuncion, como um dos seus elementos:

Bloco de código
aFuncion := { "Marcos", 42, .T., { { "Cláudia", 1, 35, "F", "27847307849" },; 
{ "Rian", 2, 7, "M", "16668978119" } } }

Criação de Arrays

A declaração dos arrays é realizada pelos mesmos comandos das variáveis dos demais tipos de dados: PRIVATE, PUBLIC, LOCAL e STATIC.

 

O array pode ser criado com um tamanho definido ou não. Caso não seja criado com um tamanho pré-definido, as suas dimensões são definidas durante a execução do programa. Vejamos o exemplo abaixo:

Bloco de código
aExemp1 := { 10, 20, 30, 40, 50 }
aExemp2 := { "Clipper", aExemp1[3] + aExemp1[5], SQRT(a[1]), 1 + aExemp1[2] }

O exemplo abaixo é exatamente equivalente ao anterior:

Bloco de código
LOCAL aExemp1[5]
LOCAL aExemp2[4]

aExemp1[1] := 10
aExemp1[2] := 20
aExemp1[3] := 30
aExemp1[4] := 40
aExemp1[5] := 50

aExemp2[1] := "Clipper"
aExemp2[2] := aExemp1[3] + aExemp1[5]
aExemp2[3] := SQRT(aExemp1[1])
aExemp2[4] := 1 + aExemp1[2]

Um array pode ser utilizado em qualquer ponto de um programa, inclusive como um elemento de outro array. Desta forma, pode-se especificar um array multidimensional:

Bloco de código
aExemp3 := { { 1, 2, 3 }, { "A", "B", "C" }, { .F., DATE(), .F. } }

Caso os elementos do array fossem mostrados para o usuário na tela, teríamos os seguintes valores:

Bloco de código
MSGALERT(aExemp3[1, 1])  // Resultado: 1
MSGALERT(aExemp3[2, 1])  // Resultado: "A"
MSGALERT(aExemp3[3, 3])  // Resultado: .F.

A função ARRAY() é usada para criar arrays com dimensões definidas. As dimensões do array a ser criado são especificadas como argumentos da função ARRAY(). Exemplo:

Bloco de código
LOCAL aTabela := ARRAY(5, 10)

 

Nesse exemplo, criou-se um array com 5 linhas e 10 colunas.


Um array vazio é definido como sendo uma matriz sem elementos. Para criar um array vazio utiliza-se a seguinte instrução:

Bloco de código
LOCAL aTabela := { }

Os arrays vazios são úteis quando não se sabe, a princípio, o número de elementos que eles possuirão. Posteriormente, poderão ser utilizadas as funções AADD() e ASIZE() para mudar a sua estrutura, adicionando o número de elementos que forem necessários para o processamento da rotina.


Para testar se um array existe ou foi criado, utiliza-se a função VALTYPE(), que fornecerá "A" caso o seu argumento for um array. Por exemplo:

Bloco de código
LOCAL aTabela := { }

IF VALTYPE(aTabela) == "A"
               MSGALERT("A variável é um array")
ENDIF

Para testar se um array está vazio, ou seja, não possui elementos, utiliza-se a função EMPTY(), conforme exemplo abaixo:

Bloco de código
IF EMPTY(aTabela)
        MSGALERT("O array está vazio")
ENDIF

O número de elementos de um array pode ser determinado por meio da função LEN():

Bloco de código
LOCAL aTabela[5, 8]
MSGALERT(LEN(aTabela))

A mensagem acima mostrará que o array aTabela possui 5 elementos.

Repare que a função LEN() fornece apenas o número de elementos da primeira dimensão do array aTabela. O motivo é que no AdvPL as matrizes multidimensionais são, na verdade, compostas por submatrizes unidimensionais intercaladas, contidas ou referenciadas por uma matriz principal. Ou seja, pode-se interpretar que o array aTabela possui uma dimensão com cinco elementos, onde cada um dos elementos desta dimensão contém uma referência a uma submatriz de oito elementos, formando, desta maneira, uma matriz de duas dimensões 5 x 8. É por este motivo que a função LEN(), quando aplicada ao array aTabela, fornece como resultado apenas cinco elementos.

 

Para determinar o número de elementos das submatrizes, ou seja, da segunda dimensão do array aTabela, deve ser aplicada a função LEN() ao primeiro elemento da matriz principal que contém a primeira submatriz, conforme o exemplo abaixo:

Bloco de código
MSGALERT(LEN(aTabela[1]))

Nesse caso, a mensagem mostrará que o primeiro elemento possui 8 colunas.

Caso a matriz avaliada esteja vazia, a função LEN() fornece o valor zero.

Elementos de Arrays

Para acessar um elemento de um array deve-se identificá-lo pelo nome do array e, em seguida, entre colchetes, pelos seus índices. Por exemplo:

Bloco de código
PRIVATE aTabela[5,8]  // Cria a matriz aTabela

Quando um array é criado sem os valores definidos, cada um dos seus elementos tem o valor NIL atribuído. Esse valor persiste até que os elementos sejam iniciados com outros valores. O exemplo abaixo demonstra a atribuição de diversos dados em alguns elementos do array aTabela.

Bloco de código
aTabela[1,1] := 100  // Equivale à aTabela[1][1] := 100
aTabela[2][3] := "AdvPL"
aTabela[5,4] := DATE()
aTabela[2][2] := .T.
aTabela[3,3] := aTabela[1,1] * 2
aTabela[4,4] := SQRT(aTabela[1,1])

Os índices que identificam os elementos de um array são sempre números inteiros e iniciam com o número 1. Os índices atribuídos aos elementos de um array devem ser compatíveis com as suas dimensões e com o número de elementos de cada dimensão. Caso isto não ocorra, será gerado um erro durante a execução do programa. Por exemplo:

Bloco de código
aTabela[6,1] := 1

A atribuição acima causará um erro, pois o array aTabela possui apenas 5 linhas.

 

O AdvPL também permite a criação e a iniciação de um array com base na estrutura de uma tabela de dados e das informações de uma pasta de arquivos contidas no servidor. Os respectivos comandos (DBSTRUCT e DIRECTORY) estão descritos no tópico Funções.

 

A função AFILL() é especialmente destinada à iniciação de elementos de arrays de uma única dimensão com um determinado dado. Por exemplo:

Bloco de código
LOCAL aVetor[20]

AFILL(aVetor, SPACE(10), 1, 10)  // Inicia os 10 primeiros elementos do array unidimensional aVetor com dez espaços em branco.
AFILL(aVetor, 0, 11, 20)  // Inicia os 10 últimos elementos do array unidimensional aVetor com o valor numérico zero.

 

Os elementos de um array podem ser iniciados com o resultado de qualquer expressão válida do AdvPL e com qualquer tipo de dado, incluindo blocos de código e referências a outros arrays. Uma vez iniciados, os elementos de um array podem ser utilizados como se fossem variáveis.

 

Como no AdvPL pode-se atribuir uma referência de um array para um elemento de outro array, a estrutura do array já existente pode ser alterada dinamicamente durante a execução do programa. Por exemplo:

Bloco de código
PRIVATE aTabela[5,5]  // O array foi criado com 5 linhas e 5 colunas.
aTabela[1, 1] := { 10, 20, 30, 50, 80 }  // A estrutura do array foi alterada em tempo de execução.

Caso o conteúdo do elemento aTabela[1, 1, 5] fosse mostrado, apareceria o conteúdo 80.

 

Entretanto, caso se tentasse mostrar o conteúdo dos elementos abaixo, ocorreria erro, pois não existem esses elementos na estrutura do array:

Bloco de código
aTabela[1, 2, 1]
aTabela[2, 1, 1]

Analisando esse exemplo, as três dimensões são válidas apenas para o elemento aTabela[1, 1], pois este passou a conter uma referência à outro array com uma dimensão. Este poderoso recurso do AdvPL permite que se explore recursos incríveis de programação. Contudo, como a estrutura de um array pode mudar dinamicamente, deve-se tomar cuidado com a sua utilização, pois existe o risco de se perder totalmente o controle de uma aplicação, tornando-a confusa e suscetível à erros.

Utilização de arrays como parâmetros de rotinas

Arrays podem ser passados como argumentos para funções. Quando a passagem é realizada por meio da sintaxe das funções, os arrays são, por definição, passados por valor. Isto significa que uma cópia da referência ao array é passada ao parâmetro que será recebido pela função invocada. Nessa situação, qualquer alteração realizada nos elementos do array pela função invocada se refletirá automaticamente no array original. Por exemplo:

Bloco de código
LOCAL aLista[20]  // O array é criado e todos os elementos recebem o valor NIL

AFILL(aLista, 1, 1, 10)  // Atribui o valor 1 aos 10 primeiros elementos
AFILL(aLista, 2, 11, 20)  // Atribui o valor 2 aos 10 últimos elementos

MSGALERT(aLista[1])  // Mostra o valor 1
MSGALERT(aLista[11])  // Mostra o valor 2

Dobro(aLista)  // Executa a função Dobro()

MSGALERT(aLista[1])  // Mostra o valor 2
MSGALERT(aLista[11])  // Mostra o valor 4

// Função Dobro()
FUNCTION Dobro(aMat)

LOCAL nElem := 0

FOR nElem := 1 TO LEN(aMat)
               aMat[nElem] := aMat[nElem] * 2
NEXT nElem

RETURN NIL

Neste exemplo, quando a função Dobro() é executada, uma cópia da referência ao array aLista é passada para o parâmetro aMat. A função Dobro() multiplica todos os elementos do array aLista por dois. Quando a função Dobro() é finalizada, a referência aMat é descartada, mas as alterações efetuadas nos valores dos elementos do array aLista são mantidas.

 

Um Array também pode ser fornecido como resultado de funções. Este recurso permite que uma função, que normalmente fornece apenas um único valor como resultado, forneça múltiplos valores através dos elementos de um array e pelo comando RETURN. Por exemplo:

Bloco de código
aTabela := CriaTb(5, 10, SPACE(10))

// Função CriaTB, que alimenta o array de acordo com o número de linhas e colunas, e o conteúdo.
FUNCTION CriaTb(nLinhas, nColunas, cConteudo)

               LOCAL aTab[nLinhas, nColunas]

               FOR nElem1 := 1 TO nLinhas

                         FOR nElem2 := 1 TO nColunas
                                   aTab[nElem1, nElem2] := cConteudo
                         NEXT nElem2

               NEXT nElem1

RETURN aTab

Funções e operadores especiais para a manipulação de arrays

O operador duplo igual ( == ) é usado para comparar dois arrays, verificando se eles apontam para a mesma referência. Por exemplo:

Bloco de código
LOCAL aTabela1 := { 1, 2, 3 }
LOCAL aLista := { 1, 2, 3 }
LOCAL aTabela2 := aTabela1 // Atribui a referência do array aTabela1 para aTabela2
 
IF aTabela1 == aTabela2
          // Resultado: .T. (verdadeiro)
          MSGALERT(“Os arrays aTabela1 e aTabela2 têm a mesma referência.”)
ENDIF
 
IF ! ( aTabela1 == aLista ) 
          // Resultado: .F. (falso)
          MSGALERT(“A referência dos arrays aTabela1 e aLista são diferentes”)
ENDIF
Nota

Importante : Mesmo que os arrays aTabela1 e aLista possuam o mesmo número de elementos e conteúdo de cada elemento seja o mesmo entre os arrays, eles são arrays independentes; isto é; um array não é referencia do outro, então o operador de igualdade entre os arrays retorna .F. . Se o tipo de comparação desejada for efetivamente de conteúdo entre dois arrays, você deve inicialmente verificar se o tamanho de ambos usando a função LEN() com cada um deles, e caso o tamanho seja o mesmo, você deve verificar se os seus elementos são iguais, onde caso um elemento do array seja outro array ( array multi-dimensional ), eles devem ser comparados da mesma forma.

O AdvPL possui duas funções para mudar as dimensões de um array já existente:

  • ASIZE( <array>, <elementos> )

 A função ASIZE() redefine um array ( <array> ) de acordo com um novo número de elementos ( <elementos> ). Caso o novo número de elementos seja superior ao antigo, novos elementos serão adicionados, atribuindo-se o valor NIL para eles. Caso o novo número de elementos seja inferior ao antigo, os elementos que estiverem acima desse número serão removidos.

  • AADD( <array>, <expressão> )

 

A função AADD() adiciona um novo elemento no array ( <array> ) especificado, atribuindo-lhe o resultado da expressão ( <expressão> ) especificada. O novo elemento será o último do array.

 

Para inserir ou eliminar elementos de um array já existente, o AdvPL possui duas funções. Ao contrário das funções AADD() e ASIZE(), estas funções não alteram as dimensões do array, mas apenas o conteúdo dos seus elementos. 

  • ADEL( <array>, <nº do elemento> )

 

A função ADEL() elimina o elemento do array ( <array> ) definido pelo número do elemento ( <nº do elemento> ). Todos os elementos localizados após o elemento eliminado são movidos uma posição para a esquerda. Ao último elemento é atribuído o valor NIL. 

  • AINS( <array>, <nº do elemento> )

 

A função AINS() insere um elemento no array ( <array> ) na posição definida pelo argumento <nº do elemento>. Ao novo elemento é atribuído o valor NIL. Os elementos localizados após o elemento inserido são movidos uma posição para a direita e o último elemento do array será destruído.

Para efetuar operações de cópia de arrays, o AdvPL possui duas funções:

  • ACOPY()

Essa função copia um conjunto ou todos os elementos de um array origem para um array destino já existente. Caso o array origem contiver subarrays, o array destino conterá apenas referências a elas, e não cópias reais.

  • ACLONE()

 

Essa função duplica um array origem inteiro para um novo array destino, criando um novo array e realmente copiando os valores dos elementos do array origem para os elementos do novo array.

 

A ordenação de elementos de arrays pode ser realizada automaticamente pela função ASORT(). Ela permite a ordenação ou classificação de todos os elementos de um array ou de um determinado conjunto deles. O critério de ordenação pode ser especificado por meio de um bloco de código.

 

Para localizar um elemento de um array contendo um determinado valor, utiliza-se a função ASCAN(). Ela realiza uma pesquisa nos elementos do array para localizar o elemento que contém um determinado valor especificado através de uma expressão ou bloco de código. Esta função pode pesquisar todos ou apenas um determinado conjunto dos elementos do array. Caso o valor desejado for encontrado, a função retorna o índice correspondente ao elemento. Caso contrário, o valor retornado será zero. 

Status do documentoConcluído
Data31/07/2014
Versão1.0
Versão anterior1.0
Autores

Marcos Cesar Pires Gomes

Revisores

Eduardo Perusso Riera

Ivan Pinheiro Cabral

Índice resumido
Índice
maxLevel1
indent10px
Índice
Índice
outlinetrue
indent10px