<Direto ao Ponto 40> A estrutura de um programa
- #Informática Básica
Artigos desta série: ( < ) Anterior | Índice | Seguinte ( > )
Olá, dev!
Este é mais um artigo da série DIRETO AO PONTO, que eu estou escrevendo para a DIO. Ele vai tratar da estrutura de um programa de computador, especificamente, do seu código fonte, destacando os comandos individuais.
Sumário
- Introdução
- Um programa de computador
- O código-fonte
- Blocos de comandos individuais
- Considerações finais
- Referências
1 – Introdução
Eu criei a série de artigos DIRETO AO PONTO com o objetivo de apresentar, de forma simples e direta, conhecimentos básicos da programação e de computação, principalmente, para os iniciantes.
Aqui, são tratados de temas como lógica de programação, linguagens, hardware dos computadores, história da computação e assuntos relacionados à plataforma da DIO, como a escrita de artigos e os desafios de código.
Neste artigo, eu vou falar sobre estrutura do código-fonte de um programa de computador, apresentando os comandos individuais.
Agora, vamos ver como se subdivide um programa escrito em alguma linguagem de programação, ou seja, quais blocos básicos o código fonte de um programa deve ter, quais são comuns a todas as linguagens e quais são específicos de alguma linguagem.
2 – Um programa de computador
Um programa é um código executável que roda em um computador e ele começa com um programa escrito em uma linguagem de programação, o código-fonte.
Cada linguagem foi criada com algum propósito, para atender determinado(s) tipo(s) de aplicação, usando um ou mais paradigmas. Cada uma possui suas especificidades, mas qualquer linguagem de programação apresenta blocos básicos que são comuns, vistos em qualquer aula de lógica de programação, até mesmo nas aulas de nível MASSINHA 1.
No passado, as linguagens não eram estruturadas, seus códigos eram cheios de comandos GO TO, pra lá e prá cá, resultando no chamado código spaghetti. O fluxo de execução dos comandos era muito confuso, difícil de acompanhar e de manter também.
Felizmente, as linguagens passaram a ser estruturadas, compostas de blocos que eram executados em sequência. Alguns blocos constavam de apenas 1 comando (instrução), outros, envolviam várias instruções, mas os blocos eram executados sequencialmente.
O paradigma estruturado passou a ser chamado de procedural, mas a base conceitual da programação estruturada, de blocos individuais de instruções (únicas ou múltiplas) executados sequencialmente, sem se entrelaçarem, montados como blocos de Lego uns sobre os outros, permaneceu e é usado até hoje.
O paradigma procedural se baseia na linguagem estruturada e nas funções e procedimentos para organizar o código.
Já surgiram novos paradigmas depois do procedural, como a programação orientada a objetos (POO) e o funcional, por exemplo.
Mesmo no paradigma de orientação a objetos, em que os blocos formadores do código são objetos, ao invés de funções e procedimentos, como no procedural, dentro da função principal, e dos métodos, o código é escrito de forma estruturada.
São esses blocos individuais que vamos falar aqui. Primeiramente, falaremos dos blocos de instruções individuais, em artigos posteriores, falaremos dos blocos de instruções múltiplas.
3 – A estrutura de um programa-fonte
Um programa-fonte é composto por instruções oferecidas por uma linguagem de programação. Nele, temos seções específicas para cada coisa, sendo as mais comuns:
· função principal
· Comentários
· Declaração de variáveis
· Inicialização de variáveis
· Expressões aritméticas
· Expressões lógicas
· Atribuição de valores a variáveis
· Chamadas de funções
· Chamadas de procedimentos
· Comandos de entrada e saída
· Comandos de seleção
· Comandos de repetição
· Funções e Procedimentos
Outros blocos podem ser:
· Importação de bibliotecas
· Definição de constantes
Da primeira lista (ver figura), podemos identificar que alguns blocos são de instruções múltiplas (em azul), como a própria função principal, o código da função 1 e os comandos de seleção e de repetição. Já os demais são formados por instruções individuais (em verde) e é deles que vamos falar hoje.
4 – Blocos de comandos individuais
Agora vamos detalhar cada um dos blocos de instruções individuais listados na seção anterior.
Geralmente, um programa começa com uma função principal, comumente chamada de main.
Seja no paradigma procedural ou POO, a função main é um bloco de comandos múltiplos, então vou começar falando dos blocos de comandos individuais que ela engloba, começando pelos mais comuns.
Os comentários são estruturas que devem ficar delimitadas por símbolos de início e fim, se encaixando no modelo de programação estruturada, mas eles não são executáveis e servem para explicar algum ponto que fique obscuro para o programador que lê o código. Não serão tratados aqui.
DECLARAÇÃO DE VARIÁVEIS
Um dos primeiros comandos executáveis de um programa-fonte é a declaração de variáveis, que nomeia cada variável a ser usada no programa, informa seu tipo e até já pode inicializá-la com algum valor, tudo em um comando só.
Cada linguagem fornece sua sintaxe própria para estes comandos, bem como tipos de dados e formas de inicialização, mas é um tipo de comando bem comum na programação. Além de declarada, uma variável pode se inicializada no mesmo comando.
INICIALIZAÇÃO DE VARIÁVEIS
Se uma variável não for inicializada na sua declaração, ela pode ser inicializada em outro momento do programa, com a atribuição de um valor a ela, geralmente adequado ao tipo de dado que foi declarado (para linguagens fortemente tipadas, como Java, por exemplo).
A inicialização de variáveis é apenas um subconjunto da operação de atribuição de valores a variáveis, tratada em sequência.
Usar uma variável não inicializada pode levar a erros de execução mais na frente no programa. Algumas linguagens podem usá-la com um valor aleatório (que estava no seu local de memória quando ela foi declarada), um valor zero (de inicialização forçada, como algumas linguagens fazem, por default), ou mesmo pode resultar em erro (“undefined”).
O pior que pode acontecer é quando se usa uma variável do tipo apontador, existente na linguagem C, que guarda uma posição de memória. Tentar usar um apontador não inicializado para armazenar um valor em uma posição não disponível (aleatória) costuma dar erros graves de execução, que podem levar a uma quebra (”crash”) no programa.
Este é um dos erros mais comuns de programadores inexperientes com apontadores em C.
Seguem exemplos de declarações de variáveis, sem e COM inicialização de valores, comuns em algumas linguagens de programação (lista de algumas linguagens que eu já usei (faltou BASIC e Kotlin), mas não pretendi mostrar as que não usei):
ATRIBUIÇÃO DE VALORES A VARIÁVEIS
A atribuição de um valor a uma variável envolve a obtenção deste valor para atribuí-lo à variável em questão. A variável fica sempre na parte esquerda do comando, antes do símbolo de atribuição ( = ) e o valor obtido vem de uma expressão aritmética, condicional ou lógica, uma função, ou outra forma de obtenção de um valor, que fica sempre do lado direito do símbolo de atribuição.
O comando de atribuição de um valor a uma variável geralmente é feito pelo símbolo de igualdade ( = ).
Eu só conheço duas linguagens de programação, Pascal e a antiga Algol 60, que usam um operador diferente para o comando de atribuição ( := ).
Eu acho que deveria ser usado um símbolo diferente do usual ( = ), mais relacionado com a lógica de remeter um valor à variável, como ( <- ), como usado nas pseudo-linguagens de algoritmos, ou mesmo o do Pascal. Assim, ficaria mais parecido com atribuição do que com igualdade.
Na minha opinião, o símbolo de igualdade carrega uma grande ambiguidade matemática. Na matemática a igualdade representa que os valores dos dois lados de uma equação são iguais.
Exemplo: x = x + 1 na matemática
x = x + 1
x – x = 1
0 = 1
E chegamos a uma impossibilidade matemática!!!
Na programação, a atribuição significa que o valor é atribuído à variável, ou seja, ela passa a ter aquele valor armazenado na memória associado a ela, não significando uma operação de igualdade matemática.O valor anteriormente associado à variável é perdido, sendo substituído pelo novo valor a ela atribuído.
Exemplo: x = x + 1 na programação
x = x + 1
para x = 10:
x = 10 + 1
x = 11
Ou seja, a variável x, que tinha antes o valor 10, passa a ter o valor 11, resultado do cálculo da expressão!
EXPRESSÕES ARITMÉTICAS
Toda linguagem de programação permite a realização de operações aritméticas, pelo menos, as 4 operações básicas (soma, subtração, multiplicação e divisão), e usa seus operadores respectivos (+, -, * e /).
Algumas também oferecem outras operações como potenciação (operador **), módulo (operador %) e podem diferenciar divisão inteira e divisão real.
O operador de potenciação está presente nas linguagens Python, Javascript, C# e PHP.
Já o operador de resto da divisão está presente nas linguagens Python, Javascript, Java, C, C++ e PHP.
A operação “módulo” realiza o resto da divisão entre dois inteiros. A divisão real gera um valor decimal, com parte inteira e decimal. A divisão inteira trunca o resultado da divisão real, mantendo só a parte inteira e descartando a parte decimal.
Nas linguagens Python e PHP, há operadores para a divisão inteira ( / ) e divisão real ( // ), nas linguagens C, Java e C# o operador é o mesmo ( / ) para ambas, mas a divisão inteira requer dois operandos inteiros, enquanto a divisão real requer, pelo menos, que um dos 2 operandos seja do tipo double ou float.
Na maioria das linguagens, os operadores possuem a seguinte precedência, que pode ser alterada por meio de parênteses:
· Potenciação, da direita para a esquerda
· Multiplicação e divisão, da esquerda para a direita
· Soma e subtração, da esquerda para a direita
Exemplos de expressões:
Divisão real 7 / 2 = 3.5
Divisão inteira 7 / 2 = 3 (quociente da divisão de 7 por 2)
Operação módulo 7 % 2 = 1 (resto da divisão de 7 por 2)
A expressão 3 + 4 * 5 – 6 / 2 seria avaliada da seguinte forma:
Primeiro seria avaliada 4 * 5 = 20, restando 3 + 20 – 6 / 2
Depois, seria feita a divisão (inteira) 6 / 2 = 3, restando 3 + 20 – 3
Em seguida, seria realizada a soma 2 + 20 = 23, restando 23 – 3
Finalmente, seria avaliada a subtração, resultando em 20.
A ordem das operações poderia ser alterada pelo uso de parênteses, assim a expressão ( 3 + 4 ) * ( 5 – 6 ) / 2 seria avaliada assim:
Primeiro seria avaliado primeiro parênteses ( 3 + 4 ) = 7, restando 7 * (5 – 6 ) / 2
Depois, seriam avaliados os outros parênteses ( 5 – 6 ) = -1, restando 7 * (-1) / 2
Em seguida, seria realizada a multiplicação 7 * (-1) = -7, restando –7 / 2
Finalmente, seria avaliada a divisão, resultando em -3.5, caso essa divisão fosse real, se fosse inteira, resultaria só na parte inteira, ou seja, -3.
Importante: No caso da potenciação, a precedência é o contrário, ou seja, faz primeiro a operação da direita, depois a da sua esquerda, por exemplo:
A expressão 2 ** 3 ** 2 seria avaliada assim:
Primeiro seria avaliada a potenciação 3 ** 2 = 9, restando 2 ** 9
Depois, seria avaliada a outra potenciação 2 ** 9 = 512
E este seria o resultado da expressão, que poderia ser atribuído à alguma variável ou usado em outra instrução, por exemplo, de saída.
É o mesmo que usar parênteses para definir melhor as precedências, assim:
( 2 ** ( 3 ** 2 ) )
EXPRESSÕES CONDICIONAIS
As expressões condicionais podem ser usadas com operadores de comparação, que comparam valores em operações de igualdade, desigualdade, ou de magnitude (maior ou menor).
Estas expressões são aquelas que avaliam condições e resultam em valores booleanos verdadeiro (V) ou falso (F). Os operadores de comparação mais comuns são os seguintes:
Para Python, C, C++, C#, Java, Javascript, Pascal, PHP e fortran
- Igual a: ==
- Diferente de: !=
- Maior que: >
- Menor que: <
- Maior ou igual a: >=
- Menor ou igual a: <=
Exemplos:
- 5 > 3, resulta em V.
- 3 > 5, resulta em F;
- 2 >= 3, resulta em F.
- 3 <= 3, resulta em V;
- 5 == 3, resulta em F;
- 5 != 3, resulta em V;
Algumas linguagens ainda têm outros operadores diferentes para ações especiais, por exemplo:
Em JavaScript e PHP, existem 2 variações para os operadores de igualdade e desigualdade:
- Igual a (só o valor): ==
- Igual a (valor e tipo): ===
- Diferente de (só o valor): !=
- Diferente de (valor e tipo): !==
Além destes, a linguagem PHP usa o operador !<> para desigualdade.
Em Pascal, os operadores de igualdade e desigualdade são:
- Igual a: =
- Diferente de: <>
A linguagem Fortran apresenta um operador diferente para a desigualdade ( /= ) e, além dos símbolos matemáticos comuns ás outras linguagens, ele apresenta operadores literais, desde as ´primeiras versões da linguagem.
- Igual a: .eq. (“equal”)
- Diferente de: .ne. (“not equal”)
- Maior que: .gt. (“greater than”)
- Menor que: .lt. (“less than”)
- Maior ou igual a: .ge. (“greater or equal”)
- Menor ou igual a: <= ou .le. (“less or equal”)
Nas primeiras versões do FORTRAN (em maiúsculas mesmo), na época dos cartões perfurados e por algum tempo depois, estes operadores eram escritos só em maiúsculas, pois as perfuradoras de cartões só tinham as maiúsculas:
.EQ., .NE., .GT., .GE., LT., e .LE.
O próprio nome da linguagem mudou, pois no passado era escrito em maiúsculas e, atualmente, em minúsculas.
EXPRESSÕES LÓGICAS
As expressões lógicas são aquelas que juntam condições condicionais e também resultam em valores booleanos V ou F. Estas expressões usam operadores lógicos, como:
· “AND” (E): Retorna V se ambas as condições forem V, F se uma delas for F;
· “OR” (OU): Retorna V se pelo menos uma das condições for V, F se ambas as condições forem F;
· “NOT” (NÃO): Inverte o valor lógico da condição; V, se for F e vice-versa;
· “XOR” (OU EXCLUSIVO): Retorna V se somente uma das condições for V, caso contrário, será F. Ou seja, é V se as duas condições tiverem valores diferentes, caso contrário, será F.
Estas expressões são fundamentais em programação para controle de fluxo e tomada de decisões.
Seguem alguns exemplos de expressões lógicas:
- (5 > 3) AND (2 < 4), V E V, resulta em V.
- (5 > 3) OR (2 > 4), V OU F, resulta em V;
- NOT (5 > 3), NÃO V, resulta em F;
- (5 > 3) XOR (2 > 4), V XOR F, resulta em V;
Para cada uma destas expressões, existe um operador associado:
PHP tem os operadores and e or, semelhantes a && e ||, mas com menor precedência que eles.
Exemplos acima usando operadores fornecidos na linguagem Python:
- (5 > 3) and (2 < 4), V E V, resulta em V.
- (5 > 3) or (2 > 4) , V OU F, resulta em V;
- not (5 > 3), NÃO V, resulta em F;
E em C:
- (5 > 3) && (2 < 4), V E V, resulta em V.
- (5 > 3) || (2 > 4) , V OU F, resulta em V;
- ! (5 > 3), NÃO V, resulta em F;
Agora, avaliando uma expressão mais complexa, com múltiplas condições:
- ( (5 > 3) and (2 < 4) ) or ( (0 == 1) and !(3 >= 3) )
Calculando cada condição separadamente:
( V and V ) or ( F and !V ) = V or ( F and F ) = V or F = V
CHAMADAS DE FUNÇÕES
Um valor também pode ser retornado para atribuição a uma variável por uma chamada a uma função. O tipo de retorno da função é declarado na definição da função e deve ser compatível com o tipo da variável, no caso de linguagem fortemente tipada, podendo ser alterado, automaticamente ou não, para se compatibilizar ao tipo da variável (“casting”).
Uma função é um dos blocos de comandos múltiplos e não será tratada neste artigo, mas em outro seguinte. Por enquanto, basta saber que o valor de retorno da função poderá ser atribuído à uma variável, ou usado em uma expressão, ou comando de entrada e saída, por exemplo. Ela ode ser chamada sem parâmetros (parênteses de chamada vazios) ou com um ou mais parâmetros, passando valores para serem processados internamente pela função.
Exemplos, em Python:
y = cubo( x ): para x = 2, a função cubo(2) retorna 8, que é atribuído a y;
z = 5 * cubo( 2 ): z = 5 * 8 = 40;
print( cubo(3) ): imprime 27 (3 * 3 * 3 = 27);
CHAMADAS DE PROCEDIMENTOS
Um procedimento funciona como uma função, só que não retorna nenhum valor para o comando de chamada, diferentemente de uma função.
Exemplos, em Python:
print( “Hello, world!” ) – imprime “Hello, world!”.
print( “Digite o seu nome: “) - imprime “Digite o seu nome: “.
COMANDOS DE ENTRADA E SAÍDA
Toda linguagem de programação oferece comandos de entrada e de saída de dados. Eles permitem interação do usuário com o programa, por meu do teclado, mouse, tela e impressora.
Estes comandos são individuais e, além de permitir a entrada e saída de dados, eles também podem formatar a saída.
Veja alguns exemplos de comandos de entrada e de saída:
OUTROS BLOCOS - IMPORTAÇÃO DE BIBLIOTECAS
Algumas linguagens permitem incluir em seu código funções já compiladas em módulos externos, chamados de bibliotecas, para uso dentro do programa. Veja alguns comandos mais comuns de importação de bibliotecas:
C: #include <sdtio.h>
C++: #include <iostream>
Python: Import pandas as pd;
OUTROS BLOCOS - DEFINIÇÃO DE CONSTANTES
A definição de constantes pode entrar no mesmo ítem da inicialização de variáveis, mas há a diferença que a variável criada não permite alteração do valor.
A maioria das linguagens usa a palavra-chave const. É o caso de C, C++, C#, Javascript, Pascal e PHP, como no exemplo:
const PI = 3.14159;
Algumas destas ainda usam um identificador de tipo (float, double, etc.) após a palavra const, como CC++ e C#.
const float PI = 3.14159
Em Java, usam-se as palavras-chave static e final:
public static final double PI = 3.14159
Python não possui uma sintaxe específica para definir constantes. Usa-se uma convenção de nomenclatura, onde variáveis que não devem ser alteradas são escritas em letras maiúsculas, mas a alteração é permitida:
PI = 3.14159
PHP usa a função define():
define("PI", 3.14159)
O Fortran usa a palavra-chave PARAMETER:
REAL, PARAMETER :: PI = 3.14159
Algumas linguagens oferecem outro tipo de definição.
A linguagem C, por exemplo, oferece um comando para definição de dados constantes que, na prática, não cria nenhuma variável nova no espaço de memória do programa. Ele apenas SUBSTITUI, textualmente, os caracteres da constante definida pelo valor dado a ela.
Por exemplo:
#define PI 3.14159
A constante PI é definida como o valor 3.14159, só que PI não vira uma variável, nem pode ter seu valor alterado. Em todo o programa, onde houver o texto “PI”. Ele será substituído pelo texto “3.14159”.
5 – Considerações finais
Este é mais um artigo da série DIRETO AO PONTO, que eu estou escrevendo para a DIO. Desta vez, eu falei sobre a estrutura do código-fonte de um programa de computador.
Foi mostrado como um código-fonte é montado a partir de blocos de comandos (ou instruções) individuais e outros de comandos múltiplos.
Os blocos de comandos individuais são aqueles com apenas 1 instrução, como os comandos para declaração e inicialização de variáveis, as expressões aritméticas, condicionais e lógicas, comandos de entrada e saída e chamadas de funções e procedimentos.
Os blocos de comandos múltiplos são os de comandos de seleção e de repetição, os comandos internos de uma função etc. Foi mostrado que alguns comandos são comuns a várias linguagens e outros são específicos de algumas delas.
No próximo artigo, eu vou começar a falar sobre os blocos de comandos múltiplos.
6 – Referências
Todo o conteúdo deste artigo foi tirado do que eu aprendi (e me lembro) sobre o assunto desde o início da minha carreira como programador, desde os anos 80 até agora. Por isso, não vou listar nenhum a referência de livros nem de sites.
No entanto, para a elaboração das tabelas com os detalhes dos comandos utilizados pelas diversas linguagens de programação que eu já usei, eu consultei as ferramentas de IA ChatGPT e Copilot.
Artigos desta série: ( < ) Anterior | Índice | Seguinte ( > )