Ybadoo - Soluções em Software Livre
Turmas
1º Semestre de 2024

Questão 01

Considere o seguinte programa escrito na sintaxe Pascal:

program MAIN;
var x: integer;
procedure SUB1;
var x: integer;
begin
x := 4;
SUB2(SUB3);
end;
procedure SUB2(procedure SUB);
var x: integer;
begin
x := 6;
SUB;
end;
procedure SUB3;
begin
writeln('x = ', x);
end;
begin
x := 2;
SUB1;
end.

Um aspecto interessante dos nomes de subprogramas passados como parâmetros é a questão referente ao ambiente de referenciamento correto para executar o subprograma passado. Com base no programa apresentado, avalie as asserções a seguir.

  1. Caso seja utilizado a vinculação rasa, o valor impresso será 6.
  2. Caso seja utilizado a vinculação profunda, o valor impresso será 4.
  3. Caso seja utilizado a vinculação ad hoc, o valor impresso será 4.
  4. Caso seja utilizado a vinculação rasa, o valor impresso será 2.

A respeito dessas asserções, assinale a alternativa correta.

a. apenas as assertivas I e II.

b. apenas as assertivas I e III.

c. apenas as assertivas II e III.

d. apenas as assertivas II e IV.

e. apenas as assertivas III e IV.

Questão 02

(POSCOMP, 2022) Analise as seguintes assertivas sobre tipos de dados:

  1. Tipos reais (float/double) são utilizados para armazenar valores numéricos com parte fracionária.
  2. Tipos caracteres (char) permitem armazenar um único caractere.
  3. Tipos inteiros (int/long) são utilizados para armazenar valores que pertencem ao conjunto dos números naturais (sem a parte fracionária).
  4. Vetores, matrizes e ponteiros são exemplos de tipos de dados primitivos (básicos).

Quais das assertivas apresentadas estão corretas?

a. apenas as assertivas I e II.

b. apenas as assertivas I e III.

c. apenas as assertivas II e III.

d. apenas as assertivas II e IV.

e. apenas as assertivas III e IV.

Questão 03

(POSCOMP, 2022) Analise o código escrito na Linguagem C (Compilador Ansi C) abaixo e assinale a alternativa que corresponde a saída na tela.

int *p, **r, a = -1, c, b=10;
p = &a;
r = &p;
c = **r + b--;
printf("%d", c);

a. 7.

b. 8.

c. 9.

d. 10.

e. 11.

Questão 04

(POSCOMP, 2019) Considere as afirmações abaixo sobre comandos em linguagens de programação:

  1. Uma declaração de variável associa um nome a um valor que, geralmente, não pode ser alterado durante a execução do programa.
  2. Uma coerção é uma conversão de tipos generalizante, ou seja, aquela no qual um objeto é convertido para um tipo que pode incluir pelo menos aproximações para todos os valores do tipo original, como por exemplo, int para double.
  3. Expressões aritméticas são expressões cujos resultados são valores numéricos, inteiros ou fracionários.
  4. Expressões lógicas são aquelas que têm como resultado um dos dois valores, verdadeiro ou falso.

Quais das assertivas apresentadas estão corretas?

a. apenas as assertivas I e II.

b. apenas as assertivas I e III.

c. apenas as assertivas II e III.

d. apenas as assertivas II e IV.

e. apenas as assertivas III e IV.

Questão 05

Considere o seguinte programa escrito na sintaxe C:

void sum(int i, int j, int t)
{
for(; 0 < j; j--)
{
i = i + t;
}
}

void main()
{
int k = 1;
sum(k, 5, k + k);
printf("%d", k);
}

Com base no programa apresentado, avalie as asserções a seguir.

  1. Caso os parâmetros sejam passados por referência, o valor impresso será 11.
  2. Caso os parâmetros sejam passados por nome, o valor impresso será 243.
  3. Caso os parâmetros sejam passados por valor-resultado, o valor impresso será 13.
  4. Caso os parâmetros sejam passados por valor, o valor impresso será 5.

A respeito dessas asserções, assinale a alternativa correta.

a. apenas as assertivas I e II.

b. apenas as assertivas I e III.

c. apenas as assertivas II e III.

d. apenas as assertivas II e IV.

e. apenas as assertivas III e IV.

Questão 06

A ideia existente por trás da semântica operacional é descrever o significado de um programa ao executar suas instruções em uma máquina, seja ela real ou simulada. As alterações que ocorrem no estado de uma máquina, quando ela executa determinada instrução, definem o significado desta. Usando as instruções da máquina virtual definida a seguir, apresente uma definição semântica operacional das instruções break/continue em C apresentada a seguir.

ident := var
ident := var op_bin var
ident := op_un var
goto label
if var relop var goto label

ident é um identificador.

var é um identificador ou uma constante.

op_bin pode ser um dos operadores aritméticos do conjunto {+, -, *, /}.

op_un pode ser um dos operadores unários do conjunto {+, -}.

relop pode ser um dos operadores relacionais do conjunto {=, <>, >, <, >=, <=}.

