Olha. Eu gostaria de ter aprendido as diversas maneiras de se exibir tanto o endereço de memória como o conteúdo de memória apontado por um ponteiro.
Resumindo, seria mais ou menos o código abaixo. Se faltar alguma coisa, irei adicionando.
#include <stdlib.h>
int main()
{
char ponteiro[5]="ABCDE";
printf("Comandos equivalentes em C\n\n");
printf("Considerando 'char ponteiro[5]=\"ABCDE\";'\n\n");
printf("Primeiro endereco do ponteiro:%p \n\n",ponteiro);
printf("Primeiro conteudo de ponteiro[0]: %c\n",ponteiro[0]);
printf("Primeiro conteudo de *ponteiro: %c\n\n",*ponteiro);
printf("Conteudo de ponteiro[1] : %c\n",ponteiro[1]);
printf("Conteudo de *(ponteiro+1): %c\n\n",*(ponteiro+1));
printf("Endereco de memoria de (&ponteiro[1]):%p\n",(&ponteiro[1]));
printf("Endereco de memoria de (&ponteiro+1) :%p\n\n",(ponteiro+1));
return 0;
}
Pergunta originalmente respondida no QUORA em 03/07/2019
Definição de Heap:
Heap é uma árvore binária com chaves em seus nós (uma chave por nó) conforme a seguir:
Ela
é essencialmente completa, ou seja, todos os seus níveis são completos
menos o último nível, onde somente a chave mais à direita pode
eventualmente estar faltando.
*A chave de cada nó pai (acima) é maior ou igual à chave filho (que vem abaixo).
Observe:
Os elementos de uma heap são ordenados de cima para baixo (junto com
qualquer caminho abaixo de sua raiz), porém eles não são ordenados da
esquerda para a direita.
Algumas propriedades de uma heap:
Dado n, há uma única árvore binária com n nós que é essencialmente completa com h=[log2n]
.
A raiz contém o maior valor chave
Uma sub árvore extraída de qualquer nó de uma heap também é uma heap
Stack
ou pilha é um conjunto ordenado de itens no qual novos itens podem ser
inseridos e a partir do qual podem ser eliminados itens um uma
extremidade chamada topo da pilha.
Ao contrário do vetor, a definição de pilha abrange a inserção e remoção de itens o que a faz um objeto dinâmico, mutável.
Por
definição somente uma extremidade é designada como topo da pilha. Novos
itens podem ser adicionados no topo da pilha, consequentemente
deslocando o topo da pilha para cima e os itens que estão no topo da
pilha podem ser removidos, consequentemente deslocando o topo da pilha
para baixo.
O topo
da pilha é a extremidade em que os dados são inseridos e retirados da
pilha e por essa razão uma pilha também é chamada de LIFO, last in first out, último a entrar, primeiro a sair.
A
pilha, computacionalmente, sempre é vista pelo topo, de cima para baixo
(somente pode-se observar o topo da pilha), embora para explicar seu
funcionamento a pilha seja exibida em perfil.
Para
acessar o último elemento de uma pilha é necessário desempilhar os
elementos que estiverem por cima do último elemento para poder
acessá-lo, conforme imagem abaixo (clique para ampliar).
Fonte
da difinição de stack: TENENBAUM, Aaron M.; LANGSAM, Yedidyah;
AUGESNSTEIN, Moshe J.. Estruturas de Dados Usando C. São Paulo: Pearson,
2013. 884 p. ISBN 13: 978-85-346-0348-5.
No começo de minha carreira eu tive o prazer de trabalhar com um técnico de computadores, senior, na antiga Burroughs Eletrônica. Isso foi nos idos de 1985 e muitos de vocês sequer pensavam em nascer kkkk.
Então, ele tinha um bordão que utilizava quando a gente se enrolava em consertar os mainframes que era o seguinte:
“Quando tudo o mais falhar, siga o manual”
Nelson Zart
Pois é. hoje me lembrei dele em dois momentos.
Um deles eu estava configurando o Apache Directory Studio para acessar o LDAP do Google Workspace Enterprise e tive de configurar o Stunnel seguindo o manual e em outro caso, meu colega estava se batendo para fazer o agente GLPI subir o status no servidor do GLPI.
Em ambos os casos, só conseguimos resolver esses problemas após lermos a documentação e proceder com a configuração, conforme indicado nos respectivos manuais.
Nada de fórum, Stack Overflow e adivinhação. Definitivamente foi a leitura do manual que resolveu o perrengue.
Em computação, hexadecimal é muito mais fácil de entender.
Quando um programador que manja de hardware olha para um código hexadecimal, ele sabe exatamente como o hardware está se comportando, apenas fazendo contas de cabeça.
Por isso que o hexadecimal é utilizado.
Não leia o resto.
Modo nerdice on.
Computador trabalha com lógica binária.
Pensando em um computador de 8 bits, sabemos que ele consegue manusear 8 bits por vez em sua linha de dados.
No diagrama abaixo temos um computador simplificado:
Do lado esquerdo tem o processador e do lado direito tem a memória. Deixei de fora alguns detalhes para ficar mais fácil a explicação.
O processador e a memória são interligados pelo barramento de endereçamento, de dados e as linhas de controle.
O barramento de dados está detalhando os 8 bits que o compõe.
Cada seta no barramento de dados representa um bit de dados.
O processador consegue ler e escrever na memória, 8 bits de dados por vez, pois trata-se de um computador de 8 bits.
Os bits, são essas linhas que podem assumir valores binários de zero ou um.
Eletronicamente falando:
Essas linhas dos bits de dados podem estar energizadas ou não.
As linhas que estiverem energizadas terão o valor lógico VERDADEIRO (1 – um) e as que não estiverem energizadas terão o valor lógico FALSO (0 – zero).
Onde entra o hexadecimal:
Note que o barramento de dados foi separado em dois conjuntos de 4 bits.
Um conjunto de 4 bits engloba os bits de 0 a 3
O segundo conjunto de 4 bits engloba os bits de 4 a 7
A pergunta que a gente faz agora é: Quantas combinações a gente consegue fazer de bits ligados e desligados aqui?
Já dou a resposta, que são 256 combinações indo de todos os 8 bits com valor FALSO – desligados até termos todos os 8 bits com o valor VERDADEIRO – ligados.
Acompanhe, analisando os 4 primeiros bits:
Os caras fizeram o seguinte, os quatro primeiros bits, dá para fazer 16 combinações indo do valor decimal zero até o valor decimal 15. Basta continuar com a tabela adicionando os bits que faltam e iremos chegar em 256 combinações, podendo representar os números de zero a 255..
Mais um detalhe: A posição do bit corresponde a um valor decimal. Se os bits zero e dois forem verdadeiros, significa que temos o número 5 nas notações decimal e hexadecimal, por exemplo.
Conforme dito, se pegar o segundo conjunto de 4 bits, também dá para fazer essas dezesseis combinações.
Juntando o primeiro e o segundo conjunto de 4 bits, dá para fazer 16 X 16 combinações, ou seja, dá para fazer 256 combinações, que é capaz de representar os valores decimais indo de zero a 255.
No fim de tudo é isso o que realmente importa:
Para simplificar isso aí, os bits são separados em grupos de 4 bits que são representados pelos símbolos indo de “0” até “F”.
Um código indicando quais linhas de cada conjunto de 4 bits estão ligadas ou desligadas.
Simples e brilhante.
Desenvolvendo computadores:
Agora, se coloque no lugar do desenvolvedor de computadores.
O cara tem que lidar com o circuito elétrico. Tem que olhar para um código e decodificar de cabeça quais linhas do barramento de dados estão energizadas ou não.
É muito mais fácil para um engenheiro de hardware:
Separar a linha de dados em grupos de 4 bits.
Trabalhar com a notação hexadecimal, 3A por exemplo.
Converter esse número, de cabeça para o binário “0011 1010”.
E identificar no barramento quais linhas de dados que estão energizadas ou não…
Do que fazer a conversão do número 58 (decimal) para seu correspondente binário, que é bem mais complicado.
É por isso que se utiliza o hexadecimal.
Hexadecimal é para humanos falarem com máquinas, enquanto que decimal é para máquinas falarem com humanos.
Recomendo que seja lido o livro do Tocci, que já indiquei em outras respostas por aqui.
O que tem a ver uma tradicional receita de pudim e a contagem binária de 8 bits, indo de zero a 255?
Pergunta respondida originalmente no Quora em 25/02/2021
Pudim de 8 bits:
Ingredientes:
1 lata de leite moça
2 medidas de leite da lata de leite moça.
4 ovos (tire a pele da gema).
8 colheres de sopa, bem cheias de açúcar.
Modo de preparo:
Por 16 minutos aqueça o açúcar em uma forma de pudim até formar o caramelo de açúcar. Cuidado para não queimar o açúcar. Espalhe esse caramelo pela forma até ela ficar bem amarelinha.
Por no máximo 32 minutos, bata em um liquidificador a 1 medida de leite moça, as 2 medidas de leite e os 4 ovos.
Coloque, na forma caramelizada, o conteúdo previamente batido no liquidificador.
Asse o pudim em Banho Maria por 64 minutos em um forno pré aquecido a 128°C, assim que colocar a forma no forno, ajuste a temperatura do forno para que fique em torno de 255°C.
Responder essa, parece que estão querendo colocar os programadores em um patamar superior. SQN. Programadores precisam se dedicar muito nessa profissão.
A profissão de programador, como um todo, demanda que o profissional seja capaz de desmembrar tarefas complexas em passos menores e facilmente executáveis, utilizando uma linguagem extremamente precisa e que não admite erros.
Programas simples como solicitar que um led acenda ao abrirmos uma porta, demandam uma série de instruções que precisam estar ordenadas na sequência correta e devem ser sintática e semanticamente corretas.
Exemplificando, para o Arduino, um programa desses que acende ou apaga um led a partir do monitoramento de um sensor, seria mais ou menos assim:
#include <Arduino.h>
int ledPortaAberta=8;
int ledPortaFechada=10;
int sensorPorta=6;
#define DESLIGADO LOW
#define LIGADO HIGH
void setup(){
pinMode(ledPortaAberta, OUTPUT);
pinMode(ledPortaFechada, OUTPUT);
pinMode(sensorPorta, INPUT);
Serial.begin(9600);
}
void loop(){
if (digitalRead(sensorPorta)==LIGADO){
digitalWrite(ledPortaAberta, DESLIGADO);
digitalWrite(ledPortaFechada, LIGADO);
Serial.println("Porta fechada");
}
else {
digitalWrite(ledPortaAberta, LIGADO);
digitalWrite(ledPortaFechada, DESLIGADO);
Serial.println("Porta aberta");
}
delay(1);
}
Conforme dito, o programa não deve ter nenhum erro sintático, caso contrário ele não ele não irá compilar e muito menos será possível gerar o código executável abaixo:
Ainda assim, não basta saber escrever o programa, colocar os comandos na sequência correta, seguir todas regras da linguagem, saber compilar, gerar esse código hexadecimal e até entender cada um dos comandos hexa acima.
O programa também tem que ser semanticamente correto.
A semântica, o sentido das palavras bem como a interpretação das sentenças e dos enunciados utilizados nessa linguagem acima devem refletir exatamente o que foi solicitado em linguagem natural, “quando uma porta se abre, um led se acende e quanto a mesma porta se fecha, o led tem que apagar”.
O trabalho do programador é converter um requisito em linguagem natural para a linguagem formal.
Esse trabalho de fazer a conversão e garantir que a semântica de ambas linguagens estejam alinhadas é onde está a arte e o desafio que programadores enfrentam todos os dias.
Dá para aprender, mas eu diria que poucos são metódicos o suficiente para tal.
É uma questão de perfil, nada mais.
Resposta originalmente postada no Quora em 29/maio/2020 e fonte da foto do teclado: https://www.cybercentralcorp.com/blog/
Se você instalou o Maven para Rodar com o Windows e está tentando usar o Oracle JDeveloper ou alguma outra IDE da Oracle e as coisas não estão funcionando muito bem, talvez seja a hora de ajustar algumas configurações no seu Windows.
Baixe o Maven do site da Apache próprio para o Windows, descompacte e mova a pasta com o Maven para a pasta Arquivos de Programas ou para o diretório de sua escolha.
Em propriedades do sistema do Windows, adicione a variável de ambiente M2_HOME com o valor do caminho do Maven
Adicione a variável de ambiente M2 nas variáveis de ambiente com o valor %M2_HOME%\bin
Adicione a variável de ambiente MAVEN_OPTS com o valor -Xms256m -Xmx512m
Adicione a variável de ambiente JAVA_HOME. Ela deve apontar para o diretório raiz do JDK (o diretório do JRE não serve para nada).
Inclua %M2% na variável de ambiente Path
Inclua %JAVA_HOME%\bin na variável de ambiente Path
No prompt de comando execute mvn –version para verificar se o Maven instalou ok.
Olha, dei uma lida no Sommerville e lá está escrito mais ou menos o seguinte:
Requisitos funcionais:
É
a definição das funcionalidades que um sistema de software deve
fornecer. Esse tipo de requisito informa como o sistema deve trabalhar
os dados de entrada e quais informações devem ser geradas na saída.
Serve
para definir o comportamento do sistema em situações específicas. Os
requisitos funcionais também servem para definir o escopo do sistema de
software ao limitarem explicitamente o que o sistema deve ou não deve
fazer.
Requisitos não funcionais:
Esse
tipo de requisito trata das limitações nos serviços ou funções
oferecidas pelo sistema baseando em parâmetros como “número de
transações por segundo”, “número de usuários operando o sistema ao mesmo
tempo” ou limitações impostas por padronizações, por exemplo.
Requisitos
não funcionais muitas vezes se aplicam à implementação e operação do
sistema como um todo ao contrário de focar em funcionalidades e ou
serviços individuais de sistemas.
Na
verdade, há uma linha não muito clara entre o que é requisito funcional
e não funcional. Dependendo da abordagem isso pode ficar confuso.
Um
requisito de usuário de segurança como limitar o tempo de acesso de
usuários autenticados, pode se enquadrar como requisito não funcional.
Entretanto
quando visto com mais detalhes, o requisito de limitar o tempo de
acesso de usuário pode se desdobrar em outros requisitos claramente
funcionais.
Esse desdobramento pode levar o requisito da limitação do tempo de acesso a ser tratado como um requisito funcional.
Isso
mostra que requisitos de um sistema de software são interligados e um
requisito pode gerar limitações, influenciar ou mesmo acabar gerando
outros requisitos.
Os requisitos de sistema entretanto não só especificam serviços ou funcionalidades do sistema.
Eles também especificam o que é necessário para assegurar que os serviços e funcionalidades sejam efetivamente entregues.
Aí galera, segue a minha visão sobre o assunto depois de dar uma lida no Sommerville.
Um
dos objetivos do processo de elucidação de requisitos é conhecer o
trabalho que os stakeholders (interessados no projeto) querem
implementar no sistema, de forma a ajudá-los em suas atividades.
Durante
a elucidação de requisitos, os engenheiros de software trabalham junto
com os stakeholders para entender o domínio da aplicação.
Os
engenheiros de software levantam as atividades trabalhadas, os
serviços, as funcionalidades que precisam ser implementadas no sistema,
bem com tomam conhecimento da performance desejada e assimilam as
limitações impostas pelo hardware, dentre outros pontos.
Dado
que pessoas, incluindo stakeholders, normalmente tem dificuldades em
definirem requisitos de forma abstrata, muitas vezes eles são levantados
a partir de exemplos da vida real, mais fáceis de serem obtidos.
Pessoas
são capazes de descrever como enfrentam situações particulares ou são
boas em descreverem como seria possível, a elas, melhorarem seus métodos
de trabalho.
Levantamento
de histórias e cenários é uma ferramenta poderosa para que engenheiros
de software capturarem esse tipo de informação, normalmente descrita em
linguagem natural.
De
posse dessas histórias e cenários, o engenheiro de software os utiliza
nas reuniões com os stakeholders para definir quais funcionalidades do
software devem ser implementadas e ou deprecadas.
Para saber mais:
SOMMERVILLE, Ian. Software Engineering: Tenth Edition. 10. ed. Boston: Pearson, 2016. 796 p. ISBN 13: 978-0-13-394303-0. –
Esses
dias eu estava acessando alguns sites e começou a dar aquele maldito
erro informando que a conexão não é confiável, cada vez que tentava
acessar sites do governo.
Isso
acontece porque o governo emite seus certificados de segurança e por
algum motivo o certificado raiz não consta na instalação do Windows e
Linux. Fica faltando e é uma droga.
Como faz para resolver esse B.O?
O
incomodado tem que sair procurando o certificado certo, fazer o
download e instalar. É um inconveniente no calor das entregas das
tarefas do escritório, fora que se formatar o computador, tem que fazer
tudo de novo.
Isso é um saco para quem manja de TI e deve ser Aramaico para quem é de humanas.
Esse funcionário público que teve essa ideia merece uma caixa de Bis de presente. Quem o conhecer, mande os parabéns!
Uma
vez encontrado um arquivo com todos certificados, bastaria descompactar
e instalar os certificados, mas aí o problema complica:
São 164 certificados (em 2022)!
Cada um tem que dar uma meia dúzia de cliques nos locais certos.
Se fizer errado, o certificado não instala direito, fica tudo zoado e não funciona.
Há risco de esquecer de instalar alguns certificados.
Há o risco de ficar reinstalando certificados já instalados.
O processo é demorado pra caramba, leva cerca de 1 hora por computador, muito tempo para uma pequena empresa, por exemplo.
“Ainda bem que sei programar” entra a partir desse ponto.
Após uma breve internetada, achei um script de PowerShell, o ajustei para as minhas necessidades e mandei rodar.
Como eu fiz?
O código pronto está aí embaixo. em linhas gerais:
Baixei e descompactei o arquivo em um diretório temporário
Abri o editor do PowerShell e naveguei até o diretório
Dei um “ls>diretorio.csv” para listar o diretório em um arquivo csv
Abri o arquivo no Excel e com umas fórmulas, montei o caminho dos arquivos
Depois usei essa informação para montar o script
Instalou todos certificados de uma vez em menos de 1 minuto.
Na prática fazer isso pela primeira vez levaria o mesmo tempo que fazer manualmente, mas dessa forma todos certificados foram instalados corretamente (com certeza), com os cliques corretos e sem esquecer de ninguém. Fora que nas próximas, supostamente sofrerei menos com a instalação de certificados, fora que hoje 07/2022 eu tive de repetir essa instalação e rodou em minutos, pois eu já tinha feito o caminho das pedras 🙂
Programadores entenderão:
O script está aqui, é específico para minha máquina e não segue nenhuma das boas práticas de programação, mas resolveu o B.O.