P2 Flashcards
Expressões
Meios fundamentais de especificar computações em uma linguagem de programação
Determina o formato das expressões
Sintaxe
Determina a maneira como as expressões são avaliadas
Semântica
Fatores que definem a avaliação de uma expressão (4)
Ordem dos operadores (regras de precedência e associatividade)
Ordem dos operandos
Tipo dos operandos
Coerção
Duas ações realizadas pela execução de uma expressão
Avaliar os operandos
Executar a operação indicada
Expressões são compostas de _____________, ___________ e ____________.
Operandos
Operadores
Parênteses
Notação infixa
Operador entre os operandos
A + B
Notação pré-fixada e notação pós-fixada
Operador antes dos operandos
+ A B
Operador depois dos operandos
A++
Definem a ordem de avaliação quando diferentes operadores são encontrados em uma expressão
Regras de precedência
Na maioria das linguagens, os operadores booleanos têm a mesma precedência?
Sim
Regras que avaliam uma expressão quando todos os operadores têm a mesma precedência
Regras de associatividade
expressões são avaliadas da esquerda para a direita
Associatividade à esquerda
(binários - exceto atribuição)
expressões são avaliadas da direita para a esquerda
Associatividade à direita
(unários e atribuição)
operadores não podem ocorrer na sequência sem uso de parênteses para indicar a ordem
tipo de associatividade
não associativo
Ada: **(potência)
operadores relacionais
exprimem relação entre operandos
==, !=, >, <…
operadores que não podem ocorrer em sequência
operadores relacionais
incremento e decremento (lings baseadas em C)
(a++)++
5++ //erro: não pode incrementar uma constante literal
Operações associativas permitem aos compiladores…
… reordenas as operações para otimizar a validação da expressão.
Caso em que mesmo números inteiros podem não ser totalmente associativos
não é possível executar as operações em qualquer ordem
A + B + C + D
* Imagine que A e C são inteiros positivos absolutamente grandes e B e D sejam inteiros negativos absolutamente grandes:
* A + B não causa overflow, mas A + C pode causar.
* Para esses valores, essa expressão não é associativa porque não é possível executar as operações em qualquer ordem
A ordem de avaliação dos operandos é irrelevante se…
… nenhum operando tiver efeitos colaterais (função modificando variável externa)
A + func(A) //ordem de avaliação faz diferença
Um programa tem ________________ se quaisquer duas expressões nesse programa que têm o mesmo valor puderem ser substituídas uma pela outra em qualquer lugar sem afetar o resultado.
transparência referencial
(afetada pelos efeitos colaterais)
result1 = (func(a) + b) / (func(a) – b);
temp = func(a);
result2 = (temp + b) / (temp – b);
nesse exemplo, em que caso não há transparência referencial?
quando func(a) modifica o valor de b (efeito colateral)
Sobrecarga de operadores
Quando alguns operadores podem ser usados para mais de um propósito
ex: (+) adição e concatenação
“Uso múltiplo de um operador”
Vantagem e desvantagem da sobrecarga de operadores
Pode melhorar a legibilidade e facilidade de escrita (se usada com bom senso)
Pode comprometer seriamente a legibilidade e confiabilidade dos programas (se usada indiscriminadamente)
avaliação na qual o resultado é determinado sem avaliar todos os operandos e/ou operadores
avaliação curto-circuito
ex: x && y
se x é falso, não precisa avaliar o y pq o resultado final vai ser falso
Qual propriedade impede a ocorrência de erro de extrapolação de índice no exemplo abaixo?
while ( (i < matriz.length) && (matriz[i] != key) )
i++;
Avaliação curto-circuito
(a > b) || ((b++) / 3)
em que contexto um programa contendo o exemplo acima falharia?
Caso o programa dependa do incremento (b++) e o operador (||) aplica avalição curto-circuito
(b só será incrementado se (a > b) == False)
linguagens funcionais não possuem esta operação:
atribuição
base para linguagens imperativas e OO:
atribuição
- Presente em todas as linguagens imperativas e orientadas a objetos;
- Utiliza apenas uma variável do lado esquerdo.
Atribuição simples (a = 5;)
– Presente na linguagem Perl. Por exemplo:
($flag ? $count1 : $count2) = 0;
– É equivalente a:
if ($flag) { $count1 = 0; } else { $count2 = 0; }
Atribuição condicional
Realiza uma operação sobre uma variável e atribui o resultado a essa variável
Operador de atribuição composto (x+=5;)
– Operadores que são atribuições abreviadas
– Aparecem em versões pré-fixadas e pós-fixadas
Operadores de atribuição unários
z = x++; //pós-fixado equivalente a z = x; x = x + 1;
z = ++x; //pré-fixado equivalente a x = x + 1; z = x;
while ((ch = getChar()) != EOF) { … }
a = b = c = 0;
são exemplos de?
atribuição como expressão
Quando as atribuições como expressão podem resultar em erros indetectáveis?
Nas linguagens C e C++, pois as expressões condicionais são baseadas em números e não em booleanos
Ex: (x=y) ao invés de (x==y) // o compilador não acusa erro
a sentença de atribuição produz um resultado, que pode ser usado como operador em outras operações
Atribuição como expressão
Sentenças de atribuição de múltiplos alvos e fontes
Atribuições de lista
first, second, third = 20, 40, 60;
é exemplo de?
atribuição de lista
As ______________ são realizadas pela avaliação de expressões e atribuição dos valores resultantes a variáveis.
computações
Dois tipos de instruções de controle
Seleção e iteração
permitem selecionar entre caminhos alternativos do fluxo de execução do programa (tipo de instrução de controle)
seleção
provoca a execução repetida de um conjunto de sentenças (tipo de instrução de controle)
iteração
O que são sentenças de controle?
Sentenças com instruções de controle
O que é uma estrutura de controle
Sentença de controle + coleção de sentenças cuja execução ela controla
Instrução que realiza um salto para um local específico no programa identificado por um rótulo
Salto incondicional
ex: goto
Fornecem meios para escolher entre dois ou mais caminhos de execução em um programa
Sentenças de seleção
Quais são as duas categorias de sentenças de seleção?
Sentenças de seleção de dois caminhos
Sentenças de seleção múltipla
Em Sentenças de Seleção de Dois Caminhos, é especificada entre parênteses se nenhum marcador sintático for usado para introduzir a cláusula então
Expressão de controle
Usados para compor as sentenças compostas
em sentenças de seleção
Delimitadores de blocos (chaves ou palavras reservadas)
Em caso de seletores aninhados, na maioria das linguagens o else pertence a qual if?
ao if anterior mais próximo
Permitem a seleção de uma dentre qualquer número de grupo de sentenças
Sentenças de Seleção Múltiplas
Representa um desvio explícito em sentenças de seleção múltiplas
Sentença opcional break
Sentença opcional break
Representa um desvio explícito em sentenças de seleção múltiplas
Sentenças de Iteração fazem com que conjunto de ____________ seja executado zero ou mais vezes.
sentenças
Todas as linguagens de programação fornecem alguma forma de repetir segmentos de código?
Sim
Quais são as duas categorias de sentenças de iteração?
Sentenças de iteração lógicas
Sentenças de iteração com contador
Sentenças de iteração lógicas
O controle do laço é baseado em uma expressão booleana
O projeto de sentenças de iteração lógicas é mais simples que o de laços com contador?
Sim
laços com pré-teste e laços com pós-teste
while
do-while
Variável que armazena o valor da contagem em laços com contador
Variável de laço
Quais são os parâmetros dos laços com contador?
Valor inicial da variável do laço
Valor final da variável do laço
Tamanho do passo (o quanto os valores da variável do laço mudam a cada iteração)
O quanto os valores da variável do laço mudam a cada iteração
tamanho do passo
Em vez de usar um contador ou uma expressão booleana, esses laços são controlados por uma estrutura de dados (matrizes ou listas)
Iteração Baseada em Estruturas de Dados (for each)
situação que tem origem em um erro que ocorrer em um programa em um momento não determinado
exceção
processamento especial que pode ser requerido quando uma exceção é detectada
tratamento de exceção
tratamento de exceção
processamento especial que pode ser requerido quando uma exceção é detectada
tratador de exceção
unidade de código que realiza o tratamento de exceção
quando uma exceção é levantada (raised) – ou lançada (thrown)?
quando seu evento associado ocorre
Quais são as 4 formas que uma exceção pode ser tratada?
- Por um tratador cujo código está dentro da própria unidade de código em que a exceção foi detectada (try catch)
- Por um tratador na unidade que chamou o subprograma que lançou a exceção (throws no cabeçalho do método)
- Enviando ao subprograma um rótulo para o qual a execução do programa é transferida caso ocorra uma exceção (tipo um goto?)
- O tratador é definido como um subprograma separado, que é passado como parâmetro para o subprograma chamado
Normalmente, é usado para liberar recursos que eventualmente possam ter sido alocados durante o processamento do bloco try e que devem ser liberados.
Bloco finally
O bloco finally, quando presente, sempre é executado, independentemente de uma
exceção ter sido lançada ou não dentro do try?
Sim
O finally não é executado se houver um return nos blocos try ou catch (V ou F)
Falso
Exceções criadas pelo programador só podem ser lançadas de maneira explícita (V ou F)
Verdadeiro
unidade (ou bloco) de código que agrupa uma ou mais sentenças, é identificado por um nome e pode ser reutilizado em diferentes locais em um programa
subprograma
A unidade de programa chamadora é suspensa durante a execução do subprograma chamado, no que isso implica?
implica na existência de um subprograma em execução em um dado momento
Quais são os 3 tipos de subprograma?
Procedimentos, funções e corrotinas
– São coleções de sentenças que definem computações parametrizadas;
– Definem novas sentenças;
procedimentos
– São semanticamente modeladas como funções matemáticas;
– Retornam um resultado, mesmo que seja vazio;
– Podem criar operadores não fornecidos pela linguagem.
funções
– Não possuem um relacionamento mestre-escravo com o subprograma chamador
– Pode ter múltiplos pontos de entrada, controlados por ela mesma
– Possui variáveis locais estáticas que mantém o seu estado entre uma chamada e outra
– A cada chamada, ela continua a sua execução a partir do ponto onde parou na última vez que foi chamada
corrotina
– Especifica o tipo de unidade sintática;
– Define o tipo de dado do subprograma;
– Indica o nome do subprograma;
– Especifica uma lista de parâmetros.
Cabeçalho de um subprograma
Cabeçalho de um subprograma sem a presença do corpo
Assinatura ou protótipo
Subprograma sobrescrito
Possui o mesmo cabeçalho que outro subprograma na superclasse
Subprograma sobrecarregado
Possui o mesmo nome que outro subprograma na mesma unidade de código
Possui o mesmo cabeçalho que outro subprograma na superclasse
Subprograma sobrescrito
Possui o mesmo nome que outro subprograma na mesma unidade e código
Subprograma sobrecarregado
estrutura que armazena as informações necessárias para a chamada e execução do subprograma
registro de ativação
Quando um subprograma é chamado, uma instância do seu registro de ativação é armazenada na…
pilha de tempo de execução do programa
Ponteiro para a instrução na qual o subprograma foi chamado
endereço de retorno
ponteiro para a instância do registro de ativação do subprograma chamador
ligação dinâmica
Endereço de retorno
Parâmetros
Variáveis
Ligação dinâmica
coloque na ordem da estrutura de um registro de ativação
Variáveis
Parâmetros
Ligação dinâmica
Endereço de retorno
Todo programa possui um ____________, que aponta para o registro de ativação do subprograma ativo.
ponteiro de ambiente (PE)
Nem todo programa possui um ponteiro de ambiente (V ou F)
Falso
Quando um subprograma é chamado, o PE do chamador é armazenado no campo ____________ do subprograma chamado.
Ligação Dinâmica
Quais operações acontecem quando um subprograma é chamado?
- é salvo o estado de execução da unidade anterior
- os parâmetros de entrada são avaliador e passados, e tb é passado o endereço de retorno
- transfere o controle pro subprograma chamado
- o compilador cria um código que faz alocação e liberação implícita das variáveis locais
Quais as 3 maneiras de um subprograma acessar dados externos?
Acesso direto a variáveis não locais
Acesso direto a atributos da própria classe
Passagem de parâmetros (mais confiável)
parâmetros definidos no cabeçalho do subprograma
parâmetros formais
parâmetros formais
parâmetros definidos no cabeçalho do subprograma
Parâmetros definidos na chamada do subprograma
parâmetros reais
alternativa a parâmetros posicionais
parâmetros nominais
O nome do parâmetro real é explicitamente vinculado ao nome do parâmetro formal
parâmetros nominais
usado quando nenhum parâmetro real é passado na chamada ao subprograma
valor padrâo
Quais são os 5 métodos de passagem de parâmetros?
passagem por valor
passagem por referência
passagem por resultado
passagem por valor-resultado
passagem por nome
O valor do parâmetro real é copiado para o parâmetro formal correspondente no início da execução do subprograma
passagem por valor
A variável que é o parâmetro formal é independente da variável que é o parâmetro real
passagem por valor
Vantagem e desvantagem da passagem por valor
Acesso local mais eficiente
Alocação de mais um espaço de memória
Diga se é implementação de modo de entrada, saída ou entrada e saída pra cada método de passagem de parâmetro
por valor - entrada
por referência - entrada e saída
por resultado - saída
por valor-resultado - entrada e saída
por nome - entrada e saída
O endereço do parâmetro real é copiado como valor para o parâmetro formal correspondente no início da execução do subprograma
passagem por referência
vantagens e desvantagens da passagem por referência
Economia de espaço e facilidade de manipulação de parâmetros estruturados
acesso mais lento (por ser indireto) e efeitos colaterais
o valor do parâmetro formal é copiado para o parâmetro real correspondente ao final da execução do subprograma
passagem por resultado
(na prática, algumas linguagens usam referências, então o valor é alterado simultaneamente)
Na passagem por resultado, a variável que é o parâmetro formal é independente da variável que é o parâmetro real?
Sim
Na passagem por resultado, é obrigatório definir um valor para o parâmetro dentro do subprograma (V ou F)
Verdadeiro
O valor do parâmetro real é copiado para o parâmetro formal correspondente no início da execução do subprograma e o valor do parâmetro formal é copiado para o parâmetro real correspondente ao final da execução do subprograma
passagem por valor-resultado
O nome dos parâmetros reais são substituídos textualmente pelos valores dos parâmetros formais
passagem por nome
O parâmetro formal só recebe o valor ou endereço do parâmetro real quando o parâmetro formal recebe uma atribuição ou é usado
passagem por nome
desvantagens da passagem por nome
bem mais lento e pode confundir o leitor do código
A automação dessa atividade é um dos elementos chave das linguagens funcionais e lógicas
gerenciamento em tempo de execução da memória heap
área que armazena os dados cujo formato e tamanho são conhecidos antes da execução do programa
área estática
(instruções do programa e variáveis estáticas)
gerencia a execução dos subprogramas, armazenando seus registros de ativação
pilha de tempo de execução
área da memória do programa usada para armazenar valores alocados e estruturados dinamicamente enquanto o programa está sendo executado
heap
algumas linguagens utilizam algoritmos de _________ para gerenciar a memória heap, de modo que o espaço disponível seja utilizado de forma eficiente
coleta de lixo
palavra de memória da heap
representa um endereço que pode ser alocado
Quais os três estados que uma palavra de memória pode assumir?
não usada: não alocada pelo programa
não definida: alocada, mas ainda sem valor
com valor: alocada e com valor
palavra não alocada pelo programa
não usada
palavra alocada sem valor atribuído
não definida
palavra alocada e com valor armazenado
com valor
Qual estado de palavra não ocorre em linguagens que inicializam automaticamente variáveis de tipos primitivos e objetos com construtores quando alocados?
estado não definido
Quando uma ou mais palavras contínuas são alocadas
bloco de memória
A alocação retorna o endereço da última palavra do bloco de memória (V ou F)
Falso (primeira palavra)
Quando ocorre um estouro (overflow) da heap?
quando não existe um bloco contíguo de palavras grande o suficiente para satisfazer a alocação
qualquer bloco na heap que não possa ser acessado pelo programa
lixo
lixo (variável perdida)
qualquer bloco na heap que não possa ser acessado pelo programa
Coleta de lixo
qualquer estratégia para a recuperação de blocos de memória heap para uso posterior do programa
Por que as linguagens OO demandam um gerenciamento da heap mais efetivo?
Porque os objetos tendem a ser muito maiores que as variáveis de tipos escalares, de modo que largar objetos perdidos na heap é muito mais problemático
Vantagens do coletor de lixo
- Os programas não têm bugs de ponteiros perdidos
- Os programas não sofrem deterioração gradual e travamentos causados pelo enchimento da memória — possuem estabilidade de longa duração
- Evita necessidade de código pra gerenciamento de memória dentro dos programas — código menor e mais limpo, legível e rápido de desenvolver e depurar
- A limpeza é realizada por uma thread separada, engatilhada em momentos de pouca atividade e quando a memória está cheia
- Pode tornar os programas mais rápidos (quando é necessário remover muitos itens da memória de uma vez)
Desvantagens do coletor de lixo
- O programador não tem controle do gerenciamento da memória
- O programa precisa ser interrompido para que seja executada a thread do coletor de lixo
- Nem sempre é óbvio quando o coleto é acionado, então o programa pode pausar inesperadamente
- O tempo de ação do coletor não é limitado (geralmente é rápido, mas isso não fica garantido)
- Podem manter algum objeto na memória que um desalocador explícito não manteria
Quais as duas abordagens que um algoritmo de coleta de lixo pode seguir?
Contagem de referências
Rastreamento
nos algoritmos de coleta de lixo que aplicam essa abordagem, cada objeto alocado na memória heap possui um contador que indica o número de ponteiros que apontam para ele. Um objeto com contador igual a zero é considerado lixo e pode ser apagado
contagem de referências
os algoritmos que aplicam essa abordagem de coleta de lixo realizam uma varredura a partir de todas variáveis estáticas ou dinâmicas da pilha que apontam para um objeto na heap. Essas variáveis (ponteiros ou referências) compõem o conjunto-raiz. Um objeto que não pode ser alcançado a partir do conjunto-raiz é considerado lixo e pode ser apagado
rastreamento
quando são formados grafos de conectividade?
quando campos (atributos) de um obj apontam pra outros objetos
em caso de grafos de conectividade, quais objetos não podem e quais podem ser coletados?
todos os objetos alcançáveis a partir do conjunto-raiz
objetos inalcançáveis
Vantagem da contagem de referência
ocorre dinamicamente, então o custo de execução é distribuído ao longo do programa
desvantagens da contagem de referência
- mais memória pra armazenar os contadores
- listas circulares
marcar-varrer é um algoritmo para qual abordagem?
rastreamento
Como funciona o marcar-varrer?
Cada objeto contém um bit de marca (BM), conteúdo e ponteiro pro próximo objeto
Cada objeto alcançável a partir de um ponteiro na pilha: BM = 1
Varrer: percorre toda a heap, tornando livres os objetos não marcados e desmarcando os anteriormente marcados (BM = 0)
Vantagens do marcar-varrer
recupera todo o lixo da heap e só é chamado quando ela está cheia
Desvantagens do marcar-varrer
a execução do algoritmo de coleta interrompe o programa
percorre os objetos alcançáveis a partir dos ponteiros existentes na pilha, e em seguida percorre toda a heap
Por que, para o compilador, um laço com contador é mais complexo que um laço condicional?
Porque um laço com contador demanda a criação e a manipulação automática de variáveis internas não acessíveis pelo programador. Essas variáveis armazenam o valor inicial, final, atual e o tamanho do passo do contador. Por sua vez, um laço condicional não necessita dessas variáveis internas e as iterações são controladas puramente por uma expressão condicional. Portanto, um laço com contador demanda mais memória e maior processamento.
(O laço for do C aparenta ser um laço com contador, mas na verdade não é, pois suas interações são controladas por uma expressão condicional e o contador e o tamanho do passo podem ser acessados e modificados pelo programador ao longo das interações.)
Quais as desvantagens do goto?
Pode originar erros que só podem ser detectados em tempo de execução
Compromete fortemente a legibilidade — o fluxo do programa deixa de seguir uma ordem sequencial
Qual problema ocorre com linguagens em que as cláusulas das estruturas de seleção de dois caminhos podem ser formadas por sentenças tanto simples quanto compostas?
Quando correm if’s aninhados, a sintaxe sozinha não consegue determinar para qual deles um else irá pertencer. Para resolver isso, é necessária uma regra semântica que determine, por exemplo, que o else “sempre pertence ao if anterior mais próximo”.
Qual a diferença entre os laços com contador do Pascal e do C?
O for do pascal é um laço com contador e, por isso, não permite que o valor da variável i seja alterado. É permitida apenas a leitura. O for do C é um laço condicional, sendo possível manipular todas as variáveis do laço livremente, mesmo que isso afete o número de iterações.
O que é uma exceção? O que é um tratador de exceção?
Uma exceção é um evento causado de uma situação errônea que, se não for tradada, provoca uma interrupção abrupta na execução do programa. A gravidade de uma exceção depende da sua natureza. Tratador de exceção é o trecho de código que é acionado em resposta ao lançamento de uma determinada exceção, com o objetivo de corrigi-la ou, pelo menos, amenizá-la.
Explique como funciona o algoritmo de coleta de lixo Coleta de Cópias.
Esse algoritmo segue o estilo de marcar-varrer, mas com apenas uma passagem. Ele divide o espaço da memória heap em duas áreas, origem e destino, sendo que o primeiro é utilizado para armazenar as variáveis/objetos e o segundo representa uma zona morta. Todos as variáveis/objetos dinâmicas da heap são alocadas um após o outro a partir do início da origem. Isso significa que o espaço de memória livre é sempre o próximo endereço após o último ocupado, o que elimina a necessidade de manter uma lista de espaços livres. Quando a área de origem enche, ou seja, o ponteiro do próximo livre aponta o final da origem, a varredura da coleta de lixo tem início. Ela percorre todo o espaço de origem e copia para a área de destino somente as variáveis/objetos alcançáveis a partir do conjunto raiz. Em seguida, o ponteiro de endereço livre passa a apontar para o próximo endereço após o último ocupado no destino e o espaço de destino se torna o espaço de origem e vice-versa. Portanto, todos as variáveis/objetos não alcançáveis que não foram copiados para o espaço o novo espaço de origem passam a ser considerados como liberados.
Por que o uso de valores padrão para parâmetros e a coerção podem complicar a sobrecarga de subprogramas?
Porque demandam a inclusão de regras semânticas na linguagem para permitir a diferenciação dos subprogramas sobrecarregados em uma chamada. Por exemplo, no código 1, a valor padrão gera uma ambiguidade na chamada ao subprograma sub1. Será executada o subprograma com uma entrada ou o que possui duas, com y assumindo o valor padrão? A mesma situação ocorre no código 2, desta vez provocada por uma possível coerção do tipo int para float. Será executado o subprograma com o parâmetro do tipo int ou o que possui a entrada do tipo float? Normalmente, as linguagens possuem uma regra semântica que prioriza a opção mais estrita, que, em ambos os exemplos, é o primeiro subprograma.
Vantagens e desvantagens da coleta de cópias
V: mais rápido q o marcar-varrer quando a qtd de objetos ativos é muito menor que metade da área da heap
D:* Reduz o tamanho da heap pela metade
* É mais lento que o marcar-varrer quando a qtd de objetos ativos é próxima da metade da heap
* A execução também gera um custo que interrompe o programa até ser finalizada.
Diferença entre parâmetros nominais e passagem por nome
O parâmetro nominal é a alternativa ao parâmetro posicional, em que o nome do parâmetro real deve ser explicitamente vinculado ao nome do parâmetro formal.
A passagem por nome é a substituição textual do nome do parâmetro real pelo valor do parâmetro formal.