for (int a = 0; a < 10; a++)
{
if (a == 4) continue;
if (a == 6) break;
}
a := 0;
label1:
if a < 10 goto label2;
goto label4;
label2:
if a = 4 goto label3;
if a = 6 goto label4;
label3:
a := a + 1;
goto label1;
label4:

Questão 07

Uma característica de projeto de expressões menos comumente discutida é a ordem de avaliação dos operandos. Por exemplo, no programa escrito na sintaxe C abaixo, o valor computado para a variável global a em fun2 dependerá da ordem de avaliação dos operandos na expressão a + fun1(). O valor da variável global a poderá ser 8 ou 20. Quais são as duas soluções para o problema da ordem de avaliação de operandos? Quais as desvantagens de cada solução?

int a = 5;

int fun1() {
a = 17;
return 3;
}

int fun2() {
a = a + fun1();
}

int main() {
fun2();
}

Há duas soluções para o problema da ordem de avaliação de operandos. Primeiro, o projetista da linguagem poderia impedir que a avaliação da função afetasse o valor das expressões simplesmente rejeitando os efeitos colaterais funcionais. O segundo método para evitar o problema é declarar, na definição da linguagem, que os operandos das expressões devem ser avaliados em uma ordem particular e exigir que os implementadores garantam esta ordem.

Rejeitar os efeitos colaterais funcionais é difícil e elimina um pouco da flexibilidade do programador. Considere o caso do C e do C++, que têm somente funções. Para eliminar os efeitos colaterais de dois parâmetros bidirecionais e, ainda assim, oferecer subprogramas que retornam mais de um valor, seria necessário umnovo tipo de subprograma semelhante aos procedimentos das outras linguagens imperativas. O acesso a globais em funções também teria que ser rejeitado. Porém, quando a eficiência é importante, usar o acesso a variáveis globais para evitar a passagem de parâmetros é um método importante de aumento da velocidade de execução. Nos compiladores, o acesso global a dados, como a tabela de símbolos, é comum.

O problema de ter-se somente uma ordem de avaliação estrita é que algumas técnicas de otimização de código usadas pelos compiladores envolvem reorganizar as avaliações de operandos. Uma ordem garantida rejeita esses métodos quando chamadas a funções estão envolvidas. Não há, portanto, nenhuma solução perfeita, conforme é sustentado pelos projetos de linguagens reais.

Questão Extra

A vinculação do tipo subscrito a uma variável de array normalmente é estática, mas as faixas de valor de subscrito, às vezes, são vinculadas dinamicamente. Como acontece com as variáveis escalares, os arrays ocorrem em quatro categorias. Nesse caso, as definições de categoria baseiam-se na vinculação às faixas de valor de subscrito e nas vinculações ao armazenamento. Quais são essas quatro categorias e como elas relacionam as faixas de subscrito e o armazenamento dos elementos presentes no array.

Como acontece com as variáveis escalares, os arrays ocorrem em quatro categorias. Nesse caso, as definições de categoria se baseiam-se na vinculação às faixas de valor de subscrito e nas vinculações ao armazenamento. Novamente, os nomes de categorias indicam onde e quando este é alocado.

Um array estático é aquele em que as faixas de subscrito estão estaticamente vinculadas e a alocação de armazenamento é estática (feita antes da execução). A vantagem dos arrays estáticos é a eficiência. Nenhuma alocação ou desalocação dinâmica é exigida. No FORTRAN 77, o tipo subscrito é vinculado a um array no tempo de projeto da linguagem, e todos os subscritos são do tipo inteiro. As faixas de subscrito são estaticamente vinculadas e todo o armazenamento é alocado estaticamente.

Um array stack-dinâmico fixo é aquele em que as faixas de subscrito estão estaticamente vinculadas, mas a alocação é feita no momento de elaboração da declaração durante a execução. A sua vantagem sobre os arrays estáticos é a eficiência de espaço. Um array grande em um procedimento pode usar o mesmo espaço que um outro array grande em um procedimento diferente, contanto que ambos os procedimentos não estejam ativos ao mesmo tempo. Os arrays que não são declarados em procedimentos Pascal e em funções C (sem o especificador static) são exemplos de stack-dinâmicos fixos.

Um array stack-dinâmico é aquele em que as faixas de subscrito estão dinamicamente vinculadas e a alocação de armazenamento é dinâmica (feita durante a execução). Porém, assim que as faixas de subscrito são vinculadas e o armazenamento é alocado, eles permanecem fixos durante o tempo de vida da variável. A vantagem deste sobre os estáticos e sobre os stack-dinâmicos fixos é a flexibilidade. O tamanho de um array não precisa ser conhecido até que ele esteja prestes a ser usado, como os arrays declarados em Ada.

Um array heap-dinâmico é aquele em que a vinculação das faixas de subscrito e de alocação de armazenamento é dinâmica e pode mudar qualquer número de vezes durante o seu tempo de vida. A sua vantagem sobre os outros é a flexibilidade, pois os arrays podem crescer ou reduzir-se durante a execução do programa conforme mudar a necessidade de espaço. O C, com a utilização das funções da biblioteca padrão malloc e free, e o C++, com os operadores new e delete, permitem que os arrays sejam armazenados na heap.