https://wiki.sj.ifsc.edu.br/api.php?action=feedcontributions&user=Msobral&feedformat=atomMediaWiki do Campus São José - Contribuições do(a) usuário(a) [pt-br]2024-03-28T19:43:14ZContribuições do(a) usuário(a)MediaWiki 1.35.9https://wiki.sj.ifsc.edu.br/index.php?title=PJI3_Avalia%C3%A7%C3%A3o_2&diff=181972PJI3 Avaliação 22022-03-09T21:32:58Z<p>Msobral: </p>
<hr />
<div>A conclusão da etapa 2 envolve implantar a rede de acesso e os enlaces WAN de um provedor. A demonstração dessa rede deve ser feita com esta topologia:<br />
<br />
<br />
[[imagem:pji3_Avaliacao_unidade4.jpg|800px]]<br />
<br><br>''A rede de acesso e o link WAN do provedor''<br />
<br />
<br />
As seguintes informações devem orientar a implantação dessa rede:<br />
* Do lado do provedor, um switch deve ser usado para implantar a LAN de Agegação.<br />
* Os links sem-fio PTMP devem ser feitos com CPE dos clientes operando como roteadores com suporte a NAT.<br />
* Links EPON e PTMP devem ser implantados com PPPoE.<br />
* Links PPPoE devem ser autenticados, de forma que cada cliente possua seu usuário e senha.<br />
<!--** A autenticação deve ser feita usando o serviço RADIUS, o qual reside no servidor de autenticação. --><br />
* O link WAN é do tipo Ethernet.<br />
* A subrede IP da rede de agregação do provedor fica a critério da turma.<br />
* A subrede IP a ser usada nas interfaces WAN dos CPE dos clientes é 192.168.2.0/24. Essa subrede foi fornecida pela operadora para uso do provedor.<br />
* O roteador de borda deve usar IP 191.36.13.61/26 em sua interface WAN.<br />
** O roteador default para o roteador de borda tem IP 191.36.13.62<br />
** O roteador de borda NÃO deve ativar NAT<br />
<br />
= Manuais e softwares =<br />
<br />
* [http://tele.sj.ifsc.edu.br/~msobral/pji3/intelbras/ Manuais e software Intelbras (OLT e ONU)]<br />
* [http://backend.intelbras.com/sites/default/files/integration/manual_usuario_wom_5000_portugues_03-17_site.pdf Manual do WOM5000]<br />
* [https://www.intelbras.com/pt-br/cpe-5-ghz-12-dbi-wom-5000i Página do WOM 5000i no site do fabricante]<br />
* [https://wiki.mikrotik.com/wiki/Manual:TOC Manual do software do roteador Mikrotik]<br />
<br />
= Avaliação = <br />
<br />
Essa rede deve ser implantada pela turma nas aulas dos dia 09 e 11/03, e sua avaliação irá considerar o seguinte:<br />
* a implantação da rede conforme a especificação<br />
* a explicação da turma sobre soluções específicas realizadas na implantação, quando questionada<br />
* o correto funcionamento da rede: dispositivos nas redes dos clientes devem conseguir acessar a Internet<br />
<br />
Um relatório deverá ser entregue com a documentação da rede que foi implantada. Ele inclui:<br />
* Quais equipamentos foram utilizados, e com que finalidade, além de indicar onde na rede foram usados<br />
* Uma explicação sobre as configurações necessárias em cada equipamento (seu modo de operação)<br />
* O plano de endereçamento IP usado na rede, tanto a do provedor quanto dos clientes</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3_Avaliacao_unidade4.jpg&diff=181971Arquivo:Pji3 Avaliacao unidade4.jpg2022-03-09T21:27:01Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3_Avalia%C3%A7%C3%A3o_2&diff=181970PJI3 Avaliação 22022-03-09T21:09:07Z<p>Msobral: Criou página com 'A conclusão da etapa 2 envolve implantar a rede de acesso e os enlaces WAN de um provedor. A demonstração dessa rede deve ser feita com esta topologia: imagem:ier-Etapa...'</p>
<hr />
<div>A conclusão da etapa 2 envolve implantar a rede de acesso e os enlaces WAN de um provedor. A demonstração dessa rede deve ser feita com esta topologia:<br />
<br />
<br />
[[imagem:ier-Etapa2-avaliacao.jpg|800px]]<br />
<br><br>''A rede de acesso e o link WAN do provedor''<br />
<br />
<br />
As seguintes informações devem orientar a implantação dessa rede:<br />
* Do lado do provedor, um switch deve ser usado para implantar a LAN de Agegação.<br />
* Os links sem-fio PTMP devem ser feitos com CPE dos clientes operando como roteadores com suporte a NAT.<br />
* Links <strike>ADSL,</strike> EPON e PTMP devem ser implantados com PPPoE.<br />
* Links PPPoE devem ser autenticados, de forma que cada cliente possua seu usuário e senha.<br />
<!--** A autenticação deve ser feita usando o serviço RADIUS, o qual reside no servidor de autenticação. --><br />
*<strike>*Os links EPON devem ter taxa de downstream e upstream de acordo com o plano contratado:<br />
** '''VIP:''' 100Mbps/20Mbps<br />
** '''Fast:''' 50Mbps/10Mbps<br />
** '''Light:''' 10Mbps/2Mbps</strike><br />
* O link WAN é do tipo Ethernet.<br />
* A subrede IP da rede de agregação do provedor fica a critério da turma.<br />
* A subrede IP a ser usada nas interfaces WAN dos CPE dos clientes é 192.168.2.0/24. Essa subrede foi fornecida pela operadora para uso do provedor.<br />
* O roteador de borda deve usar IP 192.168.1.222/24 em sua interface WAN.<br />
** O roteador default para o roteador de borda tem IP 192.168.1.254<br />
** O roteador de borda NÃO deve ativar NAT<br />
<br />
= Manuais e softwares =<br />
<br />
* [http://tele.sj.ifsc.edu.br/~msobral/pji3/ems/ Manual e software para DSLAM]<br />
* [http://tele.sj.ifsc.edu.br/~msobral/pji3/intelbras/ Manuais e software Intelbras (OLT e ONU)]<br />
* [http://backend.intelbras.com/sites/default/files/integration/manual_usuario_wom_5000_portugues_03-17_site.pdf Manual do WOM5000]<br />
* [https://www.intelbras.com/pt-br/cpe-5-ghz-12-dbi-wom-5000i Página do WOM 5000i no site do fabricante]<br />
<br />
= Avaliação = <br />
<br />
Essa rede deve ser implantada pela turma na aula do dia 11/12, e sua avaliação irá considerar o seguinte:<br />
* a implantação da rede conforme a especificação<br />
* a explicação da turma sobre soluções específicas realizadas na implantação, quando questionada<br />
* o correto funcionamento da rede: dispositivos nas redes dos clientes devem conseguir acessar a Internet<br />
<br />
<br />
Além da atividade prática, uma avaliação individual será realizada no SIGAA no dia 13/12. Essa avaliação será composta por ao menos 4 questões de múltipla escolha ou discursivas, as quais abordam as técnicas estudadas.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Hor%C3%A1rios_dos_Cursos_do_IFSC_Campus_S%C3%A3o_Jos%C3%A9&diff=180712Horários dos Cursos do IFSC Campus São José2021-12-16T13:00:19Z<p>Msobral: /* Horários de atendimento paralelo dos professores do curso de Engenharia de Telecomunicações */</p>
<hr />
<div>Link curto: https://bit.ly/IFSC_SJE_HORARIO<br />
<br />
=Tabela de horários completa=<br />
<br />
'''<span style="font-size:large;">[https://ifsc-sj.edupage.org/timetable/view.php?fullscreen=1 Horários de aula do semestre]</span> '''<br />
'''Orientações:'''<br />
<br />
* Existem três opções de horário no link acima.<br />
*# Por turmas<br />
*# Por professores, sendo a listagem dos professores ordenada alfabeticamente pelo primeiro nome, mas é mostrada invertida pelo software [sobrenome] depois [nome].<br />
*# Por salas / laboratórios<br />
<br />
==Aulas presenciais x ANP no curso de Engenharia de Telecomunicações==<br />
No documento abaixo, estão indicados para todas as disciplinas (UCs) como ocorrerão as aulas '''no período de 06/12 a 23/12'''. <br />
<br />
Recomenda-se que os alunos sempre confiram com seus professores e na página do SIGAA da disciplina os detalhes do horário.<br />
<br />
<br />
<br />
<center><br />
'''[[Media:AulasANPxPresenciaisEngtelecomFase3.pdf | Horário das aulas da Engtelecom de 06/12 a 23/12]]'''<br />
</center><br />
<br />
Note que nos horários há uma faixa a direita em <span style="color: rgb(0, 0, 255);" data-mce-style="color: #0000ff;">azul</span> para aulas em <span style="color: rgb(0, 0, 255);" data-mce-style="color: #0000ff;">ANP</span> e <span style="color: rgb(0, 255, 0);" data-mce-style="color: #00ff00;">verde</span> para aulas <span style="color: rgb(0, 255, 0);" data-mce-style="color: #00ff00;">Presenciais</span>.<br />
<center><br />
[[Arquivo:ANPxPresencial.png | 400px]]<br />
</center><br />
<br />
==Horários de atendimento paralelo dos professores do curso de Engenharia de Telecomunicações==<br />
<br />
{{InicioAP}}<br />
<!-- Não inserir dados aqui, pois são gerados automaticamente na planilha [Opções para Fase 3 e 4 Engenharia] aba [TD - Atendimento parelalo] --><br />
{{AP |Arliones Stevert Hoeller Junior|SEG 11:30-12:30; TER 17:30-18:30||https://meet.google.com/qwe-qdzg-sfy|fazer agendamento prévio para ser atendido online ou presencial}}<br />
{{AP |Carlos Boabaid Neto||||}}<br />
{{AP |Carlyle Camara Santos Junior|Remoto: TER 15h30 - 17h30||https://meet.google.com/ine-yqah-xnz|Fazer agendamento prévio}}<br />
{{AP |Deise Juliane Mazera|Remoto: SEX 13:30 - 15:30||https://meet.google.com/xxq-iptm-tei|}}<br />
{{AP |Deise Monquelate Arndt||||}}<br />
{{AP |Ederson Torresini|Remoto: TER 13h30||https://meet.google.com/iyu-qwfr-zbh|fazer agendamento prévio}}<br />
{{AP |Elen Macedo Lobato||||}}<br />
{{AP |Emerson Ribeiro de Mello||||}}<br />
{{AP |Eraldo Silveira e Silva||||}}<br />
{{AP |Evanaska M. B. Nogueira||||}}<br />
{{AP |Fábio Alexandre de Souza|Remoto: TER 08h30||https://meet.google.com/cgr-cxtp-nxn|fazer agendamento prévio}}<br />
{{AP |Felipe Silveira de Souza||||}}<br />
{{AP |Humberto Luz Oliveira||||}}<br />
{{AP |Jesue Graciliano da Silva||||}}<br />
{{AP |Jorge Henrique Busatto Casagrande||||}}<br />
{{AP |Josué de Oliveira Pinheiro Filho||||}}<br />
{{AP |Leone Carmo Garcia|QQ horário||via whatsApp|}}<br />
{{AP |Louis Augusto Gonçalves||||}}<br />
{{AP |Madeline Odete Silva Corrêa||||}}<br />
{{AP |Marcelo Girardi Schappo|Cada turma tem um horário específico||Google Meet|Verificar link da sua turma no SIGAA}}<br />
{{AP |Marcelo Maia Sobral|Atendimento feito por demanda, em horários a combinar||Google Meet|Solicitar atendimento via Slack ou email}}<br />
{{AP |Márcio Henrique Doniak|Remoto: TER 10:00 - 11:00||https://conferenciaweb.rnp.br/webconf/com29008-sistemas-de-comunicacao-2|}}<br />
{{AP |Marcos Moecke|Remoto: TER 11:30 - 12:00 (DLP); Presencial: QUI 11:30 - 12:00|LabSiDi|https://meet.google.com/cyy-ohdp-kai|fazer agendamento prévio}}<br />
{{AP |Marcos Moecke|Remoto: TER 17:15 - 18:00 (TCC); Presencial: QUI 11:30 - 12:00|LabSiDi|https://meet.google.com/zvw-jtkj-bbh|fazer agendamento prévio}}<br />
{{AP |Mario de Noronha Neto|Remoto: QUI 13h30 - 14h30; Remoto SEX 11h00 - 12h00||https://meet.google.com/cvb-hjeg-mth|}}<br />
{{AP |Nilton Francisco Oliveira da Silva||||}}<br />
{{AP |Odilson Tadeu Valle|Remoto: QUA 13:30 - 14:30; Remoto: SEX 08:30 - 09:30||https://meet.google.com/vmo-dhyd-rir|}}<br />
{{AP |Políbio Ícaro Moro Capo|Remoto: QUA 13:30 - 15:20 (ELI)||https://meet.google.com/ipy-vgst-ery|}}<br />
{{AP |Políbio Ícaro Moro Capo|Remoto: TER 13:30 - 15:20 (ADM)||https://meet.google.com/puw-cstg-hkm|}}<br />
{{AP |Roberto de Matos|Presencial: QUA 10h às 12h|Sala Prof. Tele2||}}<br />
{{AP |Roberto Wanderley da Nóbrega|Remoto: TER 14:25 - 16:35, QUI 14:25 - 16:35.|||A combinar por email ou Google Chat.}}<br />
{{AP |Rubem Toledo Bergamo||||}}<br />
{{AP |Salézio Francisco Momm|Presencial: SEX 9:30 - 11:30; Remoto: TER 9:30 - 11:30|Laboratório de física |https://meet.google.com/bsp-mxne-wva|}}<br />
{{AP |Samuel Luna de Abreu|Seg 15:40 - 17:30 / Seg 18:30-19:25|||A combinar por email ou grupo whatsapp}}<br />
{{AP |Sandro Carlos Lima||||}}<br />
{{AP |Saul Silva Caetano|Remoto: SEX 09:40 - 11:30||https://meet.google.com/ema-wqpv-onc|}}<br />
{{AP |Sérgio Florentino da Silva|Remoto: QUA 15:40 - 16h40 (ALG)|whatsapp (48 996342960) |https://meet.google.com/bqp-mged-rqs|}}<br />
{{AP |Sérgio Florentino da Silva|Remoto: SEG 9:40 - 10h40 (GEA)|whatsapp (48 996342960) |https://meet.google.com/pqw-niuk-coj|}}<br />
{{AP |Sérgio Pereira da Rocha||||}}<br />
{{AP |Silviana Cirino||||}}<br />
{{AP |Vitor Sales Dias da Rosa||||}}<br />
{{AP |Volnei Velleda Rodrigues|Remoto: SEX 11h - 12h; Presencial: TER 17h30 - 18h30|Sala 09|https://meet.google.com/buj-wanh-reu|}}<br />
|}<br />
<br />
=Informações sobre o calendário acadêmico=<br />
<br />
'''<span style="font-size:large;">[[Calend%C3%A1rio_Acad%C3%AAmico_do_IF-SC_Campus_S%C3%A3o_Jos%C3%A9|Calendário Acadêmico]]</span> '''<br />
<br />
=Capacidade dos ambientes de ensino durante a Pandemia de COVID-19=<br />
De acordo com o '''PLANO DE CONTINGÊNCIA DO CAMPUS SÃO JOSÉ''' as salas de aula e laboratórios terão o seu numero de ocupantes limitado, em função da exigência de '''distanciamento de <S>1,5 metros</S> 1 metro'''. Para garantir o distanciamento, todos os ambientes foram marcados e as posições que não devem ser ocupadas estão assinaladas com um '''X''' vermelho. <br />
<br />
As tabelas a seguir indicam para cada ambiente a capacidade atual desses ambientes, e deve ser considerada pelos professores no planejamento das atividades presenciais.<br />
<br />
As capacidades citadas abaixo são totais. Por exemplo, para uma sala com capacidade para 19 pessoas deve-se considerar o professor + 18 alunos.<br />
<br />
==Capacidade das Salas de Aula de 01 a 14==<br />
<!--{{fig|1|Tabela D1 - Capacidade das salas de aula de 01 a 14 | PSS_SJE_TabelaD1.png| 600 px | PLANO DE CONTINGÊNCIA DO CAMPUS SÃO JOSÉ}}--><br />
<center><br />
{| class="wikitable"<br />
! Local || Profundidade [cm] || Comprimento [cm] || Área [m2] || Capacidade normal || Capacidade para distância <s>1,5m</s> 1,0m <span style="color:red">(em revisão)</span><br />
|-<br />
| Sala 01 || 920 || 577 || 53,08 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 02 || 920 || 586 || 53,91 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 03 || 920 || 586 || 53,91 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 04 || 920 || 587 || 54 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 05 || 920 || 582 || 53,54 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 06 || 920 || 587 || 54 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 07 || 920 || 586 || 53,91 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 08 || 920 || 586 || 53,91 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 09 || 920 || 581 || 53,45 || 36 || <s>19</s> 28 (estudantes)<br />
|-<br />
| Sala 10 || 898 || 588 || 52,8 || 36 || 21<br />
|-<br />
| Sala 11 || 898 || 583 || 52,35 || 36 || 19<br />
|-<br />
| Sala 12 || 898 || 584 || 52,44 || 36 || 19<br />
|-<br />
| Sala 13 || 898 || 584 || 52,44 || 36 || 19<br />
|-<br />
| Sala 14 || 898 || 581 || 52,17 || 52 || 19<br />
|}<br />
</center><br />
<br />
==Capacidade dos Laboratórios de ensino==<br />
<center><br />
<!--{{fig|2|Tabela E1 - Capacidade dos Laboratórios de ensino| PSS_SJE_TabelaE1.png| 600 px | PLANO DE CONTINGÊNCIA DO CAMPUS SÃO JOSÉ}}--><br />
{| class="wikitable"<br />
! Local || Profundidade [cm] || Comprimento [cm] || Área [m2] || Capacidade normal || Capacidade para distância <s>1,5m</s> 1,0m <span style="color:red">(em revisão)</span><br />
|-<br />
| Lab. Prototipagem || 690 || 690 || 47,61 || 16 || fechado<br />
|-<br />
| Lab. Condicionamento de Ar || 690 || 578 || 39,88 || 8 || 5<br />
|-<br />
| Lab. Programação || 690 || 702 || 48,44 || 25 || 13<br />
|-<br />
| Lab. Linguagem || 690 || 590 || 40,71 || 28 || 10<br />
|-<br />
| Lab. Ciências Humanas || 690 || 636 || 43,88 || 24 || 10<br />
|-<br />
| Lab. Ciências Térmicas || 921 || 587 || 54,06 || 12 || 7<br />
|-<br />
| Lab. Eletricidade || 921 || 947 || 87,22 || 16 || 11<br />
|-<br />
| Lab. Refrigeração || 921 || 830 || 76,44 || 18 || 6<br />
|-<br />
| Lab. Solda e Sistemas Herméticos || 921 || 583 || 53,69 || 18 || 6<br />
|-<br />
| Lab. Sistemas Digitais (LabSiDi) || 917 || 690 || 63,27 || 25 || 13<br />
|-<br />
| Lab. Redes de Computadores (LabRedes) || 917 || 708 || 64,92 || 25 || 13<br />
|-<br />
| Lab. Comunicação sem Fio (LabCom)|| 917 || 709 || 65,02 || 25 || 13<br />
|-<br />
| Lab. Meios de Transmissão (LabMT) || 917 || 708 || 64,92 || 25 || <s>13</s> 16<br />
|-<br />
| Lab. Eletricidade e Eletrônica (LabEE) || 917 || 716 || 65,66 || 25 || 13<br />
|-<br />
| Lab. Informática (LabInfo) || 920 || 589 || 54,19 || 36 || <s>16</s> 19<br />
|-<br />
| Lab. Física || 920 || 700 || 64,4 || 36 || 7<br />
|-<br />
| Lab. Química Geral || 920 || 828 || 76,18 || 18 || 7<br />
|-<br />
| Lab. Biologia || 920 || 704 || 64,77 || 36 || <s>7</s> 13<br />
|-<br />
| Lab. CAD1 (LabCAD1) || 920 || 477 || 43,88 || 20 || 11<br />
|-<br />
| Lab. CAD2 (LabCAD2) || 920 || 347 || 31,92 || 14 || 9<br />
|-<br />
| Lab. CAD3 (LabCAD3) || 920 || 466 || 42,87 || 20 || 11<br />
|}<br />
</center><br />
<br />
*[[Leiautes dos laboratórios durante a Pandemia do COVID-19]]<br />
<br />
=Disciplinas com aulas práticas presenciais =<br />
<br />
<br />
* Durante a FASE <s>2</s> 3 da [https://www.ifsc.edu.br/politica-de-seguranca-sanitaria-e-planos-de-contingencia-locais PSS] no semestre 2021.2, algumas aulas de laboratório serão presenciais. O número de alunos nos laboratórios será limitado pelo quantitativo estabelecido pela Comissão de Contingência Local. <br />
<br />
* De acordo com o programa de cada disciplina, o professor indicará aos alunos matriculados na disciplina quais dias e forma como acontecerão as aulas práticas presenciais.<br />
<br />
* Para acessar o campus deve-se cumprir com as medidas preventivas conforme [https://www.ifsc.edu.br/politica-de-seguranca-sanitaria-e-planos-de-contingencia-locais PSS] e demais normas sanitárias vigentes (ver [[Media:cartilha_COVID_IFSC_SJE.pdf|cartilha COVID IFSC São José]]).<br />
<br />
* A listagem de referência das disciplinas que terão aulas práticas presenciais segue abaixo. '''VERIFIQUE COM O PROFESSOR DA DISCIPLINA QUANTO AO FORMATO E CAPACIDADE DO AMBIENTE PARA CADA AULA.'''<br />
<br />
<!-- Para gerar as tabelas use a aba publicar da planilha de '''Levantamento_UCs_Presencial_Fase2_PSS_SJE''', selecione o filtro do curso e cole a tabela no https://www.tablesgenerator.com/mediawiki_tables --><br />
<br />
==Curso de Técnico Integrado de Telecomunicações (0608)==<br />
<center><br />
{| class="wikitable" style="vertical-align:bottom; background-color:#F4F6F8;"<br />
|- style="font-style:italic; font-weight:bold; background-color:#DFE4EC;"<br />
! Fase<br />
! Código<br />
! Disciplina<br />
! Docente<br />
! style="text-align:center;" | Turno<br />
|-<br />
| 1<br />
| BLG060801<br />
| BIOLOGIA<br />
| Gustavo Gaciba<br />
| style="text-align:center;" | T<br />
|-<br />
| 2<br />
| BLG060802<br />
| BIOLOGIA<br />
| Gustavo Gaciba<br />
| style="text-align:center;" | T<br />
|-<br />
| 2<br />
| EDI060802<br />
| ELETRÔNICA DIGITAL<br />
| Cleber J. Amaral / André L. Alves<br />
| style="text-align:center;" | T<br />
|-<br />
| 2<br />
| FSC060802<br />
| FÍSICA<br />
| Salézio Momm<br />
| style="text-align:center;" | T<br />
|-<br />
| 2<br />
| PTGC060802<br />
| PORTUGUÊS<br />
| Kayron C. Bevilaqua<br />
| style="text-align:center;" | T<br />
|-<br />
| 3<br />
| BLG060803<br />
| BIOLOGIA<br />
| Gustavo Gaciba<br />
| style="text-align:center;" | M<br />
|-<br />
| 3<br />
| CER060803<br />
| CABEAMENTO ESTRUTURADO E REDES DE ACESSO<br />
| Evanaska M. B. Nogueira / Cleber J. Amaral<br />
| style="text-align:center;" | M<br />
|-<br />
| 3<br />
| MTM060803<br />
| MATEMÁTICA<br />
| Madeline O. S. Correa<br />
| style="text-align:center;" | M<br />
|-<br />
| 4<br />
| MTM060804<br />
| MATEMÁTICA<br />
| João C. B. Batti<br />
| style="text-align:center;" | T<br />
|-<br />
| 6<br />
| HST060806<br />
| HISTÓRIA<br />
| Alexandre Sardá<br />
| style="text-align:center;" | M<br />
|-<br />
| 6<br />
| PDT060806<br />
| PRINCÍPIOS DE TELECOMUNICAÇÕES<br />
| Saul Silva Caetano<br />
| style="text-align:center;" | T<br />
|-<br />
| 6<br />
| TEF060806<br />
| TELEFONIA I<br />
| Sandro Carlos Lima<br />
| style="text-align:center;" | T<br />
|-<br />
| 7<br />
| ELA060807<br />
| ELETRÔNICA APLICADA<br />
| Roberto W. da Nóbrega<br />
| style="text-align:center;" | M<br />
|-<br />
| 7<br />
| HST060807<br />
| HISTÓRIA<br />
| Ana Paula Pruner<br />
| style="text-align:center;" | M<br />
|-<br />
| 7<br />
| RDO060807<br />
| RADIOTRANSMISSÃO<br />
| Carlyle C. Santos Jr.<br />
| style="text-align:center;" | M<br />
|-<br />
| 7<br />
| TEF060807<br />
| TELEFONIA II<br />
| Fábio Alexandre de Souza<br />
| style="text-align:center;" | M<br />
|-<br />
| 8<br />
| ADC060808<br />
| ADMINISTRADORES DE REDES DE COMPUTADORES<br />
| Ederson Torresini<br />
| style="text-align:center;" | T<br />
|}<br />
</center><br />
<br />
==Curso de Técnico Subsequente de Telecomunicações (0111)==<br />
<center><br />
{| class="wikitable" style="vertical-align:bottom; background-color:#F4F6F8;"<br />
|- style="font-style:italic; font-weight:bold; background-color:#DFE4EC;"<br />
! Fase<br />
! Código<br />
! Disciplina<br />
! Docente<br />
! style="text-align:center;" | Turno<br />
|-<br />
| 1<br />
| ELD011101<br />
| ELETRÔNICA DIGITAL<br />
| Roberto de Matos / André L. Alves<br />
| style="text-align:center;" | N<br />
|-<br />
| 1<br />
| ELI011101<br />
| ELETRICIDADE E INSTRUMENTAÇÃO I<br />
| Nilton Francisco Oliveira da Silva<br />
| style="text-align:center;" | N<br />
|-<br />
| 1<br />
| PJI011101<br />
| PROJETO INTEGRADOR I<br />
| Jorge H. B. Casagrande / Eduardo J. Siridakis<br />
| style="text-align:center;" | N<br />
|-<br />
| 2<br />
| ELI011102<br />
| ELETRICIDADE E INSTRUMENTAÇÃO II<br />
| Eduardo Jorge Siridakis<br />
| style="text-align:center;" | N<br />
|-<br />
| 2<br />
| PJI011102<br />
| PROJETO INTEGRADOR II<br />
| Ederson Torresini<br />
| style="text-align:center;" | N<br />
|-<br />
| 2<br />
| RCO011102<br />
| REDES DE COMPUTADORES<br />
| Eraldo Silveira e Silva<br />
| style="text-align:center;" | N<br />
|-<br />
| 3<br />
| EAP011103<br />
| ELETRÔNICA APLICADA<br />
| Adilson Jair Cardoso<br />
| style="text-align:center;" | N<br />
|-<br />
| 3<br />
| PJI011103<br />
| PROJETO INTEGRADOR III<br />
| Marcelo Maia Sobral<br />
| style="text-align:center;" | N<br />
|-<br />
| 3<br />
| TLF011103<br />
| TELEFONIA I<br />
| Sandro Carlos Lima<br />
| style="text-align:center;" | N<br />
|-<br />
| 4<br />
| IRT011104<br />
| PROJETO DE INFRAESTRUTURA DE REDES DE TELECOMUNICAÇÕES<br />
| Saul Silva Caetano<br />
| style="text-align:center;" | N<br />
|-<br />
| 4<br />
| PJI011104<br />
| PROJETO INTEGRADOR IV<br />
| Adilson Jair Cardoso<br />
| style="text-align:center;" | N<br />
|-<br />
| 4<br />
| TLF011104<br />
| TELEFONIA II<br />
| Fábio Alexandre de Souza<br />
| style="text-align:center;" | N<br />
|}<br />
</center><br />
<br />
==Curso de Engenharia de Telecomunicações (0290)==<br />
<center><br />
{| class="wikitable" style="vertical-align:bottom; background-color:#F4F6F8;"<br />
|- style="font-style:italic; font-weight:bold; background-color:#DFE4EC;"<br />
! Fase<br />
! Código<br />
! Disciplina<br />
! Docente<br />
! style="text-align:center;" | Turno<br />
|-<br />
| 1<br />
| DES029001<br />
| DESENHO TÉCNICO<br />
| Sérgio Pereira da Rocha<br />
| style="text-align:center;" | M<br />
|-<br />
| 1<br />
| ELI029001<br />
| ELETRICIDADE E INSTRUMENTAÇÃO<br />
| Sandro Carlos Lima<br />
| style="text-align:center;" | T<br />
|-<br />
| 1<br />
| PJI029001<br />
| PROJETO INTEGRADOR I<br />
| Eraldo Silveira e Silva<br />
| style="text-align:center;" | T<br />
|-<br />
| 1<br />
| PJI029001<br />
| PROJETO INTEGRADOR I<br />
| Jorge Henrique Busatto Casagrande<br />
| style="text-align:center;" | T<br />
|-<br />
| 2<br />
| PRG029002<br />
| PROGRAMAÇÃO I<br />
| Eraldo Silveira e Silva<br />
| style="text-align:center;" | M<br />
|-<br />
| 3<br />
| CIL029003<br />
| CIRCUITOS LÓGICOS<br />
| Odilson Tadeu Valle<br />
| style="text-align:center;" | T<br />
|-<br />
| 3<br />
| ELA029003<br />
| ELETRÔNICA I<br />
| Nilton Francisco Oliveira da Silva<br />
| style="text-align:center;" | T<br />
|-<br />
| 3<br />
| PRG029003<br />
| PROGRAMAÇÃO II<br />
| Marcelo Maia Sobral<br />
| style="text-align:center;" | T<br />
|-<br />
| 4<br />
| MIC029004<br />
| MICROPROCESSADORES<br />
| Roberto de Matos<br />
| style="text-align:center;" | M<br />
|-<br />
| 4<br />
| RED029004<br />
| REDES DE COMPUTADORES I<br />
| Odilson Tadeu Valle<br />
| style="text-align:center;" | M<br />
|-<br />
| 5<br />
| RED029005<br />
| REDES DE COMPUTADORES II<br />
| Jorge Henrique Busatto Casagrande<br />
| style="text-align:center;" | T<br />
|-<br />
| 5<br />
| SOP029005<br />
| SISTEMAS OPERACIONAIS<br />
| Arliones Stevert Hoeller Junior<br />
| style="text-align:center;" | T<br />
|-<br />
| 6<br />
| ANT029006<br />
| ANTENAS E PROPAGAÇÃO<br />
| Saul Silva Caetano<br />
| style="text-align:center;" | M<br />
|-<br />
| 6<br />
| DLP029006<br />
| DISPOSITIVOS LÓGICOS PROGRAMÁVEIS I<br />
| Marcos Moecke<br />
| style="text-align:center;" | M<br />
|-<br />
| 6<br />
| PJI029006<br />
| PROJETO INTEGRADOR II<br />
| Arliones Stevert Hoeller Junior<br />
| style="text-align:center;" | M<br />
|-<br />
| 7<br />
| COM029007<br />
| SISTEMAS DE COMUNICAÇÃO I<br />
| Mario de Noronha Neto<br />
| style="text-align:center;" | T<br />
|-<br />
| 7<br />
| DLP029007<br />
| DISPOSITIVOS LÓGICOS PROGRAMÁVEIS II<br />
| Roberto de Matos<br />
| style="text-align:center;" | T<br />
|-<br />
| 7<br />
| PSD029007<br />
| PROCESSAMENTO DE SINAIS DIGITAIS<br />
| Elen Macedo Lobato<br />
| style="text-align:center;" | T<br />
|-<br />
| 7<br />
| RTR029007<br />
| REDES DE TRANSMISSÃO<br />
| Fábio Alexandre de Souza<br />
| style="text-align:center;" | T<br />
|-<br />
| 8<br />
| CSF029008<br />
| COMUNICAÇÕES SEM FIO<br />
| Mario de Noronha Neto<br />
| style="text-align:center;" | M<br />
|-<br />
| 8<br />
| PJI029008<br />
| PROJETO INTEGRADOR III<br />
| Roberto de Matos<br />
| style="text-align:center;" | M<br />
|-<br />
| 8<br />
| PTC029008<br />
| PROJETO DE PROTOCOLOS<br />
| Marcelo Maia Sobral<br />
| style="text-align:center;" | M<br />
|-<br />
| 8<br />
| STE029008<br />
| SISTEMAS EMBARCADOS<br />
| Arliones Stevert Hoeller Junior<br />
| style="text-align:center;" | M<br />
|-<br />
| 9<br />
| CRF029009<br />
| CIRCUITOS DE RÁDIO-FREQUÊNCIA<br />
| Rubem Toledo Bergamo<br />
| style="text-align:center;" | T<br />
|-<br />
| 9<br />
| SMU029009<br />
| SISTEMAS MULTIMÍDIA<br />
| Ederson Torresini<br />
| style="text-align:center;" | T<br />
|}<br />
</center></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Ajuste_adaptativo_de_par%C3%A2metros_de_acesso_ao_meio_do_tipo_CSMA/CA_usando_aprendizado_de_m%C3%A1quina&diff=180116Ajuste adaptativo de parâmetros de acesso ao meio do tipo CSMA/CA usando aprendizado de máquina2021-11-16T19:18:38Z<p>Msobral: /* Referências */</p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />na estação base.<br /><br />Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br /><br />O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br /><br />
<br />
<br />
Tanto em modo de acesso com e sem-disputa, a interferência por outras redes penaliza o desempenho das comunicações, provocando colisões e outros erros de transmissão. Isso é agravado por interferências devido a transmissões em canais adjacentes, em que há sobreposição parcial da banda do canal. Em ambientes poluídos com essas características, alguns parâmetros poderiam ser ajustados para reduzir os erros e melhorar a eficiência do acesso ao meio. No caso dessas redes baseadas em IEEE 802.11, é possível alterar dinamicamente os parâmetros do MAC CSMA/CA AIFS (intervalo entre quadros), Cwmin e Cwmax (tamanhos mínimo e máximo da janela de disputa para fins de ''backoff'').<br />
<br />
<br />
<br />
<br />
Neste tema de TCC, propõe-se um método para que o MAC CSMA/CA seja capaz de aprender a escolher dinamicamente os melhores valores para os parâmetros AIFS, Cwmin e CWmax em função de características das transmissões recentes. Isso deve ser obtido com uma técnica de Aprendizado de Máquina (ML) do tipo Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br /><br /><br />
<br />
= Referências =<br />
<br />
* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />
* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />
* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
<br />
* Ali, Rashid et al. "Deep Reinforcement Learning Paradigm for Performance Optimization of Channel Observation–Based MAC Protocols in Dense WLANs". ''IEEE Access'', vol. 7, pp. 3500-3511, 2019, doi: 10.1109/ACCESS.2018.2886216<br />
<br />
* Edalat, Y., Obraczka, K. "Dynamically Tuning IEEE 802.11's Contention Window Using Machine Learning". <span style="left: 89.6633px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.826424);" role="presentation" dir="ltr">In</span><span style="left: 348.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif;" role="presentation" dir="ltr"> </span><span style="left: 351.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.780482);" role="presentation" dir="ltr">22nd Int’l ACM Conference </span><span style="left: 89.6633px; top: 769.934px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.769808);" role="presentation" dir="ltr">on Modeling, Analysis and Simulation of Wireless and Mobile Systems (MSWiM</span><br /><span style="left: 88.2417px; top: 786.539px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.806756);" role="presentation" dir="ltr">’19), November 25–29, 2019. </span><span style="left: 89.6633px; top: 803.144px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.77571);" role="presentation" dir="ltr">USA.</span><br />
* R. Sanchez-Iborra and A. F. Skarmeta, [https://ieeexplore.ieee.org/document/9166461 "TinyML-Enabled Frugal Smart Objects: Challenges and Opportunities"], in IEEE Circuits and Systems Magazine, vol. 20, no. 3, pp. 4-18, thirdquarter 2020, doi: 10.1109/MCAS.2020.3005467.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Um_mecanismo_baseado_em_aprendizado_por_refor%C3%A7o_para_aloca%C3%A7%C3%A3o_e_reserva_do_meio_de_comunica%C3%A7%C3%A3o_em_redes_de_acesso_sem-fio_IEEE_802.11ac&diff=180115Um mecanismo baseado em aprendizado por reforço para alocação e reserva do meio de comunicação em redes de acesso sem-fio IEEE 802.11ac2021-11-16T19:18:17Z<p>Msobral: </p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />
na estação base.<br />
<br />
Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br />
<br />
O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br />
<br />
Sendo assim, as duas estratégias de acesso ao meio possuem vantagens relativas, dependendo da carga de tráfego na rede. O acesso ao meio mais vantajoso é aquele que, a cada momento, pode proporcionar maior taxa de transmissão e menor latência. Neste tema de TCC, propõe-se um método para que o protocolo MAC hı́brido seja capaz de aprender a escolher dinamicamente o melhor modo de operação. Isso deve ser obtido com uma técnica de Aprendizado de Máquina (ML) do tipo Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br />
<br />
= Referências =<br />
<br />
* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />
* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />
* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
* Panigrahi, D. and Raman, B. (2009). ''TDMA scheduling in long-distance wifi networks''. In IEEE INFOCOM 2009, pages 2931–2935<br />
* Wang, Q., Jaffrès-Runser, K., Xu, Y., Scharbarg, J., An, Z., and Fraboul, C. (2016). ''TDMA versus CSMA/CA for wireless multi-hop communications: A comparison for soft real-time networking''. In 2016 IEEE World Conference on Factory Communication Systems (WFCS), pages 1–4<br />
* R. Sanchez-Iborra and A. F. Skarmeta, [https://ieeexplore.ieee.org/document/9166461 "TinyML-Enabled Frugal Smart Objects: Challenges and Opportunities"], in IEEE Circuits and Systems Magazine, vol. 20, no. 3, pp. 4-18, thirdquarter 2020, doi: 10.1109/MCAS.2020.3005467.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Ajuste_adaptativo_de_par%C3%A2metros_de_acesso_ao_meio_do_tipo_CSMA/CA_usando_aprendizado_de_m%C3%A1quina&diff=180114Ajuste adaptativo de parâmetros de acesso ao meio do tipo CSMA/CA usando aprendizado de máquina2021-11-16T18:50:50Z<p>Msobral: </p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />na estação base.<br /><br />Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br /><br />O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br /><br />
<br />
<br />
Tanto em modo de acesso com e sem-disputa, a interferência por outras redes penaliza o desempenho das comunicações, provocando colisões e outros erros de transmissão. Isso é agravado por interferências devido a transmissões em canais adjacentes, em que há sobreposição parcial da banda do canal. Em ambientes poluídos com essas características, alguns parâmetros poderiam ser ajustados para reduzir os erros e melhorar a eficiência do acesso ao meio. No caso dessas redes baseadas em IEEE 802.11, é possível alterar dinamicamente os parâmetros do MAC CSMA/CA AIFS (intervalo entre quadros), Cwmin e Cwmax (tamanhos mínimo e máximo da janela de disputa para fins de ''backoff'').<br />
<br />
<br />
<br />
<br />
Neste tema de TCC, propõe-se um método para que o MAC CSMA/CA seja capaz de aprender a escolher dinamicamente os melhores valores para os parâmetros AIFS, Cwmin e CWmax em função de características das transmissões recentes. Isso deve ser obtido com uma técnica de Aprendizado de Máquina (ML) do tipo Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br /><br /><br />
<br />
= Referências =<br />
<br />
* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />
* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />
* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
<br />
* Ali, Rashid et al. "Deep Reinforcement Learning Paradigm for Performance Optimization of Channel Observation–Based MAC Protocols in Dense WLANs". ''IEEE Access'', vol. 7, pp. 3500-3511, 2019, doi: 10.1109/ACCESS.2018.2886216<br />
<br />
* Edalat, Y., Obraczka, K. "Dynamically Tuning IEEE 802.11's Contention Window Using Machine Learning". <span style="left: 89.6633px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.826424);" role="presentation" dir="ltr">In</span><span style="left: 348.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif;" role="presentation" dir="ltr"> </span><span style="left: 351.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.780482);" role="presentation" dir="ltr">22nd Int’l ACM Conference </span><span style="left: 89.6633px; top: 769.934px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.769808);" role="presentation" dir="ltr">on Modeling, Analysis and Simulation of Wireless and Mobile Systems (MSWiM</span><br /><span style="left: 88.2417px; top: 786.539px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.806756);" role="presentation" dir="ltr">’19), November 25–29, 2019. </span><span style="left: 89.6633px; top: 803.144px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.77571);" role="presentation" dir="ltr">USA.</span></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Ajuste_adaptativo_de_par%C3%A2metros_de_acesso_ao_meio_do_tipo_CSMA/CA_usando_aprendizado_de_m%C3%A1quina&diff=180026Ajuste adaptativo de parâmetros de acesso ao meio do tipo CSMA/CA usando aprendizado de máquina2021-11-11T23:02:11Z<p>Msobral: Criou página com 'Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó e...'</p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />na estação base.<br /><br />Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br /><br />O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br /><br />
<br />
<br />
Tanto em modo de acesso com e sem-disputa, a interferência por outras redes penaliza o desempenho das comunicações, provocando colisões e outros erros de transmissão. Isso é agravado por interferências devido a transmissões em canais adjacentes, em que há sobreposição parcial da banda do canal. Em ambientes poluídos com essas características, alguns parâmetros poderiam ser ajustados para reduzir os erros e melhorar a eficiência do acesso ao meio. No caso dessas redes baseadas em IEEE 802.11, é possível alterar dinamicamente os parâmetros do MAC CSMA/CA AIFS (intervalo entre quadros), Cwmin e Cwmax (tamanhos mínimo e máximo da janela de disputa para fins de ''backoff'').<br />
<br />
<br />
<br />
<br />
Neste tema de TCC, propõe-se um método para que o MAC CSMA/CA seja capaz de aprender a escolher dinamicamente os melhores valores para os parâmetros AIFS, Cwmin e CWmax em função de características das transmissões recentes. Isso deve ser obtido com uma técnica de Aprendizado de Máquina (ML) do tipo Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br /><br />= Referências =<br /><br />* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
<br />
<br />
* Ali, Rashid et al. "Deep Reinforcement Learning Paradigm for Performance Optimization of Channel Observation–Based MAC Protocols in Dense WLANs". ''IEEE Access'', vol. 7, pp. 3500-3511, 2019, doi: 10.1109/ACCESS.2018.2886216<br />
<br />
<br />
* Edalat, Y., Obraczka, K. "Dynamically Tuning IEEE 802.11's Contention Window Using Machine Learning". <span style="left: 89.6633px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.826424);" role="presentation" dir="ltr">In</span><span style="left: 348.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif;" role="presentation" dir="ltr"> </span><span style="left: 351.692px; top: 753.331px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.780482);" role="presentation" dir="ltr">22nd Int’l ACM Conference </span><span style="left: 89.6633px; top: 769.934px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.769808);" role="presentation" dir="ltr">on Modeling, Analysis and Simulation of Wireless and Mobile Systems (MSWiM</span><br /><span style="left: 88.2417px; top: 786.539px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.806756);" role="presentation" dir="ltr">’19), November 25–29, 2019. </span><span style="left: 89.6633px; top: 803.144px; font-size: 13.2835px; font-family: sans-serif; transform: scaleX(0.77571);" role="presentation" dir="ltr">USA.</span></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Um_mecanismo_baseado_em_aprendizado_por_refor%C3%A7o_para_aloca%C3%A7%C3%A3o_e_reserva_do_meio_de_comunica%C3%A7%C3%A3o_em_redes_de_acesso_sem-fio_IEEE_802.11ac&diff=179673Um mecanismo baseado em aprendizado por reforço para alocação e reserva do meio de comunicação em redes de acesso sem-fio IEEE 802.11ac2021-10-27T21:26:18Z<p>Msobral: </p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />
na estação base.<br />
<br />
Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br />
<br />
O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br />
<br />
Sendo assim, as duas estratégias de acesso ao meio possuem vantagens relativas, dependendo da carga de tráfego na rede. O acesso ao meio mais vantajoso é aquele que, a cada momento, pode proporcionar maior taxa de transmissão e menor latência. Neste tema de TCC, propõe-se um método para que o protocolo MAC hı́brido seja capaz de aprender a escolher dinamicamente o melhor modo de operação. Isso deve ser obtido com uma técnica de Aprendizado de Máquina (ML) do tipo Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br />
<br />
= Referências =<br />
<br />
* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />
* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />
* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
* Panigrahi, D. and Raman, B. (2009). ''TDMA scheduling in long-distance wifi networks''. In IEEE INFOCOM 2009, pages 2931–2935<br />
* Wang, Q., Jaffrès-Runser, K., Xu, Y., Scharbarg, J., An, Z., and Fraboul, C. (2016). ''TDMA versus CSMA/CA for wireless multi-hop communications: A comparison for soft real-time networking''. In 2016 IEEE World Conference on Factory Communication Systems (WFCS), pages 1–4</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Um_mecanismo_baseado_em_aprendizado_por_refor%C3%A7o_para_aloca%C3%A7%C3%A3o_e_reserva_do_meio_de_comunica%C3%A7%C3%A3o_em_redes_de_acesso_sem-fio_IEEE_802.11ac&diff=179672Um mecanismo baseado em aprendizado por reforço para alocação e reserva do meio de comunicação em redes de acesso sem-fio IEEE 802.11ac2021-10-27T21:25:37Z<p>Msobral: </p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />
na estação base.<br />
<br />
Essas redes se baseiam na tecnologia IEEE 802.11 [ieee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br />
<br />
O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br />
<br />
Sendo assim, as duas estratégias de acesso ao meio possuem vantagens relativas, dependendo da carga de tráfego na rede. O acesso ao meio mais vantajoso é aquele que, a cada momento, pode proporcionar maior taxa de transmissão e menor latência. Neste tema de TCC, propõe-se um método para que o protocolo MAC hı́brido seja capaz de aprender a escolher dinamicamente o melhor modo de operação. Isso deve ser obtido com uma técnica de Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br />
<br />
= Referências =<br />
<br />
* Simó, J., Figuera, C., Seoane, J., and Mart’inez, A. (2007). ''Distance limits in IEEE 802.11 for Rural Networks in Developing Countries''. proc. IEEE WRECOM<br />
* Patra, R., Nedevschi, S., Surana, S., Sheth, A., Subramanian, L., and Brewer, E. (2007). ''Wildnet: Design and implementation of high performance wifi based long distance networks''. In 4th USENIX Symposium on Networked Systems Design & Implementation (NSDI 07), Cambridge, MA. USENIX Association<br />
* ieee 2016. ''Ieee standard for information technology—telecommunications and information exchange between systems local and metropolitan area networks—specific requirements - part 11: Wireless lan medium access control (mac) and physical layer (phy)specifications''. IEEE Std 802.11-2016 (Revision of IEEE Std 802.11-2012), pages 1–3534<br />
* Panigrahi, D. and Raman, B. (2009). ''TDMA scheduling in long-distance wifi networks''. In IEEE INFOCOM 2009, pages 2931–2935<br />
* Wang, Q., Jaffrès-Runser, K., Xu, Y., Scharbarg, J., An, Z., and Fraboul, C. (2016). ''TDMA versus CSMA/CA for wireless multi-hop communications: A comparison for soft real-time networking''. In 2016 IEEE World Conference on Factory Communication Systems (WFCS), pages 1–4</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Um_mecanismo_baseado_em_aprendizado_por_refor%C3%A7o_para_aloca%C3%A7%C3%A3o_e_reserva_do_meio_de_comunica%C3%A7%C3%A3o_em_redes_de_acesso_sem-fio_IEEE_802.11ac&diff=179670Um mecanismo baseado em aprendizado por reforço para alocação e reserva do meio de comunicação em redes de acesso sem-fio IEEE 802.11ac2021-10-27T21:09:00Z<p>Msobral: Criou página com 'Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó e...'</p>
<hr />
<div>Em diversos lugares no Brasil e no mundo, onde não há infraestrutura de rede cabeada, usam-se redes de acesso sem-fio para fornecer serviços de dados para clientes [Simó et al. 2007]. Suas estruturas são formadas por estações base, que se situam nas dependências do provedor de acesso, e estações clientes, que ficam nas localidades dos clientes. As distâncias entre estação base e clientes tipicamente são de alguns quilômetros. As estações clientes se associam à estação base, usando-a para enviar e receber quadros de dados. A topologia resultante é denominada PTMP (Point-To-MultiPoint), e centralizada<br />
na estação base.<br />
<br />
Essas redes se baseiam na tecnologia IEEE 802.11 [iee 2016], porém com algumas modificações para obter melhor eficiência no uso do canal sem-fio [Patra et al. 2007]. Com as distâncias envolvidas, interferências entre estações clientes e estação base, e por transmissões de outras redes, são frequentes. Equipamentos para esse tipo de rede incluem um protocolo MAC modificado, com a finalidade de coordenar as transmissões dos clientes na rede sem-fio. Como exemplos, citam-se iPoll da empresa LigoWave, AirMax da empresa Ubiquiti, e NV2 da empresa Mikrotik. A abordagem comumente adotada envolve uma forma de ''polling'', com a estação base concedendo ciclicamente tempos de acesso aos clientes [Panigrahi and Raman 2009]. Essa forma de operação melhora a utilização do canal sem-fio, evitando a ocorrência de colisões entre transmissões de clientes e da base.<br />
<br />
O acesso ao meio sem-disputa, na forma de ''polling'', pode ser ineficiente em momentos em que poucos clientes transmitem, ou se as transmissões de clientes são esporádicas [Israr et al. 2012] [Wang et al. 2016]. A consequência é uma maior latência percebida por clientes para transmitirem seus quadros de dados, pois precisam esperar receberem autorização da estação base. Assim, mesmo estando a rede ociosa, um cliente não pode transmitir enquanto a estação base não o autorizar. Nesse caso, o MAC mais adequado seria o CSMA/CA usual, ao invés de TDMA. Devido a essa questão, alguns fabricantes implementam protocolos MAC hı́bridos capazes de comutar de um modo CSMA/CA para ''polling'' e vice-versa, como iPollv3 da LigoWave, dependendo da carga de tráfego na rede sem-fio.<br />
<br />
Sendo assim, as duas estratégias de acesso ao meio possuem vantagens relativas, dependendo da carga de tráfego na rede. O acesso ao meio mais vantajoso é aquele que, a cada momento, pode proporcionar maior taxa de transmissão e menor latência. Neste tema de TCC, propõe-se um método para que o protocolo MAC hı́brido seja capaz de aprender a escolher dinamicamente o melhor modo de operação. Isso deve ser obtido com uma técnica de Aprendizado por Reforço (''Reinforcemed Learning''), fazendo com que o MAC melhore seu desempenho com a experiência obtida com os resultados de escolhas anteriores.<br />
<br />
= Referências =</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede5.png&diff=176327Arquivo:Pji3-lab1-Rede5.png2021-05-18T23:19:00Z<p>Msobral: Msobral carregada uma nova versão de Arquivo:Pji3-lab1-Rede5.png</p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede4.png&diff=176326Arquivo:Pji3-lab1-Rede4.png2021-05-18T23:18:31Z<p>Msobral: Msobral carregada uma nova versão de Arquivo:Pji3-lab1-Rede4.png</p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Subredes_IPv4&diff=176140PJI3-Subredes IPv42021-05-14T20:24:30Z<p>Msobral: Criou página com '__notoc__ * [https://www.cisco.com/c/en/us/support/docs/ip/routing-information-protocol-rip/13788-3.html IP Addressing (Cisco)] * [https://study-ccna.com/subnetting-explained...'</p>
<hr />
<div>__notoc__<br />
<br />
* [https://www.cisco.com/c/en/us/support/docs/ip/routing-information-protocol-rip/13788-3.html IP Addressing (Cisco)]<br />
* [https://study-ccna.com/subnetting-explained/ Uma introdução a subredes]<br />
<br />
<br />
A Internet é uma grande rede formada pela interligação de redes menores, denominadas ''subredes''. Cada subrede está associada a uma faixa de endereços IP. Os equipamentos (''hosts'') contidos em uma subrede possuem endereços IP dentro dessa faixa. Esse esquema facilita o roteamento na Internet, pois, para enviar um pacote para um determinado ''host'', basta saber que caminho seguir para chegar até sua subrede. Com isso, não é necessário (nem seria viável !) que os roteadores saibam como chegar até cada possível ''host'' existente na Internet. Para que isso funcione, deve haver uma forma simples de relacionar os endereços IP de hosts às faixas de endereços das subredes que os contêm.<br />
<br />
[[imagem:IER-Subnet1.png]]<br />
<br>''Uma rede formada por subredes interligadas por roteadores''<br />
<br />
<br />
Uma subrede IP é representada por um ''prefixo de rede'' e uma ''máscara''. O prefixo são os ''N'' bits mais significativos comuns a todos os endereços IP contidos em uma subrede (lembre que um endereço IP tem 32 bits). A máscara informa quantos bits tem o prefixo. A combinação de prefixo de rede e máscara funciona da seguinte forma:<br />
<br />
Imagine que exista uma subrede contendo os endereços de 192.168.2.0 até 192.168.2.255. Se representarmos esses endereços em binário, podemos ver que os 24 bits mais significativos são os mesmos para todos os endereços:<br />
<br />
<br />
[[imagem:Pji-prefixo1.png|400px]]<br />
<br />
<br />
A máscara de rede tem a forma de um endereço IP, porém com bits 1 na parte correspondente ao prefixo, e 0 no resto. Assim, para o exemplo acima a máscara de rede é ''255.255.255.0''. Outra forma de representar a máscara é simplesmente informar o tamanho em bits do prefixo, e no exemplo a máscara seria ''24''. Juntando o prefixo e a máscara, a subrede pode ser representada de uma destas duas formas:<br />
* '''192.168.2.0/255.255.255.0'''<br />
* '''192.168.2.0/24'''<br />
<br />
<br />
Agora imagine que o prefixo tenha 28 bits, como mostrado nesta figura:<br />
<br />
<br />
[[imagem:Pji-prefixo2.png|400px]]<br />
<br />
<br />
Por ter um prefixo mais longo, o tamanho dessa subrede é menor. Isso significa que ela contém menos endereços IP, tanto que o primeiro endereço é ''192.168.2.0'' e o último é ''192.168.2.15''. Essa subrede poderia ser representada por:<br />
* '''192.168.2.0/255.255.255.240'''<br />
* '''192.168.2.0/28'''<br />
<br />
<br />
Aproveitando esse exemplo, pode-se mostrar uma outra subrede que, apesar de não parecer, é diferente da anterior:<br />
<br />
<br />
[[imagem:Pji-prefixo3.png|400px]]<br />
<br />
<br />
Essa outra subrede contém endereços entre ''192.168.2.16'' e ''192.168.2.31''. Essa subrede poderia ser representada por:<br />
* '''192.168.2.16/255.255.255.240'''<br />
* '''192.168.2.16/28'''<br />
<br />
<br />
Como se pode notar, uma consequência dessa forma de definir subredes é que seus tamanhos sempre serão potências de 2. Em outras palavras, as quantidades de endereços IP de qualquer subrede IP imaginável sempre serão potências de 2.<br />
<br />
= Encaminhamento IP =<br />
<br />
Todo ''host'' é capaz de realizar uma função da camada de rede chamada de encaminhamento IP (''IP forwarding''). O encaminhamento é feito quando um ''host'' recebe um [http://www.tcpipguide.com/free/t_IPDatagramGeneralFormat.htm datagrama IP], e precisa decidir o que fazer com ele. O destino do datagrama depende do endereço de destino contido em seu cabeçalho IP.<br />
# '''Se o endereço IP for o do próprio ''host''''': o conteúdo do datagrama é desencapsulado e entregue à camada superior.<br />
# '''Se o endereço IP NÃO for o do próprio ''host''''': a tabela de rotas do ''host'' é consultada para buscar uma rota que satisfaça o endereço de destino. Caso ela exista, o datagrama é transmitido para o próximo roteador indicado nessa rota.<br />
<br />
<br />
Os dois videos a seguir ilustram o encaminhamento de um datagrama IP ao longo de uma rede:<br />
<br />
<center><br />
[[Arquivo:IER-Forwarding1.mp4|800px]]<br />
<br>''Exemplo 1''<br />
<br />
<br />
[[Arquivo:IER-Forward2.mp4|800px]]<br />
<br>''Exemplo 2''<br />
</center><br />
<br />
Uma rota serve para informar como se chega a um determinado destino. Um destino pode ser um único endereço IP, ou uma subrede (que contém um conjunto de endereços IP). Para que um pacote IP chegue a um destino, deve-se transmiti-lo para o próximo roteador em direção a esse destino. Esse próximo roteador também deve conhecer uma rota para tal destino, repetindo o mesmo procedimento. Ao menos duas informações compõem cada rota: <br />
* '''O destino, que é expressado como uma subrede:''' Uma subrede é representada por um ''prefixo de rede'' e uma ''máscara''.<br />
* '''O próximo roteador, expressado por um endereço IP:''' o endereço IP do próximo roteador (também chamado de ''gateway'', que significa ''portal'' em inglês), o qual deve pertencer à mesma subrede do equipamento que o especifica em uma rota.<br />
<br />
<br />
No caso em que o endereço de destino não for o do próprio ''host'', esse endereço é comparado com cada rota existente na tabela de rotas. Rotas com máscaras de rede maiores são testadas primeiro (o tamanho de uma máscara é definido pela quantidade de bits 1 que ela possui), pois são rotas para subredes menores e, portanto, mais específicas. Se nenhuma rota servir, o datagrama é silenciosamente descartado.<br />
<br />
A tabela de rotas a seguir foi obtida em um computador com sistema operacional Linux. <br />
<br />
<syntaxhighlight lang=bash><br />
aluno@M1:~$ route -n<br />
Tabela de Roteamento IP do Kernel<br />
Destino Roteador MáscaraGen. Opções Métrica Ref Uso Iface<br />
0.0.0.0 191.36.9.254 0.0.0.0 UG 0 0 0 enp0s25<br />
169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 enp0s25<br />
191.36.9.0 0.0.0.0 255.255.255.0 U 0 0 0 enp0s25<br />
192.168.2.64 191.36.9.1 255.255.255.192 U 0 0 0 enp0s25<br />
</syntaxhighlight><br />
<br />
Supondo que esse ''host'' tenha que encaminhar um datagrama com endereço de destino 8.8.8.8, a busca por uma rota adequada seria esta:<br />
# '''Rota para ''192.168.2.64/26''''': ao aplicar a máscara ''/26'' (''255.255.255.192'') ao endereço de destino ''8.8.8.8'', obtêm-se o prefixo ''8.8.8.0''. Como ele é diferente de ''192.168.2.64'', esta rota não serve.<br />
# '''Rota para ''191.36.9.0/24''''': ao aplicar a máscara ''/24'' ao endereço de destino ''8.8.8.8'', obtêm-se o prefixo ''8.8.8.0''. Como ele é diferente de ''191.36.9.0'', esta rota não serve.<br />
# '''Rota para ''169.254.0.0/16''''': ao aplicar a máscara ''/16'' ao endereço de destino ''8.8.8.8'', obtêm-se o prefixo ''8.8.0.0''. Como ele é diferente de ''169.254.0.0'', esta rota não serve.<br />
# '''Rota para ''0.0.0.0/0''''': ao aplicar a máscara ''/0'' ao endereço de destino ''8.8.8.8'', obtêm-se o prefixo ''0.0.0.0''. Como ele é igual a ''0.0.0.0'' (prefixo da rota), esta rota será usada.<br />
<br />
<br />
Se outro datagrama tiver endereço de destino 191.36.9.140, a busca pela rota seria:<br />
# '''Rota para ''192.168.2.64/26''''': ao aplicar a máscara ''/26'' ao endereço de destino ''191.36.9.140'', obtêm-se o prefixo ''191.36.9.128''. Como ele é diferente de ''192.168.2.64'', esta rota não serve.<br />
# '''Rota para ''191.36.9.0/24''''': ao aplicar a máscara ''/24'' ao endereço de destino ''191.36.9.140'', obtêm-se o prefixo ''191.36.9.0''. Como ele é igual a ''191.36.9.0'' (prefixo da rota), esta rota será usada.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176139PJI3-Interfaces de gerenciamento2021-05-14T20:15:03Z<p>Msobral: </p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. <br />
<br />
Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet. No PacketTracer, ela pode ser acessada diretamente no painel de cada equipamento de rede.<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
No PacketTracer é possível fazer um acesso desse tipo. Basta conectar a porta serial de um computador à console de um roteador ou switch. Em seguida, no computador se usa o aplicativo Terminal.<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# No PacketTracer, acesse a interface de gerenciamento de um roteador com cada um dos métodos disponíveis:<br />
#* Porta serial<br />
#* Telnet<br />
#* SSH<br />
<br />
{{collapse top|Ativar acesso com SSH ou Telnet em roteador ou switch Cisco}}<br />
Os equipamentos Cisco inicialmente estão com SSH e Telnet desativados. Isso faz sentido, porque um acesso desses possibilita visualizar e, talvez, modificar a configuração do equipamento. Por isso é necessário um procedimento para ativá-los com certos cuidados. A sequência de comandos a seguir deve ser feita na interface CLI do equipamento. ([https://www.thegeekstuff.com/2013/08/enable-ssh-cisco/ versão original desse tutorial]).<br />
<br />
1. Defina o nome de host e nome de domínio DNS em seu roteador: <br />
<syntaxhighlight lang=bash><br />
# ip hostname meuroteador<br />
# ip domain-name ifsc.edu.br<br />
</syntaxhighlight><br />
2. Gere as chaves de encriptação RSA: isso é necessário p ara o SSH, pois ele encripta (protege) os dados transferidos durante o acesso:<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# crypto key generate rsa<br />
The name for the keys will be: myswitch.thegeekstuff.com<br />
Choose the size of the key modulus in the range of 360 to 2048 for your<br />
General Purpose Keys. Choosing a key modulus greater than 512 may take<br />
a few minutes.<br />
<br />
How many bits in the modulus [512]: 1024<br />
% Generating 1024 bit RSA keys, keys will be non-exportable...[OK]<br />
</syntaxhighlight><br />
3. Configure os terminais virtuais que serão usados para acesso remoto .. neste exemplo, será usado o usuário ''aluno'' com senha ''telecom''<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# line vty 0 4<br />
meuroteador(config-line)# transport input ssh<br />
meuroteador(config-line)# login local<br />
meuroteador(config-line)# password telecom<br />
meuroteador(config-line)# exit<br />
</syntaxhighlight><br />
... e também configure a console com estes comandos:<br />
# line console 0<br />
<syntaxhighlight lang=bash><br />
meuroteador(config-line)# logging synchronous<br />
meuroteador(config-line)# login local<br />
meuroteador(config-line)# exit<br />
</syntaxhighlight><br />
4. Defina a senha do usuário que fará o acesso com SSH:<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# username aluno password aulapji3<br />
meuroteador(config)# end<br />
</syntaxhighlight><br />
5. Pronto ! O acesso com SSH foi ativado em seu roteador. Agora você pode testar acessá-lo a partir de um computador.<br />
{{collapse bottom}}</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176138PJI3-Interfaces de gerenciamento2021-05-14T20:12:34Z<p>Msobral: /* Atividade */</p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. <br />
<br />
Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet. No PacketTracer, ela pode ser acessada diretamente no painel de cada equipamento de rede.<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
No PacketTracer é possível fazer um acesso desse tipo. Basta conectar a porta serial de um computador à console de um roteador ou switch. Em seguida, no computador se usa o aplicativo Terminal.<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# No PacketTracer, acesse a interface de gerenciamento de um roteador com cada um dos métodos disponíveis:<br />
#* Porta serial<br />
#* Telnet<br />
#* SSH<br />
<br />
{{collapse top|Ativar acesso com SSH ou Telnet em roteador ou switch Cisco}}<br />
Os equipamentos Cisco inicialmente estão com SSH e Telnet desativados. Isso faz sentido, porque um acesso desses possibilita visualizar e, talvez, modificar a configuração do equipamento. Por isso é necessário um procedimento para ativá-los com certos cuidados. A sequência de comandos a seguir deve ser feita na interface CLI do equipamento. ([https://www.thegeekstuff.com/2013/08/enable-ssh-cisco/ versão original desse tutorial]).<br />
1. Defina o nome de host e nome de domínio DNS em seu roteador: <br />
<syntaxhighlight lang=bash><br />
# ip hostname meuroteador<br />
# ip domain-name ifsc.edu.br<br />
</syntaxhighlight><br />
2. Gere as chaves de encriptação RSA: isso é necessário p ara o SSH, pois ele encripta (protege) os dados transferidos durante o acesso:<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# crypto key generate rsa<br />
The name for the keys will be: myswitch.thegeekstuff.com<br />
Choose the size of the key modulus in the range of 360 to 2048 for your<br />
General Purpose Keys. Choosing a key modulus greater than 512 may take<br />
a few minutes.<br />
<br />
How many bits in the modulus [512]: 1024<br />
% Generating 1024 bit RSA keys, keys will be non-exportable...[OK]<br />
</syntaxhighlight><br />
3. Configure os terminais virtuais que serão usados para acesso remoto .. neste exemplo, será usado o usuário ''aluno'' com senha ''telecom''<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# line vty 0 4<br />
meuroteador(config-line)# transport input ssh<br />
meuroteador(config-line)# login local<br />
meuroteador(config-line)# password telecom<br />
meuroteador(config-line)# exit<br />
</syntaxhighlight><br />
... e também configure a console com estes comandos:<br />
# line console 0<br />
<syntaxhighlight lang=bash><br />
meuroteador(config-line)# logging synchronous<br />
meuroteador(config-line)# login local<br />
meuroteador(config-line)# exit<br />
</syntaxhighlight><br />
4. Defina a senha do usuário que fará o acesso com SSH:<br />
<syntaxhighlight lang=bash><br />
meuroteador(config)# username aluno password aulapji3<br />
meuroteador(config)# end<br />
</syntaxhighlight><br />
5. Pronto ! O acesso com SSH foi ativado em seu roteador. Agora você pode testar acessá-lo a partir de um computador.<br />
{{collapse bottom}}</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176137PJI3-Interfaces de gerenciamento2021-05-14T19:45:33Z<p>Msobral: /* Atividade */</p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. <br />
<br />
Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet. No PacketTracer, ela pode ser acessada diretamente no painel de cada equipamento de rede.<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
No PacketTracer é possível fazer um acesso desse tipo. Basta conectar a porta serial de um computador à console de um roteador ou switch. Em seguida, no computador se usa o aplicativo Terminal.<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# No PacketTracer, acesse a interface de gerenciamento de um roteador com cada um dos métodos disponíveis:<br />
#* Porta serial<br />
#* Telnet<br />
#* SSH</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176136PJI3-Interfaces de gerenciamento2021-05-14T19:44:32Z<p>Msobral: /* Interface de linha de comando (CLI) via console (porta serial) */</p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. <br />
<br />
Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet. No PacketTracer, ela pode ser acessada diretamente no painel de cada equipamento de rede.<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
No PacketTracer é possível fazer um acesso desse tipo. Basta conectar a porta serial de um computador à console de um roteador ou switch. Em seguida, no computador se usa o aplicativo Terminal.<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# Acesse a interface de gerenciamento do seu switch com cada um dos métodos disponíveis.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176135PJI3-Interfaces de gerenciamento2021-05-14T19:42:01Z<p>Msobral: /* Interface de linha de comando (CLI) via SSH ou telnet */</p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. <br />
<br />
Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet. No PacketTracer, ela pode ser acessada diretamente no painel de cada equipamento de rede.<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# Acesse a interface de gerenciamento do seu switch com cada um dos métodos disponíveis.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Interfaces_de_gerenciamento&diff=176134PJI3-Interfaces de gerenciamento2021-05-14T19:04:45Z<p>Msobral: Criou página com '__toc__ Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou...'</p>
<hr />
<div>__toc__<br />
<br />
Equipamentos de rede gerenciáveis podem ser configurados com diferentes métodos de acesso. Dependendo do modelo do equipamentos, interfaces de gerenciamento web ou [https://pt.wikipedia.org/wiki/Interface_de_linha_de_comandos CLI] podem ser usadas.<br />
<br />
= Interface web =<br />
<br />
Alguns equipamentos oferecem uma interface de configuração via web, a qual deve ser acessada por meio de um endereço IP de gerenciamento do equipamento (detalhes devem ser obtidos de seu manual). Assim, basta conectar um computador a uma interface de rede do equipamento e acessar seu endereço IP usando um navegador. Esse tipo de interface é prática e de uso simplificado, porém nem sempre completa.<br />
** [https://emulator.tp-link.com/ArcherC73.0(US)/Index.htm Simulador interface de gerenciamento web para roteador sem-fio TP-Link]<br />
** [https://emulator.tp-link.com/TL-SG3424/Index.htm Simulador interface de gerenciamento web para switch TP-Link TL-SG3424]<br />
<br />
= Interface de linha de comando (CLI) via SSH ou telnet =<br />
<br />
A interface de linha de comando, chamada também de CLI (''Command Line Interface''), é um tipo de interface de gerenciamento tradicional. Por essa interface usualmente se tem acesso a todos os possíveis comandos e configurações implementados em um equipamento. Esse tipo de interface comumente se apresenta na forma de um menu hierarquizado. Roteadores e switches Cisco oferecem [https://networklessons.com/cisco/ccna-routing-switching-icnd1-100-105/introduction-cisco-ios-cli-command-line-interface exemplos clássicos de CLI]. Tal tipo de interface pode ser acessado através da rede, usando os programas SSH ou Telnet.<br />
** [https://www.net-refresh.com/ Um simulador de CLI de equipamentos Cisco]<br />
<br />
= Interface de linha de comando (CLI) via console (porta serial)=<br />
<br />
Muitos equipamentos possibilitam que a interface CLI seja também acessada diretamente via porta serial, chamada de ''console''. Esses equipamentos disponibilizam uma porta serial do tipo [https://pt.wikipedia.org/wiki/RS-232 RS-232], ou uma porta [https://en.wikipedia.org/wiki/USB USB] que emula uma porta serial desse tipo. Para acessar o equipamento deve-se ter em mãos um cabo serial apropriado, um computador com porta serial RS-232 (se não houver a opção USB), e um programa emulador de terminal a ser executado no computador. O Linux oferece alguns programas emuladores de terminal tais como [https://medium.com/@m0blabs/usando-o-minicom-5f3872da9531 minicom] e [http://cutecom.sourceforge.net/ cutecom], e o Windows oferece o clássico [http://academiaccna.com.br/word/?p=1 hyperterminal]. Esse tipo de acesso envolve configurar a porta serial do computador para que consiga se comunicar com o equipamento, segundo instruções do fabricante. Essa configuração envolve estes parâmetros:<br />
** '''Taxa de bits:''' taxas de bits de comunicação típicas são 9600 (Cisco), 19200, 38400 (TP-Link), 57600 e 115200 bps.<br />
** '''Tamanho da palavra:''' os equipamentos usam comumente 8 bits por palavra<br />
** '''Stop bits:''' os equipamentos usam tipicamente 1 stop bit<br />
** '''Paridade:''' não se usa paridade<br />
** '''Controle de fluxo:''' normalmente feita automaticamente (não se deve selecionar o tipo de controle de fluxo)<br />
<br />
Os manuais costumam apresentar a configuração da porta console com esta notação:<br />
<br />
taxa tamanhoPalavra paridade stopbit<br />
<br />
Ex:<br />
<br />
9600 8N1<br />
<br />
... que significa:<br />
<br>''Taxa:'' 9600 bps<br />
<br>''Tamanho da palavra:'' 8 bits<br />
<br>''Paridade:'' N (desativada)<br />
<br>''Stop bits:'' 1<br />
<br />
<br />
= Atividade =<br />
<br />
# Identifique as formas de acesso à interface de gerenciamento dos switches TP-Link SG 3210 ou Intelbras SG-2404<br />
# Acesse a interface de gerenciamento do seu switch com cada um dos métodos disponíveis.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176123PJI3-Roteamento Estatico2021-05-14T18:31:02Z<p>Msobral: /* Exercícios */</p>
<hr />
<div>= Objetivos =<br />
<br />
* Explorar o uso de endereçamento IPv4 em redes locais<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br />
<br />
= Introdução =<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]] e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')] são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br />
<br />
[[imagem:PJI3-Ip1.jpg]]<br />
<br>''Um endereço IP apresentado em notação decimal e em binário''<br />
<br />
O endereço IP de um ''host'' pode ser configurado de forma estática ou dinâmica. No primeiro caso, o usuário predefine o endereço IP no próprio equipamento. No segundo, o equipamento usa um protocolo especial de configuração para obter sua configuração de rede (ex: DHCP). Equipamentos com um papel fixo na rede, relacionado com sua infraestrutura ou com serviços de rede, são configurados com endereços estáticos. Exemplos são roteadores, pontos-de-acesso e servidores. Equipamentos que usam a rede, mas não fazem parte de sua infraestrutura, nem oferecem serviços, costumam ter seus endereços IP configurados automaticamente de forma dinâmica. Esse é o caso de computadores desktop e laptops, celulares e smart TVs (entre outros). Uma vez obtendo sua configuração de rede, um equipamento pode se comunicar em sua rede e (espera-se !) com a Internet.<br />
<br />
<br />
Um conjunto de informações são necessárias para que um ''host'' consiga efetivamente se comunicar em rede, as quais não se limitam ao endereço IP. Essas informações são:<br />
* '''Endereço IP e máscara de rede''': um host precisa de um endereço para que possa se comunicar com outros hosts. A máscara de rede informa o tamanho da subrede IP em que ele se encontra (e ocm isso pode-se saber quais endereços IP fazem parte dessa subrede).<br />
* '''Rota default (padrão)''': para se comunicar com hosts de outras subredes, é preciso enviar os pacotes para um roteador que saiba encaminhá-los a seus destinos. O roteador ''default'' (ou ''padrão'') é um roteador para quem se destinam todos esses pacotes. Tecnicamente ele corresponde à rota para o destino ''0.0.0.0/0''.<br />
* '''Endereço IP do servidor DNS''': usuários costumam endereçar hosts e servidores por seus nomes de domínio, e não por seus endereços IP. Isso é muito mais fácil de memorizar do que os endereços numéricos. Nomes de domínio são análogos a nomes de assinantes em um catálogo telefônico. No entanto, as aplicações precisam dos endereços IP para se comunicarem. O servidor DNS faz a tradução de nome de domínio para endereço IP, e é usado pelas aplicações transparentemente (isso é, você não percebe que isso ocorre). Assim, as aplicações se comunicam com o servidor DNS para resolver nomes de domínio e obter seus respectivos endereços IP. O endereço desse servidor deve ser configurado em cada host, para que se possam traduzir nomes de domínio.<br />
<br />
= Exercícios =<br />
<br />
Os exercícios a seguir envolvem implantar algumas redes, e endereçar os equipamentos de forma estáticas. Além disso, as rotas devem ser definidas para que equipamentos em diferentes subredes consigam se comunicar. Essas redes devem ser implantadas no PacketTracer. Escolha os equipamentos que devem ser usados, e configure-os para que todos os computadores consigam se comunicar. Você pode testar a comunicação com ''ping''. <br />
<br />
== 1. Uma rede simples ==<br />
<br />
Esta rede possui apenas duas subredes interligadas por um roteador. Com ela se pode experimentar a configuração de endereços IPv4 e a definição de rotas estáticas.<br />
<br />
[[imagem:Pji3-lab1-Rede1.png]]<br />
<br />
== 2. Uma rede um pouco maior ==<br />
<br />
Esta outra rede é parecida com a rede anterior, porém possui uma subrede a mais. Do ponto de vista da configuração de rede, a diferença está em rotas adicionais necessárias, e onde precisam ser definidas.<br />
<br />
[[imagem:Pji3-lab1-Rede2.png]]<br />
<br />
== 3. Uma pequena variação da rede anterior ==<br />
<br />
Esta rede também possui três subredes, mas a forma com estão interligadas tem uma pequena diferença. A questão de rotas adicionais é semelhante ao caso da rede anterior.<br />
<br />
[[imagem:Pji3-lab1-Rede3.png]]<br />
<br />
== 4. Uma rede com caminhos alternativos ==<br />
<br />
A rede a seguir tem os roteadores interligados em anel, e por isso existem caminhos alternativos para chegar a cada destino. As rotas a serem definidas em cada roteador devem escolher apenas um caminho possível para cada destino.<br />
<br />
[[imagem:Pji3-lab1-Rede4.png]]<br />
<br />
== 5. Duas redes conectadas ==<br />
<br />
Esta última rede é formada por duas redes com mesma estrutura da rede anterior. Parece que muitas rotas adicionais precisarão ser definidas nos roteadores, mas se você explorar o conceito de hierarquização dos endereços (subredes dentro de subredes), a definição de rotas pode ser muito simplificada !<br />
<br />
[[imagem:Pji3-lab1-Rede5.png]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176121PJI3-Roteamento Estatico2021-05-14T18:25:22Z<p>Msobral: /* Exercícios */</p>
<hr />
<div>= Objetivos =<br />
<br />
* Explorar o uso de endereçamento IPv4 em redes locais<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br />
<br />
= Introdução =<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]] e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')] são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br />
<br />
[[imagem:PJI3-Ip1.jpg]]<br />
<br>''Um endereço IP apresentado em notação decimal e em binário''<br />
<br />
O endereço IP de um ''host'' pode ser configurado de forma estática ou dinâmica. No primeiro caso, o usuário predefine o endereço IP no próprio equipamento. No segundo, o equipamento usa um protocolo especial de configuração para obter sua configuração de rede (ex: DHCP). Equipamentos com um papel fixo na rede, relacionado com sua infraestrutura ou com serviços de rede, são configurados com endereços estáticos. Exemplos são roteadores, pontos-de-acesso e servidores. Equipamentos que usam a rede, mas não fazem parte de sua infraestrutura, nem oferecem serviços, costumam ter seus endereços IP configurados automaticamente de forma dinâmica. Esse é o caso de computadores desktop e laptops, celulares e smart TVs (entre outros). Uma vez obtendo sua configuração de rede, um equipamento pode se comunicar em sua rede e (espera-se !) com a Internet.<br />
<br />
<br />
Um conjunto de informações são necessárias para que um ''host'' consiga efetivamente se comunicar em rede, as quais não se limitam ao endereço IP. Essas informações são:<br />
* '''Endereço IP e máscara de rede''': um host precisa de um endereço para que possa se comunicar com outros hosts. A máscara de rede informa o tamanho da subrede IP em que ele se encontra (e ocm isso pode-se saber quais endereços IP fazem parte dessa subrede).<br />
* '''Rota default (padrão)''': para se comunicar com hosts de outras subredes, é preciso enviar os pacotes para um roteador que saiba encaminhá-los a seus destinos. O roteador ''default'' (ou ''padrão'') é um roteador para quem se destinam todos esses pacotes. Tecnicamente ele corresponde à rota para o destino ''0.0.0.0/0''.<br />
* '''Endereço IP do servidor DNS''': usuários costumam endereçar hosts e servidores por seus nomes de domínio, e não por seus endereços IP. Isso é muito mais fácil de memorizar do que os endereços numéricos. Nomes de domínio são análogos a nomes de assinantes em um catálogo telefônico. No entanto, as aplicações precisam dos endereços IP para se comunicarem. O servidor DNS faz a tradução de nome de domínio para endereço IP, e é usado pelas aplicações transparentemente (isso é, você não percebe que isso ocorre). Assim, as aplicações se comunicam com o servidor DNS para resolver nomes de domínio e obter seus respectivos endereços IP. O endereço desse servidor deve ser configurado em cada host, para que se possam traduzir nomes de domínio.<br />
<br />
= Exercícios =<br />
<br />
Os exercícios a seguir envolvem implantar algumas redes, e endereçar os equipamentos de forma estáticas. Além disso, as rotas devem ser definidas para que equipamentos em diferentes subredes consigam se comunicar. Essas redes devem ser implantadas no PacketTracer. Escolha os equipamentos que devem ser usados, e configure-os para que todos os computadores consigam se comunicar. Você pode testar a comunicação com ''ping''. <br />
<br />
== 1. Uma rede simples ==<br />
<br />
Esta rede possui apenas duas subredes interligadas por um roteador. <br />
<br />
[[imagem:Pji3-lab1-Rede1.png]]<br />
<br />
== 2. Uma rede um pouco maior ==<br />
<br />
Esta outra rede é parecida com a rede anterior, porém possui uma subrede a mais.<br />
<br />
[[imagem:Pji3-lab1-Rede2.png]]<br />
<br />
== 3. Uma pequena variação da rede anterior ==<br />
<br />
Esta rede também possui três subredes, mas a forma com estão interligadas tem uma pequena diferença.<br />
<br />
[[imagem:Pji3-lab1-Rede3.png]]<br />
<br />
== 4. Uma rede com caminhos alternativos ==<br />
<br />
A rede a seguir tem os roteadores interligados em anel, e por isso existem caminhos alternativos para chegar a cada destino. <br />
<br />
[[imagem:Pji3-lab1-Rede4.png]]<br />
<br />
== 5. Duas redes conectadas ==<br />
<br />
Esta última rede é formada por duas redes com mesma estrutura da rede anterior.<br />
<br />
[[imagem:Pji3-lab1-Rede5.png]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176119PJI3-Roteamento Estatico2021-05-14T18:09:59Z<p>Msobral: </p>
<hr />
<div>= Objetivos =<br />
<br />
* Explorar o uso de endereçamento IPv4 em redes locais<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br />
<br />
= Introdução =<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]] e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')] são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br />
<br />
[[imagem:PJI3-Ip1.jpg]]<br />
<br>''Um endereço IP apresentado em notação decimal e em binário''<br />
<br />
O endereço IP de um ''host'' pode ser configurado de forma estática ou dinâmica. No primeiro caso, o usuário predefine o endereço IP no próprio equipamento. No segundo, o equipamento usa um protocolo especial de configuração para obter sua configuração de rede (ex: DHCP). Equipamentos com um papel fixo na rede, relacionado com sua infraestrutura ou com serviços de rede, são configurados com endereços estáticos. Exemplos são roteadores, pontos-de-acesso e servidores. Equipamentos que usam a rede, mas não fazem parte de sua infraestrutura, nem oferecem serviços, costumam ter seus endereços IP configurados automaticamente de forma dinâmica. Esse é o caso de computadores desktop e laptops, celulares e smart TVs (entre outros). Uma vez obtendo sua configuração de rede, um equipamento pode se comunicar em sua rede e (espera-se !) com a Internet.<br />
<br />
<br />
Um conjunto de informações são necessárias para que um ''host'' consiga efetivamente se comunicar em rede, as quais não se limitam ao endereço IP. Essas informações são:<br />
* '''Endereço IP e máscara de rede''': um host precisa de um endereço para que possa se comunicar com outros hosts. A máscara de rede informa o tamanho da subrede IP em que ele se encontra (e ocm isso pode-se saber quais endereços IP fazem parte dessa subrede).<br />
* '''Rota default (padrão)''': para se comunicar com hosts de outras subredes, é preciso enviar os pacotes para um roteador que saiba encaminhá-los a seus destinos. O roteador ''default'' (ou ''padrão'') é um roteador para quem se destinam todos esses pacotes. Tecnicamente ele corresponde à rota para o destino ''0.0.0.0/0''.<br />
* '''Endereço IP do servidor DNS''': usuários costumam endereçar hosts e servidores por seus nomes de domínio, e não por seus endereços IP. Isso é muito mais fácil de memorizar do que os endereços numéricos. Nomes de domínio são análogos a nomes de assinantes em um catálogo telefônico. No entanto, as aplicações precisam dos endereços IP para se comunicarem. O servidor DNS faz a tradução de nome de domínio para endereço IP, e é usado pelas aplicações transparentemente (isso é, você não percebe que isso ocorre). Assim, as aplicações se comunicam com o servidor DNS para resolver nomes de domínio e obter seus respectivos endereços IP. O endereço desse servidor deve ser configurado em cada host, para que se possam traduzir nomes de domínio.<br />
<br />
= Exercícios =<br />
<br />
Os exercícios a seguir envolvem implantar algumas redes, e endereçar os equipamentos de forma estáticas. Além disso, as rotas devem ser definidas para que equipamentos em diferentes subredes consigam se comunicar. Essas redes devem ser implantadas no PacketTracer. Escolha os equipamentos que devem ser usados, e configure-os para que todos os computadores consigam se comunicar. Você pode testar a comunicação com ''ping''. <br />
<br />
== 1. Uma rede simples ==<br />
<br />
[[imagem:Pji3-lab1-Rede1.png]]<br />
<br />
== 2. Uma rede um pouco maior ==<br />
<br />
[[imagem:Pji3-lab1-Rede2.png]]<br />
<br />
== 3. Uma pequena variação da rede anterior ==<br />
<br />
[[imagem:Pji3-lab1-Rede3.png]]<br />
<br />
== 4. Uma rede com caminhos alternativos ==<br />
[[imagem:Pji3-lab1-Rede4.png]]<br />
<br />
== 5. Duas redes conectadas ==<br />
[[imagem:Pji3-lab1-Rede5.png]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176118PJI3-Roteamento Estatico2021-05-14T18:00:05Z<p>Msobral: </p>
<hr />
<div>= Objetivos =<br />
<br />
* Explorar o uso de endereçamento IPv4 em redes locais<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br />
<br />
= Introdução =<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]] e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')] são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br />
<br />
[[imagem:PJI3-Ip1.jpg]]<br />
<br>''Um endereço IP apresentado em notação decimal e em binário''<br />
<br />
O endereço IP de um ''host'' pode ser configurado de forma estática ou dinâmica. No primeiro caso, o usuário predefine o endereço IP no próprio equipamento. No segundo, o equipamento usa um protocolo especial de configuração para obter sua configuração de rede (ex: DHCP). Equipamentos com um papel fixo na rede, relacionado com sua infraestrutura ou com serviços de rede, são configurados com endereços estáticos. Exemplos são roteadores, pontos-de-acesso e servidores. Equipamentos que usam a rede, mas não fazem parte de sua infraestrutura, nem oferecem serviços, costumam ter seus endereços IP configurados automaticamente de forma dinâmica. Esse é o caso de computadores desktop e laptops, celulares e smart TVs (entre outros). Uma vez obtendo sua configuração de rede, um equipamento pode se comunicar em sua rede e (espera-se !) com a Internet.<br />
<br />
<br />
Um conjunto de informações são necessárias para que um ''host'' consiga efetivamente se comunicar em rede, as quais não se limitam ao endereço IP. Essas informações são:<br />
* '''Endereço IP e máscara de rede''': um host precisa de um endereço para que possa se comunicar com outros hosts. A máscara de rede informa o tamanho da subrede IP em que ele se encontra (e ocm isso pode-se saber quais endereços IP fazem parte dessa subrede).<br />
* '''Rota default (padrão)''': para se comunicar com hosts de outras subredes, é preciso enviar os pacotes para um roteador que saiba encaminhá-los a seus destinos. O roteador ''default'' (ou ''padrão'') é um roteador para quem se destinam todos esses pacotes. Tecnicamente ele corresponde à rota para o destino ''0.0.0.0/0''.<br />
* '''Endereço IP do servidor DNS''': usuários costumam endereçar hosts e servidores por seus nomes de domínio, e não por seus endereços IP. Isso é muito mais fácil de memorizar do que os endereços numéricos. Nomes de domínio são análogos a nomes de assinantes em um catálogo telefônico. No entanto, as aplicações precisam dos endereços IP para se comunicarem. O servidor DNS faz a tradução de nome de domínio para endereço IP, e é usado pelas aplicações transparentemente (isso é, você não percebe que isso ocorre). Assim, as aplicações se comunicam com o servidor DNS para resolver nomes de domínio e obter seus respectivos endereços IP. O endereço desse servidor deve ser configurado em cada host, para que se possam traduzir nomes de domínio.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176117PJI3-Roteamento Estatico2021-05-14T17:53:23Z<p>Msobral: </p>
<hr />
<div>= Objetivos =<br />
<br />
* Explorar o uso de endereçamento IPv4 em redes locais<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br />
<br />
= Introdução =<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]] e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')] são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br />
<br />
[[imagem:PJI3-Ip1.jpg]]<br />
<br>''Um endereço IP apresentado em notação decimal e em binário''</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PJI3-Roteamento_Estatico&diff=176115PJI3-Roteamento Estatico2021-05-14T17:50:58Z<p>Msobral: Criou página com '= Objetivo =<br /><br />* Explorar o uso de endereçamento IPv4 em redes locais * Definir rotas estáticas, para que todos equipamentos possam se comunicar<br /><br /><b...'</p>
<hr />
<div>= Objetivo =<br /><br />* Explorar o uso de endereçamento IPv4 em redes locais<br />
<br />
<br />
* Definir rotas estáticas, para que todos equipamentos possam se comunicar<br /><br /><br />= Introdução =<br />
<br />
<br />
<br />
<br />
Como visto em [[RCO-TecTel_(página)|Redes de Computadores]]<br />
<br />
<br />
e [[PJI2-TecTel_(página)|Projeto 2]], computadores e equipamentos na Internet (chamados de ''hosts'') precisam ter um identificador único e que seja válido globalmente. Esse identificador, chamado de endereço IP, é a identidade de um ''host'' na Internet, e funciona como um localizador, pois informa onde na Internet está esse ''host''. O endereço IP tem um papel fundamental para que ''hosts'' possam enviar e receber mensagens, pois graças a esses endereços a rede consegue determinar onde eles se localizam (parecido com um CEP). <br />
<br />
Os endereços IP, definidos pelo [https://pt.wikipedia.org/wiki/Protocolo_de_Internet protocolo da Internet (''IP - Internet Protocol'')]<br />
<br />
<br />
são números de 32 bits que desempenham o papel de identificadores globais. Cada um desses endereços é comumente representado em uma notação decimal, com um número entre 0 e 255 para cada 8 bits. como mostrado na figura a seguir. Com isso, é possível em tese endereçar até <math>2^{32}</math> ''hosts'' na Internet, o que equivale a pouco mais de 4 bilhões de endereços.<br /><br /><@@@IMG103979@@@>" data-mw-type="image" data-mw-id="103979" data-mw-src="imagem:PJI3-Ip1.jpg" data-mw-link="false" data-mw-sizewidth="false" data-mw-sizeheight="false" data-mw-wikitext="%5B%5Bimagem:PJI3-Ip1.jpg%5D%5D" draggable="true" contenteditable="false"></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede5.png&diff=176114Arquivo:Pji3-lab1-Rede5.png2021-05-14T17:49:34Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede4.png&diff=176113Arquivo:Pji3-lab1-Rede4.png2021-05-14T17:49:10Z<p>Msobral: Msobral carregada uma nova versão de Arquivo:Pji3-lab1-Rede4.png</p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede4.png&diff=176111Arquivo:Pji3-lab1-Rede4.png2021-05-14T17:43:49Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede3.png&diff=176110Arquivo:Pji3-lab1-Rede3.png2021-05-14T17:43:34Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede2.png&diff=176109Arquivo:Pji3-lab1-Rede2.png2021-05-14T17:43:22Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:Pji3-lab1-Rede1.png&diff=176108Arquivo:Pji3-lab1-Rede1.png2021-05-14T17:42:59Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:TCC290_Vinicius_da_Luz_Souza.pdf&diff=175673Arquivo:TCC290 Vinicius da Luz Souza.pdf2021-05-04T19:11:31Z<p>Msobral: Msobral carregada uma nova versão de Arquivo:TCC290 Vinicius da Luz Souza.pdf</p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:TCC_Vinicius_Souza_12pt_oneside.pdf&diff=175671Arquivo:TCC Vinicius Souza 12pt oneside.pdf2021-05-04T19:08:27Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:TCC290_Vinicius_da_Luz_Souza.pdf&diff=175493Arquivo:TCC290 Vinicius da Luz Souza.pdf2021-04-17T10:30:20Z<p>Msobral: Msobral carregada uma nova versão de Arquivo:TCC290 Vinicius da Luz Souza.pdf</p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Ferramenta_para_Captura_e_An%C3%A1lise_de_Mensagens_OMCI_em_Redes_GPON&diff=175468Ferramenta para Captura e Análise de Mensagens OMCI em Redes GPON2021-04-14T20:07:59Z<p>Msobral: Criou página com ';Autor: Vinícius da Luz Souza ;Orientador: Prof. Marcelo Maia Sobral ;Coorientador: Prof. Roberto de Matos ;Curso: Engenharia de Telecomunicações ;Resumo: As...'</p>
<hr />
<div>;Autor:<br />
Vinícius da Luz Souza<br />
<br />
;Orientador: <br />
Prof. [[Marcelo Maia Sobral]]<br />
<br />
;Coorientador: <br />
Prof. [[Roberto de Matos]]<br />
<br />
;Curso:<br />
Engenharia de Telecomunicações<br />
<br />
;Resumo:<br />
As redes GPON(Gigabit Passive Optical Network) são redes de acesso baseadas na utilização de elementos passivos com o intuito de fornecer conexão através da fibra óptica. Graças ao aumento na demanda por altas taxas de transmissão, somado aos benefícios da utilização da fibra óptica e seu notável barateamento nos últimos anos, essa tecnologia vem ganhando mercado. No Brasil, a presença de PPPs (Provedores de Pequeno Porte) tem impulsionado ainda mais a utilização deste tipo de rede, aumentando a procura por equipamentos para GPON. Entretanto, apesar das normatizações da ITU-T(ITU Telecommunication Standardization Sector) G.984 e G.988, a incompatibilidade entre fabricantes é notória nessa tecnologia,fazendo com que alguns ativos da rede não se comuniquem adequadamente. Desta forma, este trabalho tem por objetivo desenvolver uma ferramenta que capture e analise mensagens de gerenciamento que trafegam na redeGPON, mais especificamente, as mensagens OMCI(Optical network termination Management and Control Interface). Esta ferramenta poderá auxiliar na análise da interoperabilidade de equipamentos,orientando engenheiros e analistas no desenvolvimento de produtos que utilizem esta tecnologia.<br />
<br />
;Palavras chave: <br />
Redes Ópticas, GPON, OMCI<br />
<br />
;Abstract:<br />
GPON (Gigabit Passive Optical Network) are access networks based on the use of passive elements in order to provide connection through optical fiber. Thanks to the increase in demand for high transmission rates, added to the benefits of using optical fiber and its notable cheapness in recent years, this technology has been gaining market share. In Brazil, the presence of small internet providers has further boosted the use of this type of network, increasing the demand for equipment for GPON. However, despite the regulations of ITU-TG.984 and G.988, the incompatibility of the manufacturers is notorious in this technology, causing some network assets to not communicate properly. Thus, this work aims to develop a tool that captures and analyzes management messages that travel on the GPON network, more specifically, the OMCI (Optical network termination Management and Control Interface) messages. This tool can assist in the analysis of interoperability between equipment, guiding engineers and analysts in the development of products that use this technology.<br />
<br />
;Keywords:<br />
Optical Networks, GPON, OMCI<br />
<br />
;Arquivos:<br />
Arquivos relacionados a trabalho, a monografia em pdf e também arquivos fontes e executáveis estão disponibilizados nos links abaixo:<br />
*[[Media:TCC290_Vinicius_da_Luz_Souza.pdf |Monografia.pdf]]<br />
<br />
[[Categoria:Trabalhos de Alunos]]<br />
[[Categoria:Projeto de Fim de Curso]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Arquivo:TCC290_Vinicius_da_Luz_Souza.pdf&diff=175467Arquivo:TCC290 Vinicius da Luz Souza.pdf2021-04-14T20:07:39Z<p>Msobral: </p>
<hr />
<div></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=TCC_da_Engenharia_de_Telecomunica%C3%A7%C3%B5es_-_conclu%C3%ADdos&diff=175466TCC da Engenharia de Telecomunicações - concluídos2021-04-14T20:00:41Z<p>Msobral: /* Semestre 2020-2 */</p>
<hr />
<div><!-- <br />
Para cada TCC cadastrar os dados abaixo:<br />
<br />
{{ TCC2 | Titulo | Graduando | Orientador | Coorientador | Banca1, Banca2 e Banca3 | Data | Horário | Número }}<br />
<br />
Na página do TCC preencher os dados no modelo abaixo:<br />
<br />
;Resumo:<br />
<br />
;Palavras chave:<br />
<br />
;Abstract:<br />
<br />
;Keywords:<br />
<br />
== Arquivos ==<br />
;Monografia: [[Media: TCC290_KarolinaRocha.pdf | Monografia.pdf]]<br />
;<br />
[[Categoria:Trabalhos de Alunos]]<br />
[[Categoria:Projeto de Fim de Curso]]<br />
--><br />
Os TCCs estão disponíveis em http://biblioteca.ifsc.edu.br/ Campus São José.<br />
<br />
<br />
==Semestre 2020-2==<br />
<br />
{{ TCC2 | Ferramenta para Captura e Análise de Mensagens OMCI em Redes GPON | VINÍCIUS DA LUZ SOUZA | Marcelo Maia Sobral | Roberto de Matos | Marcelo Maia Sobral, Eraldo Silveira e Silva, Jorge Henrique Busatto Casagrande | 01/04/2020 | 16:00 | 43 }}<br />
<br />
{{ TCC2 | Automatização de ensaios da RFC 7084 em roteadores IPv6 para certificações Anatel | RONALDO JOÃO BORGES | Jorge Henrique Busatto Casagrande | Marcelo Sobral | Jorge Henrique Busatto Casagrande, Roberto de Matos, Arliones Stevert Hoeller Junior | 16/11/2020 | 10:00 | 42 }}<br />
<br />
==Semestre 2020-1==<br />
<br />
{{ TCC2 | Interceptação legal em redes de telefonia IP: Proposta de um cenário utilizando Asterisk | JÉSSICA DA SILVA HAHN | Jorge Henrique Busatto Casagrande | Ederson Torresini | Jorge Henrique Busatto Casagrande, Odilson Tadeu Valle, Fabio Alexandre de Souza | 23/10/2020 | 17:00 | 41 }}<br />
<br />
==Semestre 2019-2==<br />
<br />
{{ TCC2 | Redes Industriais IEEE 802.11 x IEEE 802.15.4: Uma análise comparativa no monitoramento de paradas de máquinas | KATHARINE SCHAEFFER FERTIG | Odilson Tadeu Valle | Eraldo Silveira e Silva | Odilson Tadeu Valle, Marcelo Maia Sobral, Tiago Semprebom | 21/02/2020 | 13:35 | 40 }}<br />
<br />
{{ TCC2 | Sistema de Monitoramento e Gerenciamento de Produção de Colmeias com Uso de Progressive Web App | KRISTHINE SCHAEFFER FERTIG | Marcos Moecke | Ederson Torresini | Ederson Torresini, Mario de Noronha Neto, Eduardo Nathan Antunes, Fábio Domingues | 21/02/2020 | 10:00 | 39 }}<br />
<br />
{{ TCC2 | Sistema de controle para ambientes climatizados utilizando processamento remoto e redes mesh | FERNANDO MÜLLER DA SILVA | Pedro Armando da Silva Junior | | Pedro Armando da Silva Junior, Tiago Semprebom, Eraldo Silveira e Silva, Anastácio da Silva Júnior | 17/12/2019 | 09:45 | 38 }}<br />
<br />
==Semestre 2019-1==<br />
<br />
{{ TCC2 | Plataforma de Controle de Versão e Moderação de Código Orientada a SaaS | GUILHERME EVANGELISTA DE ALBUQUERQUE | Ederson Torresini | | Ederson Torresini, Marcelo Maia Sobral, Humberto José de Sousa | 07/08/2019 | 17:00 | 37 }}<br />
<br />
{{ TCC2 | Infraestrutura de Internet das Coisas aplicada a laboratórios remotos usando WebRTC e microserviços | LETÍCIA APARECIDA COELHO | Ederson Torresini | | Ederson Torresini, Mario de Noronha Neto, Gustavo Leão Moreira | 07/08/2019 | 16:00 | 36 }}<br />
<br />
{{ TCC2 | Localização indoor utilizando Bluetooth Low Energy e aprendizado de máquina | DANIEL TREVISAN TATSCH | Roberto de Matos | Mario de Noronha Neto | Roberto de Matos, Eraldo Silveira e Silva, Jorge Henrique Busatto Casagrande | 10/07/2019 | 14:01 | 35 }}<br />
<br />
{{ TCC2 | Reconhecimento de silhueta de automóveis para carros autônomos utilizando aprendizado de máquina | TAMARA RAMOS ARRIGONI | Ramon Mayor Martins | Diego da Silva de Medeiros | Diego da Silva de Medeiros, Elen Macedo Lobato, Mario de Noronha Neto | 10/07/2019 | 10:40 | 34 }}<br />
<br />
{{ TCC2 | Automatização de testes na camada física de equipamentos IEEE 802.11 utilizando rádio definido por software | PEDRO HENRIQUE DA SILVA HAMES | Roberto Wanderley da Nóbrega | | Roberto Wanderley da Nóbrega, Tiago Semprebom, Roberto de Matos, Guilherme Frederico Weidle Junior | 10/07/2019 | 09:40 | 33 }}<br />
<br />
{{ TCC2 | Evaluating Impact of Temperature Stimulus on Signal Quality from a Wearable Pulse Optical Sensor | JESSICA DE SOUZA | Roberto de Matos | Sidhant Gupta | Roberto de Matos, Deise Monquelate Arndt, Marcos Moecke | 09/07/2019 | 15:03 | 32 }}<br />
<br />
{{ TCC2 | Sistema de Manutenção Preditiva Utilizando Redes BLE e Wi-Fi com Aprendizado de Máquina | VITOR MANOEL DA SILVEIRA | Mario de Noronha Neto | Valdir Noll | Mario de Noronha Neto, Roberto Alexandre Dias, Roberto de Matos | 09/07/2019 | 10:35 | 31 }}<br />
<br />
{{ TCC2 | Sistema para detecção de faixas em rodovias: Aplicação de técnicas a partir da utilização do método Systematic Search Flow | LUCAS GOMES DE FARIAS | Diego da Silva de Medeiros | Renata Coelho Borges | Diego da Silva de Medeiros, Ramon Mayor Martins, Wemerson Delcio Parreira | 05/07/2019 | 14:00 | 30 }}<br />
<br />
{{ TCC2 | Nuvem privada multizona usando orquestração de contêineres: Proposta multicâmpus de alta disponibilidade para o IFSC | GABRIEL DE SOUZA | Ederson Torresini | Humberto José de Sousa | Ederson Torresini, Odilson Tadeu Valle, Christopher Giese | 01/07/2019 | 09:35 | 29 }}<br />
<br />
==Semestre 2018-2==<br />
<br />
{{ TCC2 | Analisador de Controle Remoto Utilizando RTL-SDR | MARCOS VINICIOS PINHO | Roberto Wanderley da Nóbrega | Ramon Mayor Martins | Diego da Silva de Medeiros, Marcos Moecke | 18/12/2018 | 8h10min | 28 }}<br />
<br />
{{ TCC2 | Implementação de um sistema ADS-B através de técnicas de Rádio Definido por Software | LUCAS LUCINDO VIEIRA | Roberto Wanderley da Nóbrega | Ramon Mayor Martins | Fábio Alexandre de Souza, Clayrton Monteiro Henrique | 17/12/2018 | 10h10min | 27 }}<br />
<br />
{{ TCC2 | Roteamento para Estender o Tempo de Vida de Redes de Sensores sem Fios Utilizando Redes Definidas por Software | ANDRE FELIPPE WEBER | Tiago Semprebom | Eraldo Silveira e Silva | Marcelo Maia Sobral, Carlos Barros Montez | 14/12/2018 | 10h30min | 26 }}<br />
<br />
{{ TCC2 | Desenvolvimento de um Sistema de Reconhecimento de Locutor Utilizando Aprendizado de Máquina | HENRIQUE HILLESHEIN | Mário de Noronha Neto | Rafael de Souza Toledo | Diego da Silva de Medeiros, Tiago Semprebom | 14/12/2018 | 9h15min | 25 }}<br />
<br />
{{ TCC2 | Mineração de dados usando inteligência artificial para análise de log de nuvem privada de contêineres | MARIA LUIZA THEISGES | Ederson Torresini | Clayrton Monteiro Henrique, Fernando Rodrigues Santos | Diego da Silva de Medeiros, Humberto José de Souza | 14/12/2018 | 7h30min | 24 }}<br />
<br />
{{ TCC2 | Proposta de armazenamento distribuído baseado em contêineres em infraestrutura hiperconvergente | MATUZALEM MULLER DOS SANTOS | Ederson Torresini | Jorge H. B. Casagrande | Emerson Ribeiro de Mello, Humberto José de Souza | 13/12/2018 | 10h30min | 23 }}<br />
<br />
{{ TCC2 | Métodos Híbridos para Gerenciamento de Projetos em Desenvolvimento de Software | NATAN MARTINS JORY | Clayrton Monteiro Henrique | | Ederson Torresini, Pedro Paulo Corrêa de Souza, Fernanda Dias de Oliveira da Rocha | 12/12/2018 | 10h | 22 }}<br />
<br />
{{ TCC2 | Projeto de um Subsistema de Telecomunicações para Nanossatélite em LEO | ELTON FERREIRA BROERING | Ramon Mayor Martins | | Roberto de Matos, Roberto Wanderley da Nóbrega, Rubem Toledo Bergamo | 10/12/2018 | 13h35min | 21 }}<br />
<br />
{{ TCC2 | Desenvolvimento de Software didático para análise de linhas de transmissão, baseado em Carta de Smith | PAULA CRISTINA GRANDO | Evanaska Maria Barbosa Nogueira | Diego da Silva de Medeiros | Clayrton Monteiro Henrique, Roberto Wanderley da Nóbrega, Saul Silva Caetano | 07/12/2018 | 13h10min | 20 }}<br />
<br />
{{ TCC2 | Analise de propagação de redes WLAN em ambientes indoor | MATEUS ARAUJO SILVA | Evanaska Maria Barbosa Nogueira | | Diego da Silva de Medeiros, Mario de Noronha Neto | 06/121/2018 | 10h | 19 }}<br />
<br />
{{ TCC2 | Análise do sinal de eletrocardiograma para detecção de cardiopatias | BRUNO MARCOS ESPINDOLA | Elen Macedo Lobato | | Diego da Silva de Medeiros, Ramon Mayor Martins | 30/11/2018 | 10h | 18 }}<br />
<br />
==Semestre 2018-1==<br />
<br />
{{ TCC2 | Implementação de Toolbox Octave de Técnicas de Sincronismo de Símbolo em Sistemas de Telecomunicações | GABRIEL COZER CANTU | Roberto Wanderley da Nóbrega | | Eraldo Silveira e Silva, Mário de Noronha Neto | 09/07/2018 | 13h30 | 17 }}<br />
<br />
{{ TCC2 | Utilização da tecnologia LoRaWAN para o monitoramento de dados ambientais | THIAGO WERNER | Mário de Noronha Neto | | Arliones Stevert Hoeller Junior, Ramon Mayor Martins, Rubem Toledo Bergamo | 09/07/2018 | 9h10 | 16 }}<br />
<br />
{{ TCC2 | Sistema Didático para Análise de Sinais no Domínio da Frequência: Implementação em FPGA | GUSTAVO PAULO MEDEIROS DA SILVA | Marcos Moecke | | Diego da Silva de Medeiros, Roberto de Matos | 06/07/2018 | 9h40 | 15 }}<br />
<br />
{{ TCC2 | Projeto de antenas Moxon-Yagi para comunicação com satélites de órbita baixa (LEO) | WALTER CARDOSO DE FREITAS JÚNIOR | Ramon Mayor Martins | | Rubem Toledo Bergamo, Evanaska Maria Barbosa Nogueira, Roberto Wanderley da Nóbrega | 04/07/2018 | 13h35 | 14 }}<br />
<br />
{{ TCC2 | Controle de Modulação e codificação adaptativo utilizando GNU Rádio | MARCUS VINICIUS BUNN | Roberto Wanderley da Nóbrega | | Mário de Noronha Neto, Ramon Mayor Martins | 02/07/2018 | 14h30 | 13 }}<br />
<br />
==Semestre 2017-2==<br />
<br />
{{ TCC2 | Mapeamento de Qualidade de Serviço em Redes IEEE 802.15.4 | THIAGO HENRIQUE BONOTTO DA SILVA | Tiago Semprebom | Eraldo Silveira e Silva | Marcelo Maia Sobral, Odilson Tadeu Valle | 20/12/2017 | 8h | 12 }}<br />
<br />
{{ TCC2 | Algoritmo de Identificação de Sinais Intermitentes no Espectro Radioelétrico | STEPHANY PADILHA GUIMARAES | Mario de Noronha Neto | Douglas Amorim Ferreira | Ramon Mayor Martins, Roberto Wanderley da Nóbrega | 19/12/2017 | 17h | 11 }}<br />
<br />
{{ TCC2 | Reconhecimento de Placas de Sinalização de Trânsito via Processamento Digital de Imagem de Aprendizado de Máquina | MATHIAS SILVA DA ROSA | Diego da Silva de Medeiros | Deise Monquelate Arndt | Ramon Mayor Martins, Marcos Moecke | 19/12/2017 | 09h30min | 10 }}<br />
<br />
{{ TCC2 | Localização Indoor Utilizando a Tecnologia LoRaWAN e Aprendizado de Máquina | GIULIO CRUZ DE OLIVEIRA | Mario de Noronha Neto | Arliones Stevert Hoeller Junior | Evanaska Maria Barbosa Nogueira, Maria Claudia de Almeida Castro, Richard Demo Souza | 18/12/2017 | 10h30min | 9 }}<br />
<br />
{{ TCC2 | Reconhecimento de Voz utilizando extração de Coeficientes Mel-Cepstrais e Redes Neurais Artificiais | ERNANI RODRIGUES DE S.THIAGO | Ramon Mayor Martins | | Elen Macedo Lobato, Diego da Silva de Medeiros, Cleber Jorge Amaral | 18/12/2017 | 9h20min | 8 }}<br />
<br />
{{ TCC2 | Redução de sensores de EEG e detecção de movimento motor através de Redes Neurais Artificiais | VINICIUS BANDEIRA | Ramon Mayor Martins | | Elen Macedo Lobato, Diego da Silva de Medeiros, Cleber Jorge Amaral | 15/12/2017 | 8h | 7 }}<br />
<br />
==Semestre 2017-1==<br />
<br />
{{ TCC2 | Detecção de vértebras em imagens médicas - Estudo de caso Pixeon | KAROLINE DA ROCHA | Marcos Moecke | | Diego da Silva de Medeiros, Ramon Mayor Martins | 11/08/2017 | 15h30min | 6 }}<br />
<br />
{{ TCC2 | Implantação de engenharia de tráfego com MPLS-TE em rede WAN | ANA LUIZA SCHARF | Marcelo Maia Sobral | | Odilson Tadeu Valle, Jorge H. B. Casagrande | 11/08/2017 | 13h30min | 5 }}<br />
<br />
{{ TCC2 | Estudo e Análise das Antenas utilizadas em RFID | TIAGO TEIXEIRA | Ramon Mayor Martins | | Rubem Toledo Bergamo, Clayrton M. Henrique | 10/08/2017 | 15h40min | 4 }}<br />
<br />
{{ TCC2 | Plataforma de desenvolvimento de aplicações IoT utilizando redes LoRaWAN | LEONAN DA SILVA SARAIVA | Arliones Stevert Hoeller Junior | | Tiago Semprebom, Eraldo Silveira e Silva | 06/07/2017 | 10h30min | 3 }}<br />
<br />
==Semestre 2016-2==<br />
<br />
{{ TCC2 | Redes LoRaWAN: implantação e desenvolvimento de aplicações | JEAN MICHEL DE SOUZA SANT'ANA | Prof. Me. Arliones Stevert Hoeller Junior | Prof. Dr. Mario de Noronha Neto | Prof. Dr. Richard Demo Souza, Prof. Dr. Odilson Tadeu Valle, Prof. Dr. Marcelo Maia Sobral | 03/03/2017 | 11h | 2 }}<br />
<br />
{{ TCC2 | Testes de desempenho de enlaces ponto a ponto da tecnologia LoRa | DANILO BEDAQUE | Prof. Dr. Mario de Noronha Neto | Prof. Dr. Richard Demo Souza | Prof. Dr. Fábio Alexandre de Souza, Prof. Me. Arliones Stevert Hoeller Junior, Prof. Me. Diego da Silva Medeiros | 03/03/2017 | 10h | 1 }}<br />
<br />
[[Categoria:TCC]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=TCC_da_Engenharia_de_Telecomunica%C3%A7%C3%B5es_-_conclu%C3%ADdos&diff=175465TCC da Engenharia de Telecomunicações - concluídos2021-04-14T20:00:24Z<p>Msobral: /* Semestre 2020-2 */</p>
<hr />
<div><!-- <br />
Para cada TCC cadastrar os dados abaixo:<br />
<br />
{{ TCC2 | Titulo | Graduando | Orientador | Coorientador | Banca1, Banca2 e Banca3 | Data | Horário | Número }}<br />
<br />
Na página do TCC preencher os dados no modelo abaixo:<br />
<br />
;Resumo:<br />
<br />
;Palavras chave:<br />
<br />
;Abstract:<br />
<br />
;Keywords:<br />
<br />
== Arquivos ==<br />
;Monografia: [[Media: TCC290_KarolinaRocha.pdf | Monografia.pdf]]<br />
;<br />
[[Categoria:Trabalhos de Alunos]]<br />
[[Categoria:Projeto de Fim de Curso]]<br />
--><br />
Os TCCs estão disponíveis em http://biblioteca.ifsc.edu.br/ Campus São José.<br />
<br />
<br />
==Semestre 2020-2==<br />
<br />
{{ TCC2 | Automatização de ensaios da RFC 7084 em roteadores IPv6 para certificações Anatel | RONALDO JOÃO BORGES | Jorge Henrique Busatto Casagrande | Marcelo Sobral | Jorge Henrique Busatto Casagrande, Roberto de Matos, Arliones Stevert Hoeller Junior | 16/11/2020 | 10:00 | 42 }}<br />
<br />
{{ TCC2 | Ferramenta para Captura e Análise de Mensagens OMCI em Redes GPON | VINÍCIUS DA LUZ SOUZA | Marcelo Maia Sobral | Roberto de Matos | Marcelo Maia Sobral, Eraldo Silveira e Silva, Jorge Henrique Busatto Casagrande | 01/04/2020 | 16:00 | 43 }}<br />
<br />
==Semestre 2020-1==<br />
<br />
{{ TCC2 | Interceptação legal em redes de telefonia IP: Proposta de um cenário utilizando Asterisk | JÉSSICA DA SILVA HAHN | Jorge Henrique Busatto Casagrande | Ederson Torresini | Jorge Henrique Busatto Casagrande, Odilson Tadeu Valle, Fabio Alexandre de Souza | 23/10/2020 | 17:00 | 41 }}<br />
<br />
==Semestre 2019-2==<br />
<br />
{{ TCC2 | Redes Industriais IEEE 802.11 x IEEE 802.15.4: Uma análise comparativa no monitoramento de paradas de máquinas | KATHARINE SCHAEFFER FERTIG | Odilson Tadeu Valle | Eraldo Silveira e Silva | Odilson Tadeu Valle, Marcelo Maia Sobral, Tiago Semprebom | 21/02/2020 | 13:35 | 40 }}<br />
<br />
{{ TCC2 | Sistema de Monitoramento e Gerenciamento de Produção de Colmeias com Uso de Progressive Web App | KRISTHINE SCHAEFFER FERTIG | Marcos Moecke | Ederson Torresini | Ederson Torresini, Mario de Noronha Neto, Eduardo Nathan Antunes, Fábio Domingues | 21/02/2020 | 10:00 | 39 }}<br />
<br />
{{ TCC2 | Sistema de controle para ambientes climatizados utilizando processamento remoto e redes mesh | FERNANDO MÜLLER DA SILVA | Pedro Armando da Silva Junior | | Pedro Armando da Silva Junior, Tiago Semprebom, Eraldo Silveira e Silva, Anastácio da Silva Júnior | 17/12/2019 | 09:45 | 38 }}<br />
<br />
==Semestre 2019-1==<br />
<br />
{{ TCC2 | Plataforma de Controle de Versão e Moderação de Código Orientada a SaaS | GUILHERME EVANGELISTA DE ALBUQUERQUE | Ederson Torresini | | Ederson Torresini, Marcelo Maia Sobral, Humberto José de Sousa | 07/08/2019 | 17:00 | 37 }}<br />
<br />
{{ TCC2 | Infraestrutura de Internet das Coisas aplicada a laboratórios remotos usando WebRTC e microserviços | LETÍCIA APARECIDA COELHO | Ederson Torresini | | Ederson Torresini, Mario de Noronha Neto, Gustavo Leão Moreira | 07/08/2019 | 16:00 | 36 }}<br />
<br />
{{ TCC2 | Localização indoor utilizando Bluetooth Low Energy e aprendizado de máquina | DANIEL TREVISAN TATSCH | Roberto de Matos | Mario de Noronha Neto | Roberto de Matos, Eraldo Silveira e Silva, Jorge Henrique Busatto Casagrande | 10/07/2019 | 14:01 | 35 }}<br />
<br />
{{ TCC2 | Reconhecimento de silhueta de automóveis para carros autônomos utilizando aprendizado de máquina | TAMARA RAMOS ARRIGONI | Ramon Mayor Martins | Diego da Silva de Medeiros | Diego da Silva de Medeiros, Elen Macedo Lobato, Mario de Noronha Neto | 10/07/2019 | 10:40 | 34 }}<br />
<br />
{{ TCC2 | Automatização de testes na camada física de equipamentos IEEE 802.11 utilizando rádio definido por software | PEDRO HENRIQUE DA SILVA HAMES | Roberto Wanderley da Nóbrega | | Roberto Wanderley da Nóbrega, Tiago Semprebom, Roberto de Matos, Guilherme Frederico Weidle Junior | 10/07/2019 | 09:40 | 33 }}<br />
<br />
{{ TCC2 | Evaluating Impact of Temperature Stimulus on Signal Quality from a Wearable Pulse Optical Sensor | JESSICA DE SOUZA | Roberto de Matos | Sidhant Gupta | Roberto de Matos, Deise Monquelate Arndt, Marcos Moecke | 09/07/2019 | 15:03 | 32 }}<br />
<br />
{{ TCC2 | Sistema de Manutenção Preditiva Utilizando Redes BLE e Wi-Fi com Aprendizado de Máquina | VITOR MANOEL DA SILVEIRA | Mario de Noronha Neto | Valdir Noll | Mario de Noronha Neto, Roberto Alexandre Dias, Roberto de Matos | 09/07/2019 | 10:35 | 31 }}<br />
<br />
{{ TCC2 | Sistema para detecção de faixas em rodovias: Aplicação de técnicas a partir da utilização do método Systematic Search Flow | LUCAS GOMES DE FARIAS | Diego da Silva de Medeiros | Renata Coelho Borges | Diego da Silva de Medeiros, Ramon Mayor Martins, Wemerson Delcio Parreira | 05/07/2019 | 14:00 | 30 }}<br />
<br />
{{ TCC2 | Nuvem privada multizona usando orquestração de contêineres: Proposta multicâmpus de alta disponibilidade para o IFSC | GABRIEL DE SOUZA | Ederson Torresini | Humberto José de Sousa | Ederson Torresini, Odilson Tadeu Valle, Christopher Giese | 01/07/2019 | 09:35 | 29 }}<br />
<br />
==Semestre 2018-2==<br />
<br />
{{ TCC2 | Analisador de Controle Remoto Utilizando RTL-SDR | MARCOS VINICIOS PINHO | Roberto Wanderley da Nóbrega | Ramon Mayor Martins | Diego da Silva de Medeiros, Marcos Moecke | 18/12/2018 | 8h10min | 28 }}<br />
<br />
{{ TCC2 | Implementação de um sistema ADS-B através de técnicas de Rádio Definido por Software | LUCAS LUCINDO VIEIRA | Roberto Wanderley da Nóbrega | Ramon Mayor Martins | Fábio Alexandre de Souza, Clayrton Monteiro Henrique | 17/12/2018 | 10h10min | 27 }}<br />
<br />
{{ TCC2 | Roteamento para Estender o Tempo de Vida de Redes de Sensores sem Fios Utilizando Redes Definidas por Software | ANDRE FELIPPE WEBER | Tiago Semprebom | Eraldo Silveira e Silva | Marcelo Maia Sobral, Carlos Barros Montez | 14/12/2018 | 10h30min | 26 }}<br />
<br />
{{ TCC2 | Desenvolvimento de um Sistema de Reconhecimento de Locutor Utilizando Aprendizado de Máquina | HENRIQUE HILLESHEIN | Mário de Noronha Neto | Rafael de Souza Toledo | Diego da Silva de Medeiros, Tiago Semprebom | 14/12/2018 | 9h15min | 25 }}<br />
<br />
{{ TCC2 | Mineração de dados usando inteligência artificial para análise de log de nuvem privada de contêineres | MARIA LUIZA THEISGES | Ederson Torresini | Clayrton Monteiro Henrique, Fernando Rodrigues Santos | Diego da Silva de Medeiros, Humberto José de Souza | 14/12/2018 | 7h30min | 24 }}<br />
<br />
{{ TCC2 | Proposta de armazenamento distribuído baseado em contêineres em infraestrutura hiperconvergente | MATUZALEM MULLER DOS SANTOS | Ederson Torresini | Jorge H. B. Casagrande | Emerson Ribeiro de Mello, Humberto José de Souza | 13/12/2018 | 10h30min | 23 }}<br />
<br />
{{ TCC2 | Métodos Híbridos para Gerenciamento de Projetos em Desenvolvimento de Software | NATAN MARTINS JORY | Clayrton Monteiro Henrique | | Ederson Torresini, Pedro Paulo Corrêa de Souza, Fernanda Dias de Oliveira da Rocha | 12/12/2018 | 10h | 22 }}<br />
<br />
{{ TCC2 | Projeto de um Subsistema de Telecomunicações para Nanossatélite em LEO | ELTON FERREIRA BROERING | Ramon Mayor Martins | | Roberto de Matos, Roberto Wanderley da Nóbrega, Rubem Toledo Bergamo | 10/12/2018 | 13h35min | 21 }}<br />
<br />
{{ TCC2 | Desenvolvimento de Software didático para análise de linhas de transmissão, baseado em Carta de Smith | PAULA CRISTINA GRANDO | Evanaska Maria Barbosa Nogueira | Diego da Silva de Medeiros | Clayrton Monteiro Henrique, Roberto Wanderley da Nóbrega, Saul Silva Caetano | 07/12/2018 | 13h10min | 20 }}<br />
<br />
{{ TCC2 | Analise de propagação de redes WLAN em ambientes indoor | MATEUS ARAUJO SILVA | Evanaska Maria Barbosa Nogueira | | Diego da Silva de Medeiros, Mario de Noronha Neto | 06/121/2018 | 10h | 19 }}<br />
<br />
{{ TCC2 | Análise do sinal de eletrocardiograma para detecção de cardiopatias | BRUNO MARCOS ESPINDOLA | Elen Macedo Lobato | | Diego da Silva de Medeiros, Ramon Mayor Martins | 30/11/2018 | 10h | 18 }}<br />
<br />
==Semestre 2018-1==<br />
<br />
{{ TCC2 | Implementação de Toolbox Octave de Técnicas de Sincronismo de Símbolo em Sistemas de Telecomunicações | GABRIEL COZER CANTU | Roberto Wanderley da Nóbrega | | Eraldo Silveira e Silva, Mário de Noronha Neto | 09/07/2018 | 13h30 | 17 }}<br />
<br />
{{ TCC2 | Utilização da tecnologia LoRaWAN para o monitoramento de dados ambientais | THIAGO WERNER | Mário de Noronha Neto | | Arliones Stevert Hoeller Junior, Ramon Mayor Martins, Rubem Toledo Bergamo | 09/07/2018 | 9h10 | 16 }}<br />
<br />
{{ TCC2 | Sistema Didático para Análise de Sinais no Domínio da Frequência: Implementação em FPGA | GUSTAVO PAULO MEDEIROS DA SILVA | Marcos Moecke | | Diego da Silva de Medeiros, Roberto de Matos | 06/07/2018 | 9h40 | 15 }}<br />
<br />
{{ TCC2 | Projeto de antenas Moxon-Yagi para comunicação com satélites de órbita baixa (LEO) | WALTER CARDOSO DE FREITAS JÚNIOR | Ramon Mayor Martins | | Rubem Toledo Bergamo, Evanaska Maria Barbosa Nogueira, Roberto Wanderley da Nóbrega | 04/07/2018 | 13h35 | 14 }}<br />
<br />
{{ TCC2 | Controle de Modulação e codificação adaptativo utilizando GNU Rádio | MARCUS VINICIUS BUNN | Roberto Wanderley da Nóbrega | | Mário de Noronha Neto, Ramon Mayor Martins | 02/07/2018 | 14h30 | 13 }}<br />
<br />
==Semestre 2017-2==<br />
<br />
{{ TCC2 | Mapeamento de Qualidade de Serviço em Redes IEEE 802.15.4 | THIAGO HENRIQUE BONOTTO DA SILVA | Tiago Semprebom | Eraldo Silveira e Silva | Marcelo Maia Sobral, Odilson Tadeu Valle | 20/12/2017 | 8h | 12 }}<br />
<br />
{{ TCC2 | Algoritmo de Identificação de Sinais Intermitentes no Espectro Radioelétrico | STEPHANY PADILHA GUIMARAES | Mario de Noronha Neto | Douglas Amorim Ferreira | Ramon Mayor Martins, Roberto Wanderley da Nóbrega | 19/12/2017 | 17h | 11 }}<br />
<br />
{{ TCC2 | Reconhecimento de Placas de Sinalização de Trânsito via Processamento Digital de Imagem de Aprendizado de Máquina | MATHIAS SILVA DA ROSA | Diego da Silva de Medeiros | Deise Monquelate Arndt | Ramon Mayor Martins, Marcos Moecke | 19/12/2017 | 09h30min | 10 }}<br />
<br />
{{ TCC2 | Localização Indoor Utilizando a Tecnologia LoRaWAN e Aprendizado de Máquina | GIULIO CRUZ DE OLIVEIRA | Mario de Noronha Neto | Arliones Stevert Hoeller Junior | Evanaska Maria Barbosa Nogueira, Maria Claudia de Almeida Castro, Richard Demo Souza | 18/12/2017 | 10h30min | 9 }}<br />
<br />
{{ TCC2 | Reconhecimento de Voz utilizando extração de Coeficientes Mel-Cepstrais e Redes Neurais Artificiais | ERNANI RODRIGUES DE S.THIAGO | Ramon Mayor Martins | | Elen Macedo Lobato, Diego da Silva de Medeiros, Cleber Jorge Amaral | 18/12/2017 | 9h20min | 8 }}<br />
<br />
{{ TCC2 | Redução de sensores de EEG e detecção de movimento motor através de Redes Neurais Artificiais | VINICIUS BANDEIRA | Ramon Mayor Martins | | Elen Macedo Lobato, Diego da Silva de Medeiros, Cleber Jorge Amaral | 15/12/2017 | 8h | 7 }}<br />
<br />
==Semestre 2017-1==<br />
<br />
{{ TCC2 | Detecção de vértebras em imagens médicas - Estudo de caso Pixeon | KAROLINE DA ROCHA | Marcos Moecke | | Diego da Silva de Medeiros, Ramon Mayor Martins | 11/08/2017 | 15h30min | 6 }}<br />
<br />
{{ TCC2 | Implantação de engenharia de tráfego com MPLS-TE em rede WAN | ANA LUIZA SCHARF | Marcelo Maia Sobral | | Odilson Tadeu Valle, Jorge H. B. Casagrande | 11/08/2017 | 13h30min | 5 }}<br />
<br />
{{ TCC2 | Estudo e Análise das Antenas utilizadas em RFID | TIAGO TEIXEIRA | Ramon Mayor Martins | | Rubem Toledo Bergamo, Clayrton M. Henrique | 10/08/2017 | 15h40min | 4 }}<br />
<br />
{{ TCC2 | Plataforma de desenvolvimento de aplicações IoT utilizando redes LoRaWAN | LEONAN DA SILVA SARAIVA | Arliones Stevert Hoeller Junior | | Tiago Semprebom, Eraldo Silveira e Silva | 06/07/2017 | 10h30min | 3 }}<br />
<br />
==Semestre 2016-2==<br />
<br />
{{ TCC2 | Redes LoRaWAN: implantação e desenvolvimento de aplicações | JEAN MICHEL DE SOUZA SANT'ANA | Prof. Me. Arliones Stevert Hoeller Junior | Prof. Dr. Mario de Noronha Neto | Prof. Dr. Richard Demo Souza, Prof. Dr. Odilson Tadeu Valle, Prof. Dr. Marcelo Maia Sobral | 03/03/2017 | 11h | 2 }}<br />
<br />
{{ TCC2 | Testes de desempenho de enlaces ponto a ponto da tecnologia LoRa | DANILO BEDAQUE | Prof. Dr. Mario de Noronha Neto | Prof. Dr. Richard Demo Souza | Prof. Dr. Fábio Alexandre de Souza, Prof. Me. Arliones Stevert Hoeller Junior, Prof. Me. Diego da Silva Medeiros | 03/03/2017 | 10h | 1 }}<br />
<br />
[[Categoria:TCC]]</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PRG29003:_A_implementa%C3%A7%C3%A3o_da_%C3%A1rvore_de_pesquisa_bin%C3%A1ria&diff=174745PRG29003: A implementação da árvore de pesquisa binária2021-03-13T23:10:21Z<p>Msobral: /* Enumerando os dados de uma árvore */</p>
<hr />
<div>__toc__<br />
<br />
No [[PRG29003:_Introdução_a_árvores_binárias|projeto 4]] estudaram-se árvores de pesquisa binária como forma de acesso rápido a dados armazenados. Usou-se então uma implementação de árvore fornecida na ''prglib''. Agora deve-se implementar essa estrutura de dados para que ofereça as mesmas operações existentes na ''prglib'' original.<br />
<br />
= Começando uma árvore binária =<br />
<br />
A árvore de pesquisa binária é formada por nodos que armazenam um dado qualquer (da mesma forma que foi feito com listas), e possui no máximo dois ramos. O ponto de partida pode ser visto na primeira versão do arquivo ''libs/arvore.h'', mostrada abaixo:<br />
<br />
<syntaxhighlight lang=c><br />
#ifndef ARVORE_H<br />
#define ARVORE_H<br />
<br />
#include <istream><br />
#include <string><br />
<br />
using std::string;<br />
using std::istream;<br />
<br />
namespace prglib {<br />
<br />
template <typename T> class arvore {<br />
public:<br />
// este construtor na prática não deve ser usado ...<br />
arvore();<br />
<br />
// cria um nodo da árvore, o qual contém o dado passado no parâmetro "dado"<br />
arvore(const T & dado);<br />
<br />
// cria uma árvore cujos nodos contêm os dados contidos na lista "dados"<br />
arvore(lista<T> & dados);<br />
<br />
// cria uma árvore cujos nodos contêm os dados contidos na stream "inp" (que pode ser um arquivo)<br />
arvore(istream & inp);<br />
<br />
// cria uma árvore que é uma cópia de "outra"<br />
arvore(const arvore<T> & outra);<br />
<br />
// destrutor da árvore<br />
~arvore();<br />
<br />
// adiciona um dado à árvore<br />
void adiciona(const T& algo);<br />
<br />
// acessa um dado contido na árvore. OBS o dado acessado não pode ser modificado !<br />
const T& obtem(const T & algo) const;<br />
<br />
// obtém o valor da raiz da árvore. OBS esse valor não pode ser modificado !<br />
const T& obtem() const ;<br />
<br />
// operações de enumeração dos dados da árvore<br />
void listeInOrder(lista<T> & result);<br />
void listePreOrder(lista<T> & result);<br />
void listePostOrder(lista<T> & result);<br />
void listeEmLargura(lista<T> & result);<br />
<br />
// retorna a quantidade de dados contidos na árvore<br />
unsigned int tamanho() const;<br />
<br />
// retorna a altura da árvore<br />
unsigned int altura() ;<br />
<br />
// retorna o fator de balanceamento da árvore (em torno da raiz)<br />
int fatorB() ;<br />
<br />
// balanceia a árvore usando o algoritmo AVL<br />
// retorna a nova raiz da árvore<br />
arvore<T> * balanceia();<br />
<br />
// balanceia a árvore usando o algoritmo AVL<br />
// se o parâmetro "otimo" for true, repete o balanceamento sucessivamente, até que<br />
// a altura da árvore não mais reduza<br />
// retorna a nova raiz da árvore<br />
arvore<T> * balanceia(bool otimo);<br />
<br />
// retorna a subárvore esquerda<br />
arvore<T> * esquerda();<br />
<br />
// retorna a subárvore direita<br />
arvore<T> * direita();<br />
<br />
// Iteração da árvore (in-order)<br />
void inicia();<br />
bool fim();<br />
T& proximo();<br />
<br />
// iteração reversa da árvore (in-order)<br />
void iniciaPeloFim();<br />
bool inicio();<br />
T& anterior();<br />
<br />
// remove um dado da árvore. Retorna uma cópia do dado removido<br />
T remove(const T & algo);<br />
<br />
// obtém o menor dado contido na árvore. OBS esse dado não pode ser modificado<br />
T & obtemMenor() const;<br />
<br />
// obtém o maior dado contido na árvore. OBS esse dado não pode ser modificado<br />
T & obtemMaior() const;<br />
<br />
// obtém os dados menores que "algo"<br />
void obtemMenoresQue(lista<T> & result, const T & algo);<br />
<br />
// obtém os dados maiores que "algo"<br />
void obtemMaioresQue(lista<T> & result, const T & algo);<br />
<br />
// obtém todos valores entre "start" e "end" (inclusive)<br />
void obtemIntervalo(lista<T> & result, const T & start, const T & end);<br />
protected:<br />
T data;<br />
arvore<T> * esq, * dir, * pai;<br />
<br />
arvore<T> * rotacionaL(); <br />
arvore<T> * rotacionaR(); <br />
};<br />
<br />
} // fim do namespace<br />
<br />
#include <libs/arvore-impl.h><br />
<br />
#endif /* ARVORE_H */<br />
</syntaxhighlight><br />
<br />
== Atividade ==<br />
<br />
'''OBS:''' O programa abaixo pode ser usado como um testador inicial da implementação da árvore:<br />
<br />
{{collapse top | Programa de teste da árvore}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <string><br />
#include <prglib.h><br />
<br />
using namespace std;<br />
using prglib::arvore;<br />
<br />
int main() {<br />
string w[7] = {"graviola","caju","sapoti","acai", "banana","morango","laranja"};<br />
<br />
// Uma árvore deve ser criada dinamicamente ... isso facilita<br />
// sua implementação.<br />
arvore<string> * arv = new arvore<string>(w[0]);<br />
<br />
for (int n=1; n < 6; n++) arv->adiciona(w[n]);<br />
<br />
for (int n=0; n < 7; n++) {<br />
try {<br />
cout << "arv[" << w[n] << "] = " << arv->obtem(w[n]) << endl;<br />
} catch (...) {<br />
cout << "Ops: " << w[n] << " não está na árvore !" << endl;<br />
}<br />
}<br />
<br />
delete arv;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O resultado de sua execução deve ser este: <syntaxhighlight lang=text><br />
arv[graviola] = graviola<br />
arv[caju] = caju<br />
arv[sapoti] = sapoti<br />
arv[acai] = acai<br />
arv[banana] = banana<br />
arv[morango] = morango<br />
Ops: laranja não está na árvore !<br />
</syntaxhighlight><br />
<br />
{{collapse top | versão alternativa do programa de teste}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <string><br />
#include <prglib.h><br />
<br />
using namespace std;<br />
using prglib::arvore;<br />
<br />
int main() {<br />
string w[7] = {"graviola", "caju","sapoti","acai", "banana","morango","laranja"};<br />
<br />
// Uma árvore deve ser criada dinamicamente ... isso facilita<br />
// sua implementação.<br />
arvore<string> * arv = nullptr;<br />
<br />
for (auto & fruta : w) {<br />
if (arv) arv->adiciona(fruta);<br />
else arv = new arvore<string>(fruta);<br />
}<br />
<br />
for (auto & fruta : w) {<br />
try {<br />
cout << "arv[" << fruta << "] = " << arv->obtem(fruta) << endl;<br />
} catch (...) {<br />
cout << "Ops: " << fruta << " não está na árvore !" << endl;<br />
}<br />
}<br />
<br />
delete arv;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
{{collapse bottom}}<br />
<br />
<br />
# Implemente ''adiciona'' e ''obtem'' de forma não-recursiva. Nessa versão, esses métodos usam um laço para percorrer os nodos da árvore. <syntaxhighlight lang=text><br />
algoritmo adiciona(algo):<br />
Define raiz como nodo atual<br />
Para sempre faça<br />
se algo igual ao dado do nodo atual então <br />
substitui dado do nodo atual por algo<br />
termina algoritmo<br />
fimSe<br />
se algo menor que dado do nodo atual então <br />
se existe ramo esquerdo então nodo atual é o nodo da esquerda<br />
senão <br />
cria novo nodo com algo<br />
conecta o novo nodo no ramo esquerdo<br />
termina algoritmo<br />
fimSe<br />
senão<br />
se existe ramo direito então nodo atual é o nodo da direita<br />
senão <br />
cria novo nodo com algo<br />
conecta o novo nodo no ramo direito<br />
termina algoritmo<br />
fimSe<br />
fimSe <br />
fimPara<br />
fim adiciona<br />
</syntaxhighlight><br />
# Como exercício, implemente ''adiciona'' e ''obtem'' de forma recursiva. Nessa versão, esses métodos NÃO usam um laço para percorrer os nodos da árvore. ''Dica:'' note que cada ramo de uma árvore pode ser visto como uma outra árvore. Esses métodos são parecidos, e o seguinte pseudo-código ilustra o método adiciona em uma versão não-recursiva: <syntaxhighlight lang=text><br />
algoritmo adiciona(algo):<br />
se algo igual ao dado da raiz então <br />
substitui dado da raiz por algo<br />
termina algoritmo<br />
fimSe<br />
se algo menor que dado da raiz então <br />
se existe ramo esquerdo então adiciona algo na subárvore da esquerda<br />
senão <br />
cria novo nodo com algo<br />
conecta o novo nodo no ramo esquerdo<br />
termina algoritmo<br />
fimSe<br />
senão<br />
se existe ramo direito então adiciona algo na subárvore da direita<br />
senão <br />
cria novo nodo com algo<br />
conecta o novo nodo no ramo direito<br />
termina algoritmo<br />
fimSe<br />
fimSe <br />
fimPara<br />
fim adiciona<br />
</syntaxhighlight><br />
# Implemente os métodos ''obtemMenor'' e ''obtemMaior''. Eles são bem simples ...<br />
# Implemente o método ''altura'' ... faça-o de forma recursiva, pois a versão não-recursiva não é fácil ! A altura da árvore é uma informação importante relacionada à eficiência na estrutura da árvore (sua topologia), como visto lá [[PRG29003:_Introdução_a_árvores_binárias#Qu.C3.A3o_eficiente_ficou_sua_.C3.A1rvore_.3F|na introdução sobre árvores binárias]]. Pela definição, a altura de uma árvore ''A'' pode ser calculada com esta recorrência:<br />
<br />
<math>h(A)=\begin{cases}<br />
0, \text{if } A_{esq} = NULL \and A_{dir} = NULL \\<br />
1+max(h(A_{esq}), h(A_{dir})), \text{caso contrario} \\<br />
\end{cases}<br />
</math><br />
<br />
= Enumerando os dados de uma árvore =<br />
<br />
* [https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ Stack Frame Layout on X86_64 (para ajudar a entender onde estão as variáveis locais em chamadas recursivas de funções e métodos)]<br />
<br />
<br />
Até o momento nos concentramos em operações básicas de árvores. Elas possibilitam criar e adicionar dados a uma árvore, e pesquisar por um dado em função de um dado específico. Porém outras formas de acessar os dados de uma árvore podem ser úteis, dentre elas o acesso sequencial de acordo com uma determinada ordem. Por exemplo, pode-se desejar acessar os dados de uma árvore de forma ordenada. Assim, devem-se conhecer as quatro ordens de visitação de nodos de uma árvore:<br />
<!--* '''In order:''' visitam-se nodos na sequência esquerda, raiz, direita. O resultado é o acesso ordenado em função das chaves.<br />
* '''Pre order:''' visitam-se nodos na sequência raiz, esquerda, direita. O resultado é uma ordem de acesso que revela a topologia da árvore.<br />
* '''Post order:''' visitam-se nodos na sequência esquerda, direita, raiz. O resultado é uma ordem de acesso das folhas em direção à raiz.<br />
* '''Level order:''' visitam-se nodos cada nível por vez, da esquerda pra direita.<br />
--><br />
<br />
{| border=1<br />
!Tipo<br />
!Descrição<br />
!Exemplo<br />
|-<br />
|'''In order'''||visitam-se nodos na sequência esquerda, raiz, direita. O resultado é o acesso ordenado em função das chaves||[[imagem:Prg2-Inorder.gif]]<br />
|-<br />
|'''Pre order''' ||visitam-se nodos na sequência raiz, esquerda, direita. O resultado é uma ordem de acesso que revela a topologia da árvore||[[imagem:Prg2-Preorder.gif]]<br />
|-<br />
|'''Post order''' ||visitam-se nodos na sequência esquerda, direita, raiz. O resultado é uma ordem de acesso das folhas em direção à raiz||[[imagem:Prg2-Postorder.gif]]<br />
|-<br />
|'''Level order'''|| visitam-se nodos cada nível por vez, da esquerda pra direita||[[imagem:Prg2-Levelorder.gif]]<br />
|}<br />
<br />
As três primeiras formas de acesso são do tipo '''busca em profundidade''', pois implicam descer até as folhas de um lado antes de visitarem o outro lado da árvore. A última forma de acesso é do tipo '''busca em largura''', pois os nodos são visitados por nível da árvore.<br />
<br />
<br />
Cada uma das formas de acesso tem sua aplicações em algoritmos. Por exemplo, ''in order'' serve para ordenar os dados, ''pre order'' pode ser usada para copiar uma árvore, e ''post order'' pode ser usado para destruir uma árvore. Alguns algoritmos já criados usam algumas dessas formas de acesso (ex: ''escrevaSe'' é do tipo ''in order''; o destrutor da árvore e ''altura'' são do tipo ''post order''). Hoje será visto como implementar métodos genéricos que enumeram os dados de uma árvore segundo essas sequências de acesso.<br />
<br />
<syntaxhighlight lang=c><br />
void listeInOrder(lista<T> & result);<br />
void listePreOrder(lista<T> & result);<br />
void listePostOrder(lista<T> & result);<br />
void listeEmLargura(lista<T> & result);<br />
</syntaxhighlight>''Os métodos de enumeração na classe arvore''<br />
<br />
{{collapse top | um algoritmo para listePreOrder em versão não-recursiva}}<br />
A versão não-recursiva de listePreOrder precisa de uma pilha para navegar pelos nodos da árvore.<br />
<br />
<syntaxhighlight lang=text><br />
algoritmo PRE_ORDER:<br />
empilha raiz<br />
<br />
enquanto pilha não vazia faça<br />
desempilha um nodo<br />
faz algo com nodo<br />
<br />
se nodo tem ramo direito então empilha ramo direito<br />
se nodo tem ramo esquerdo então empilha ramo esquerdo<br />
fim enquanto<br />
<br />
fim algoritmo<br />
</syntaxhighlight>''Algoritmo em pseudo-código''<br />
<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> void arvore<T>::listePreOrder(lista<T> & result) {<br />
// OBS: com a lista funcionando como pilha, <br />
// push <==> insere(algo), pop <==> remove(0)<br />
lista<arvore<T>*> q; // pilha de nodos a visitar<br />
<br />
q.insere(this); // inicia com a raiz<br />
while (not q.vazia()) { // repete até que pilha fique vazia<br />
// desempilha um nodo <br />
// anexa em result dado do nodo desempilhado<br />
// se nodo tem ramo direito, empilha-o <br />
// se nodo tem ramo esquerdo, empilha-o<br />
}<br />
}<br />
</syntaxhighlight>''Esqueleto do método listePreOrder em versão não-recursiva''<br />
{{collapse bottom}}<br />
<br />
<br />
As versões não-recursivas desses algoritmos podem ser facilmente encontradas em forums de programadores, e também na [http://www.wikipedia.org/ Wikipedia]:<br />
* [https://en.wikipedia.org/wiki/Tree_traversal#In-order_2 In-order]<br />
* [https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_2 Pre-order]<br />
* [https://en.wikipedia.org/wiki/Tree_traversal#Post-order_2 Post-order]<br />
* [https://en.wikipedia.org/wiki/Tree_traversal#Breadth-first_search_2 Em-largura]<br />
<br />
== Iteração da árvore ==<br />
<br />
A iteraçao da árvore na [[PRG2-2017-2#A_.C3.A1rvore_de_pesquisa_bin.C3.A1ria_da_prglib|Prglib original]] possibilita obter de forma ordenada os dados contidos na árvore. Assim, a iteração segue uma enumeração dos dados no estilo ''in-order''. Para implementá-la deve-se usar um algoritmo não-recursivo, visto que cada chamada do iterador, por meio do método ''proximo'', retorna um único dado. <br />
<br />
<br />
Um algoritmo para enumeração ''in-order'' faz uso de uma pilha como estrutura de dados auxiliar. Sendo assim, a ''classe arvore'' precisa possuir uma pilha como um novo atributo. Para economizar memória, já que todo nodo da árvore possuirá esse novo atributo, a pilha deve ser criada dinamicamente quando se inicia uma iteração, e destruída ao final da iteração. Para isso a pilha deve ser declarada como o ponteiro ''p_stack'' na ''classe arvore'':<br />
<br />
{{collapse top|Declaração da arvore em libs/arvore.h contendo o atributo para a pilha}}<br />
<syntaxhighlight lang=c><br />
#ifndef ARVORE_H<br />
#define ARVORE_H<br />
<br />
namespace prglib {<br />
<br />
template <typename T> class arvore {<br />
public:<br />
arvore();<br />
//arvore(const arvore<T> & outra);<br />
arvore(const T & dado);<br />
virtual ~arvore();<br />
<br />
void adiciona(const T& algo);<br />
T& obtem(const T & algo);<br />
void listeInOrder(lista<T> & result);<br />
void listePreOrder(lista<T> & result);<br />
void listePostOrder(lista<T> & result);<br />
void listeEmLargura(lista<T> & result);<br />
unsigned int tamanho() const; <br />
unsigned int altura() ;<br />
int fatorB() ;<br />
arvore<T> * balanceia();<br />
arvore<T> * balanceia(bool otimo);<br />
<br />
// iterador in-order<br />
void inicia();<br />
bool fim();<br />
T& proximo();<br />
<br />
// iterador in-order reverso<br />
void iniciaPeloFim();<br />
bool inicio();<br />
T& anterior();<br />
<br />
// remove um dado equivalente a "algo", retornando uma cópia<br />
T remove(const T & algo);<br />
<br />
// obtém maior ou menor dados contidos na árvore<br />
T & obtemMenor() const;<br />
T & obtemMaior() const;<br />
<br />
void obtemMenoresQue(lista<T> & result, const T & algo);<br />
void obtemMaioresQue(lista<T> & result, const T & algo);<br />
<br />
// obtém todos valores entre "start" e "end" (inclusive)<br />
void obtemIntervalo(lista<T> & result, const T & start, const T & end);<br />
protected:<br />
T data;<br />
arvore<T> * esq, * dir; <br />
<br />
// um ponteiro para pilha a ser usada pelo iterador.<br />
// OBS: pode-se usar uma lista como se fosse pilha !<br />
lista<arvore<T>*> * p_stack; <br />
<br />
arvore<T> * rotacionaL(); <br />
arvore<T> * rotacionaR(); <br />
};<br />
<br />
} // fim do namespace<br />
<br />
#include <libs/arvore-impl.h><br />
<br />
#endif /* ARVORE_H */<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
<br />
O algoritmo para enumeração ''pre-order'' é mostrado a seguir. Deve-se notar que esse algoritmo enumera todos os dados da árvore. Portanto, ele é uma versão não-recursiva de ''listePreOrder'':<br />
<br />
<syntaxhighlight lang=text><br />
algoritmo pre-order(lista):<br />
cria uma pilha de nodos<br />
<br />
empilha a raiz<br />
<br />
enquanto pilha não vazia faça<br />
desempilha um nodo<br />
anexa à lista dado do nodo<br />
se nodo possui ramo direito então<br />
empilha o nodo direito<br />
se nodo possui ramo esquerdo então<br />
empilha o nodo esquerdo<br />
fim se<br />
fim enquanto<br />
<br />
destroi pilha<br />
<br />
fim pre-order<br />
</syntaxhighlight><br />
<br />
<br />
O algoritmo para enumeração ''in-order'' é mostrado a seguir. Deve-se notar que esse algoritmo enumera todos os dados da árvore. Portanto, ele é uma versão não-recursiva de ''listeInOrder'':<br />
<br />
<syntaxhighlight lang=text><br />
algoritmo in-order(lista):<br />
cria uma pilha de nodos<br />
<br />
empilha a raiz e todos os nodos nos ramos mais à esquerda da raiz,<br />
até o nodo com menor valor<br />
enquanto pilha não vazia faça<br />
desempilha um nodo<br />
anexa à lista dado do nodo<br />
se nodo possui ramo direito então<br />
empilha o nodo direito e todos os nodos nos ramos mais à esquerda dele,<br />
até o nodo com menor valor<br />
fim se<br />
fim enquanto<br />
<br />
destroi pilha<br />
<br />
fim in-order<br />
</syntaxhighlight><br />
<br />
<br />
A iteração da árvore pode aproveitar esse algoritmo com pequenas modificações.<br />
<br />
== Atividade ==<br />
<br />
# Implemente a iteração in-order de sua árvore (métodos ''inicia, proximo, fim'')<br />
# Implemente a iteração in-order reversa de sua árvore (métodos ''iniciaPeloFim, anterior, inicio'')<br />
<br />
= Balanceamento da árvore =<br />
<br />
* [http://en.wikipedia.org/wiki/AVL_tree AVL Tree]<br />
<br />
Nos experimentos feitos até agora, as '''árvores de pesquisa binária''' apresentaram um bom desempenho tanto para serem criadas quanto para pesquisarem valores. Foi estudado que isso se deve a uma importante propriedade da árvore binária, que limita à altura da árvore a quantidade de operações de comparação em uma pesquisa qualquer. Como a altura é função do logaritmo da quantidade de nodos, ela tende a crescer muito lentamente com o aumento da quantidade de nodos da árvore (ex: uma árvore com pouco mais 2.3 milhões de nodos teria altura de pelo menos 21). Porém isso depende de os nodos estarem igualmente distribuídos dos dois lados da árvore. Em outras palavras, '''a árvore deve estar balanceada'''.<br />
<br />
A partir de hoje iremos estudar como balancear uma árvore binária, e para isso usaremos o algoritmo clássico [http://en.wikipedia.org/wiki/AVL_tree AVL]. Mas outras abordagens existem, tais como [https://en.wikipedia.org/wiki/Red%E2%80%93black_tree árvores vermelho-preto]. Uma [https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Applications_and_related_data_structures interessante comparação entre árvores AVL e Vermelho-Preto] pode ser lida na Wikipedia:<br />
<br />
<syntaxhighlight lang=text><br />
Red–black trees offer worst-case guarantees for insertion time, deletion time, and search time. <br />
Not only does this make them valuable in time-sensitive applications such as real-time applications, <br />
but it makes them valuable building blocks in other data structures which provide worst-case <br />
guarantees; for example, many data structures used in computational geometry can be based on <br />
red–black trees, and the Completely Fair Scheduler used in current Linux kernels uses red–black <br />
trees.<br />
<br />
The AVL tree is another structure supporting O(log n) search, insertion, and removal. It is more <br />
rigidly balanced than red–black trees, leading to slower insertion and removal but faster retrieval. <br />
This makes it attractive for data structures that may be built once and loaded without <br />
reconstruction, such as language dictionaries (or program dictionaries, such as the opcodes of an <br />
assembler or interpreter).<br />
</syntaxhighlight><br />
<br />
<br />
== Fator de balanceamento ==<br />
<br />
O fator de balanceamento é a diferença entre as alturas das árvores esquerda e direita, e pode ser calculado assim:<br />
<br />
<br />
<math>F_b = altura(esquerda) -altura(direita)</math><br />
<br />
<br />
Se para todos os nodos da árvore <math>\lVert F_b \rVert <= 1</math>, então a árvore está balanceada e nada precisa ser feito. Porém se para algum nodo <math>\lVert F_b \rVert > 1</math>, então existe um desequilíbrio (má distribuição de nodos), o qual pode ser corrigido. <br />
<br />
<br />
O balanceamento pode ser feito realizando rotações da árvore.<br />
<br />
== Rotações e balanceamento ==<br />
<br />
O balanceamento da árvore implica equilibrar as alturas de cada árvore esquerda e direita dentro de uma árvore. Essa operação pode ser feita tendo como base o que se chama de ''rotações'' da árvore. Duas rotações básicas são possíveis: rotação à direita e à esquerda. Ambas rotações preservam a propriedade de relação de precedência dos dados contidos na árvore: à esquerda da raiz estão os dados menores que o valor da raiz, e à direita estão os maiores. Na figura a seguir, os círculos representam nodos e os triângulos representam subárvores.<br />
<br />
[[imagem:PRG2-Rotacoes.jpg]]<br />
<br />
<br />
Combinando-se essas duas rotações básicas, podem-se realizar quatro tipo de transformações necessárias para o balanceamento de uma árvore AVL:<br />
<br />
[[imagem:LL2.jpg|500px]]<br />
<br>''Caso 1: rotação direita''<br />
<br />
<br />
[[imagem:LR2.jpg|500px]]<br />
<br>''Caso 2: rotação esquerda da árvore esquerda''<br />
<br />
<br />
[[imagem:RR2.jpg|500px]]<br />
<br>''Caso 3: rotação esquerda''<br />
<br />
<br />
[[imagem:RL2.jpg|500px]]<br />
<br>''Caso 4: rotação direita da árvore direita''<br />
<br />
<br />
O balanceamento é feito combinando-se as rotações elementares (direita e esquerda) para aplicá-las a cada caso, o que aqui se chama de ''redução''. A cada ''redução'' reduz-se o módulo do fator de balanceamento em uma unidade. Portanto se esse fator tiver um valor elevado, várias ''reduções'' sucessivas serão necessárias até que ele fique dentro do limite aceitável (i.e. <math>\vert F_b \vert <= 1</math>). As ''reduções'' podem ser feitas à direita ou esquerda:<br />
* '''<math>F_b < -1</math>: redução à direita:''' <br />
*# ''Se caso 4:'' executa-se ''rotacionaR'' na árvore direita<br />
*# executa-se ''rotacionaL''<br />
* '''<math>F_b > 1</math>: redução à esquerda:''' <br />
*# ''Se caso 2:'' executa-se ''rotacionaL'' na árvore esquerda<br />
*# executa-se ''rotacionaR''<br />
<br />
<br />
O algoritmo de balanceamento pode ser modelado da seguinte forma:<br />
<br />
<syntaxhighlight lang=text><br />
algoritmo balanceia(arvore):<br />
entrada: arvore (modificada ao final do algoritmo)<br />
valor de retorno: raiz da árvore após balanceamento<br />
variáveis: Fb (inteiro)<br />
<br />
se arvore esquerda nao nula entao <br />
arvore esquerda <- balanceia(arvore esquerda)<br />
<br />
se arvore direita nao nula entao <br />
arvore direita <- balanceia(arvore direita)<br />
<br />
Fb <- calcula fator de balanceamento da arvore<br />
<br />
enquanto Fb < -1 faça<br />
reduz à direita e calcula novo Fb<br />
fimEnquanto<br />
<br />
enquanto Fb > 1 faça<br />
reduz à esquerda e calcula novo Fb<br />
fimEnquanto<br />
<br />
retorna arvore<br />
</syntaxhighlight><br />
<br />
<br />
Tanto as rotações quanto o balanceamento devem ser implementados como métodos da ''classe arvore''. As rotações pode ser declaradas como métodos protegidos ou privativos, pois devem ser usados somente pelo algoritmo de balanceamento:<br />
<br />
<syntaxhighlight lang=c><br />
template <class T> class arvore {<br />
protected:<br />
// os atributos de uma arvore <br />
public:<br />
// os métodos públicos da Arvore<br />
<br />
// A operação que calcula o fator de balanceamento<br />
int fatorB() const;<br />
<br />
// A operação que balanceia a árvore<br />
// note que ela retorna um ponteiro para a nova raiz ...<br />
arvore<T> * balanceia();<br />
arvore<T> * balanceia(bool otimo);<br />
<br />
// os métodos protegidos da Arvore ... por enquanto são públicos<br />
// Quando estiverem prontos, devem ficar protegidos ou privativos<br />
<br />
// rotação esquerda: retorna a nova raiz da árvore<br />
arvore<T> * rotacionaL();<br />
<br />
// rotação direita: retorna a nova raiz da árvore<br />
arvore<T> * rotacionaR();<br />
};<br />
</syntaxhighlight><br />
<br />
Assim ... implemente o balanceamento da sua árvore ! Dicas:<br />
# Implemente o fator de balanceamento<br />
# Implemente cada uma das rotações, testando-as em árvores pequenas com diferentes topologias.<br />
# Tendo as rotações corretas, implemente o algoritmo de balanceamento. Teste-o com pequenas árvores cujas topologias sejam conhecidas. Verifique a altura e fator de balanceamento dessas árvores antes e após o balanceamento.<br />
<br />
<br />
{{collapse top | Método escrevaSe reescrito para ajudar a visualizar a topologia da árvore}}<br />
Acrescente isto ao arquivo ''arvore.h'', antes da declaração da classe arvore:<br />
<syntaxhighlight lang=c><br />
#include <ostream><br />
<br />
using std::ostream;<br />
</syntaxhighlight><br />
<br />
Acrescente este método à declaração dos métodos públicos da classe arvore em ''arvore.h''<br />
<syntaxhighlight lang=c><br />
void escrevaSe(ostream & out) const;<br />
</syntaxhighlight><br />
<br />
<br />
Acrescente isto a ''arvore-impl.h''<br />
<syntaxhighlight lang=c><br />
#include <string><br />
<br />
using std::string;<br />
<br />
template <typename T> void arvore<T>::escrevaSe(ostream& out) const {<br />
static int nivel = -1;<br />
string prefixo;<br />
<br />
nivel++;<br />
prefixo.append(nivel, ' ');<br />
<br />
if (dir) dir->escrevaSe(out);<br />
out << prefixo << data << std::endl;<br />
if (esq) esq->escrevaSe(out);<br />
nivel--;<br />
}<br />
</syntaxhighlight><br />
<br />
{{collapse bottom}}<br />
{{collapse top | Programa de teste das rotações: testa rotacionaL e rotacionaR}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <string><br />
#include <prglib.h><br />
<br />
using namespace std;<br />
using prglib::arvore;<br />
<br />
int main() {<br />
arvore<int> * arv;<br />
<br />
// uma árvore toda pro lado direito<br />
arv = new arvore<int>(2);<br />
arv->adiciona(3);<br />
arv->adiciona(4);<br />
arv->adiciona(5);<br />
arv->adiciona(6);<br />
<br />
arv->escrevaSe(cout);<br />
cout << endl;<br />
<br />
arv = arv->rotacionaL();<br />
arv->escrevaSe(cout);<br />
cout << endl;<br />
<br />
arv = arv->rotacionaR();<br />
arv->escrevaSe(cout);<br />
cout << endl;<br />
<br />
delete arv;<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
== Atividade ==<br />
<br />
# Implemente o balanceamento AVL de sua árvore, e aplique-o à árvore criada a partir das palavras do [http://tele.sj.ifsc.edu.br/~msobral/prg2/portugues.zip arquivo de portugues]. A altura inicial da árvore é 42, e a altura após o balanceamento pode chegar a 21 (experimente realizar alguns balanceamentos sucessivos, até que a altura não mais reduza).<br />
<br />
= Acesso à estrutura da árvore =<br />
<br />
As operações definidas para árvore podem não ser suficientes para atender todas as necessidades que surjam. Por exemplo, não é possível desenhar a estrutura da árvore com as operações existentes. As três operações a seguir, se acrescentadas à árvore, podem conferir flexibilidade para atender esse tipo de necessidade.<br />
<br />
<syntaxhighlight lang=c><br />
// obtém o valor contido na raiz<br />
const T& obtem() const ;<br />
<br />
// obtém a subárvore esquerda<br />
arvore<T> * esquerda();<br />
<br />
// obtém a subárvore direita<br />
arvore<T> * direita();<br />
</syntaxhighlight><br />
<br />
== Desenhando uma árvore ==<br />
<br />
Tomando como exemplo o desenho da estrutura da árvore, pode-se usar o programa [http://manpages.ubuntu.com/manpages/bionic/man1/dot.1.html dot], que é usado para desenhar [https://pt.wikipedia.org/wiki/Teoria_dos_grafos grafos] (árvore é um [https://pt.wikipedia.org/wiki/%C3%81rvore_(grafo) tipo de grafo]). O programa ''dot'' desenha um grafo a partir de uma especificação no seguinte formato:<br />
<br />
<syntaxhighlight lang=text><br />
graph nome_do_grafo {<br />
nodo1 -- nodo2<br />
nodo1 -- nodo3<br />
... demais conexões entre nodos ...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Por exemplo, observe a especificação para o seguinte desenho de uma árvore:<br />
<br />
{|border=1<br />
!Desenho<br />
!Especificação dot<br />
|-<br />
|[[imagem:prg2-Arv-desenho.png|200px]]|| <syntaxhighlight lang=text><br />
graph arvore {<br />
5 -- 3<br />
3 -- 1<br />
3 -- 4<br />
5 -- 7<br />
7 -- 6<br />
7 -- 9<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
''OBS:'' a ordem em que são listadas as conexões entre nodos não é relevante.<br />
<br />
Usando as operações ''obtem'', ''esquerda'' e ''direita'' da árvore, pode-se gerar uma especificação para o programa ''dot'' desenhá-la.<br />
<br />
<!--<br />
<syntaxhighlight lang=c><br />
template <typename T> void desenha(arvore<T> * arv, ostream & out) {<br />
auto raiz = arv->obtem(); <br />
auto esq = arv->esquerda();<br />
auto dir = arv->direita();<br />
<br />
if (! esq and ! dir) out << raiz << endl;<br />
else {<br />
if (esq) {<br />
out << raiz << " -- " << esq->obtem() << endl;<br />
if (esq->altura()) desenha(esq, out);<br />
}<br />
if (dir) {<br />
out << raiz << " -- " << dir->obtem() << endl;<br />
if (dir->altura()) desenha(dir, out);<br />
}<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
--><br />
<br />
= Remoção de um dado da árvore =<br />
<br />
Em uma aplicação da árvore pode ser necessário remover dados. Uma forma de fazer isso é listar todos os dados da árvore, remover os dados desejados e, em seguida, reconstruir a árvore, porém isso envolve um esforço computacional desnecessário. A solução mais simples é remover somente os dados desejados, fazendo talvez um ajuste pontual na estrutura da árvore. A operação ''remove'' definida abaixo deve implementar tal algoritmo .<br />
<br />
<br />
<syntaxhighlight lang=c><br />
// Este método da classe Arvore remove um nodo que seja igual a "algo"<br />
// Retorna o dado removido.<br />
// Se o dado não for encontrado, dispara uma exceção<br />
T remove(const T & algo);<br />
</syntaxhighlight><br />
''O método para remoção de um nodo da árvore, conforme declarado em arvore.h''<br />
<br />
<br />
A remoção de um dado de uma árvore de pesquisa binária tem o seguinte princípio:<br />
# Localiza-se o nodo que contém o dado a ser removido.<br />
# Substitui-se o valor desse nodo por '''uma''' destas alternativas:<br />
#* O '''maior''' valor existente '''à esquerda''' do nodo a ser removido.<br />
#* O '''menor''' valor existente '''à direita''' do nodo a ser removido.<br />
<br />
<br />
A figura abaixo ilustra a remoção de um dado de uma árvore, destacando as duas possibilidades para a operação:<br />
<br />
<br />
[[imagem:Prg2-arvores-Remocao.png|600px]]<br />
<br />
<br />
No exemplo acima, o menor valor à direita do nodo a ser removido é fácil de ser encontrado: basta seguir os ramos à esquerda da subárvore direita. O maior valor à esquerda também é fácil de ser encontrado: basta seguir os ramos à direita da subárvore esquerda. Mas o caso geral pode ficar mais complicado. Por exemplo, seja a árvore abaixo:<br />
<br />
<br />
[[imagem:Prg2-Remocao2.png|350px]]<br />
<br />
<br />
Nesse exemplo, o menor valor à direita do nodo a ser removido não é uma folha, nem pode ser encontrado simplesmente seguindo-se os ramos esquerdos da árvore direita. O mesmo vale para o maior valor à esquerda.<br />
<br />
<br />
Para funcionar em todos os casos, o algoritmo de remoção de um dado da árvore pode ser resumido por este pseudo-código:<br />
<br />
<syntaxhighlight lang=text><br />
Localize o valor a ser removido<br />
<br />
Se for uma folha, remove o nodo e retorna<br />
<br />
Se fator de balanceamento da árvore enraizada no nodo a ser removido for maior que zero, então <br />
Procura o maior valor da árvore esquerda<br />
Copia esse valor para o nodo que contém o valor a ser removido<br />
Remove esse maior valor da árvore esquerda<br />
Senão<br />
Procura o menor valor da árvore direita<br />
Copia esse valor para o nodo que contém o valor a ser removido<br />
Remove esse menor valor da árvore direita<br />
fimSe<br />
</syntaxhighlight><br />
<br />
<br />
Além do método ''remove'', dois outros métodos precisam ser implementados para obter o maior ou o menor valor de uma árvore:<br />
<br />
<syntaxhighlight lang=c><br />
// Este método da classe Arvore remove um nodo que seja igual a "algo"<br />
// Retorna o dado que foi removido. Se o dado não for encontrado, dispara uma exceção<br />
// A raiz da árvore pode ser modificada no processo ...<br />
T remove(const T & algo);<br />
<br />
// Retorna o menor dado da árvore<br />
T & obtemMenor() const;<br />
<br />
// Retorna o mair dado da árvore<br />
T & obtemMaior() const;<br />
</syntaxhighlight><br />
<br />
{{collapse top | Programa de teste para remoção de valor da árvore}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <string><br />
#include <prglib.h><br />
<br />
using prglib::arvore;<br />
using namespace std;<br />
<br />
int main() {<br />
string dados[7] = {"um", "teste", "pequeno", "muito", "da", "simples", "arvore"}; <br />
<br />
auto arv = new arvore<string>(dados[3]);<br />
<br />
for (int k=1; k < 4; k++) { <br />
arv->adiciona(dados[k+3]);<br />
arv->adiciona(dados[3-k]);<br />
}<br />
<br />
arv->escrevaSe(cout);<br />
<br />
string dado = arv->remove(dados[1]);<br />
cout << "Removeu " << dado << endl;<br />
arv->escrevaSe(cout);<br />
<br />
dado = arv->remove(dados[3]);<br />
cout << "Removeu raiz: " << dado << endl;<br />
arv->escrevaSe(cout);<br />
<br />
delete arv;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
== Atividade ==<br />
<br />
# Implemente o método ''remove'', e teste-o com o programa de teste. Experimente remover:<br />
#* um valor de uma folha<br />
#* um valor que esteja em um nodo intermediário<br />
#* o valor que está na raiz</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Introdu%C3%A7%C3%A3o_C%2B%2B&diff=172246Introdução C++2020-11-20T17:29:42Z<p>Msobral: /* Funções template */</p>
<hr />
<div>__toc__<br />
<br />
= Bibliografia = <br />
<br />
* [http://www.cplusplus.com/doc/tutorial/ Tutorial sobre linguagem C++]<br />
* [http://glu.fcfrp.usp.br/tulio/materiais/c++.pdf Introdução a C++ (USP)]<br />
* [http://www.inf.ufrgs.br/~johann/cpp2004/ Introdução a C++ (UFRGS)]<br />
* [http://orion.lcg.ufrj.br/C++/curso/ Introdução a C++ (UFRJ)]<br />
* [http://www.cplusplus.com/ Cplusplus.com: um sítio com muita informação sobre C++ (incluindo um guia de referência da biblioteca C++ padrão)]<br />
* [http://www.icce.rug.nl/documents/cplusplus/ C++ Annotations (muito bom e aprofundado)]<br />
* [https://isocpp.org/ News, Status & Discussion about Standard C++]<br />
* [https://pihisall.wordpress.com/2007/03/15/aprenda-a-programar-em-dez-anos/ Aprenda a programar em 10 anos !]<br />
* [http://www.johndcook.com/blog/2011/06/14/why-do-c-folks-make-things-so-complicated/ Por que os caras de C++ fazem tudo tão complicado ?]<br />
* [http://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798 Organização de arquivos de código-fonte]<br />
<br />
<!-- Tópicos para tutoriais de C++:<br />
<br />
- cout: http://www.tiexpert.net/programacao/c/cout.php<br />
<br />
- cin: http://www.tiexpert.net/programacao/c/cin.php<br />
<br />
- biblioteca ctype (achei interessante): http://www.tiexpert.net/programacao/c/ctype.php<br />
<br />
- Operador condicional ternário ?: : http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.35 curso basico<br />
<br />
- Valores default para funções: http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.44 curso basico<br />
<br />
- Sobrecarga de operador para classes: http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.30 curso avançado<br />
<br />
- Template: http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf p.52<br />
<br />
- Processamento de arquivos: http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf p.59<br />
http://dcm.ffclrp.usp.br/~augusto/teaching/ici/Arquivos-Texto-CPP.pdf Alguns exemplos, porém um pouco mais complexo.<br />
<br />
- Comparativo entre C e C++: http://www-usr.inf.ufsm.br/~pozzer/disciplinas/cg_5_oo_c++.pdf p.8<br />
<br />
- Exceções try-catch, throw: http://www.inf.pucrs.br/~pinho/PRGSWB/Apoio/Excecoes/Excecoes.html <br />
https://www.youtube.com/watch?v=-g3HR44neDg Vídeo com códigos disponíveis com exemplos simples de exceções e classe de exceção.<br />
Código1: https://gist.github.com/marcoscastro/1ec08c1f944759ef7a1c<br />
Código2: https://gist.github.com/marcoscastro/e8f939b583fdaf84ed52<br />
<br />
- http://www.pontov.com.br/files/cpp/roadmapcpp/ApostilaProgramacaoCppv045.pdf Apostila com diversos conteúdos, muito boa.<br />
p.84: Novidades e vantagens C++ em relação ao C.<br />
p.121: Namespace<br />
p.241: Sobrecarga de Operador<br />
<br />
- Programando em C, C++, 'A Bíblia'. Kris Jams, Lars Klander. <br />
824.Resolvendo o Escopo Global<br />
838.Usando a palavra-chave CONST em C++<br />
839.Usando a palavra-chave ENUM em C++<br />
841.Alocando memória com new<br />
843.Testando a falta de espaço livre<br />
864.Compreendendo a Sobrecarga<br />
865. Sobrecaregando as funções<br />
<br />
- http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-096-introduction-to-c-january-iap-2011/assignments/ Curso aberto com diversas apostilas com exercícios e soluções.<br />
<br />
Bibliografia:<br />
<br />
- http://www.tiexpert.net/programacao/c São bastante instrutivos e didáticos, porém, sem exercícios.<br />
<br />
- http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf Todos os tópicos possuem exemplos e exercícios baseados nos exemplos.<br />
<br />
- http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf Bem didática com exemplos e exercícios.<br />
<br />
- http://www.inf.pucrs.br/~pinho/PRGSWB/Apoio/Excecoes/Excecoes.html<br />
<br />
- http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf <br />
<br />
- http://dcm.ffclrp.usp.br/~augusto/teaching/ici/Arquivos-Texto-CPP.pdf<br />
<br />
- http://www.pontov.com.br/files/cpp/roadmapcpp/ApostilaProgramacaoCppv045.pdf<br />
<br />
- http://www.cplusplus.com/forum/articles/12974/ Lista de exercícios. Está em inglês porém detalha quais requisitos para resolvê-los.<br />
<br />
- https://en.wikibooks.org/wiki/C%2B%2B_Programming/Exercises Wiki em construção, possui alguns exercícios.<br />
<br />
- Programando em C, C++, 'A Bíblia'. Kris Jams, Lars Klander.<br />
<br />
- http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-096-introduction-to-c-january-iap-2011/<br />
--><br />
<br />
= Introdução =<br />
<br />
A linguagem de programação C++ estende a linguagem C, de forma a aderir ao paradigma de orientação a objetos. Com isso, a linguagem oferece construções que possibilitam a expressão de programas modelados segundo uma análise orientada a objetos. A linguagem se apresenta como um superconjunto da linguagem C, o que significa que um programa em C pode ser visto também como um programa C++, mas não o contrário. <br />
<br />
Este primeiro exemplo apresenta o clássico programa de demonstração ''hello world'' escrito em C++:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
cout << "Hello world !" << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
Para compilar este exemplo, deve-se gravá-lo em um arquivo com extensão '''.cc''' ou '''.cpp'''. O compilador C++ disponível no Linux se chama [http://manpages.ubuntu.com/manpages/trusty/man1/gcc.1.html g++], sendo da mesma família de compiladores do [http://manpages.ubuntu.com/manpages/trusty/man1/gcc.1.html gcc]. Supondo que o nome do arquivo seja ''hello.cc'', pode-se compilá-lo assim:<br />
<br />
<syntaxhighlight lang=bash><br />
g++ -o hello hello.cc<br />
</syntaxhighlight><br />
<br />
O comando acima deve gerar um arquivo executável chamado ''hello''. Para executá-lo, faça o seguinte:<br />
<br />
<syntaxhighlight lang=bash><br />
./hello<br />
</syntaxhighlight><br />
<br />
O exemplo acima pode ser estendido para mostrar como ler dados do teclado:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <stdio.h><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int x;<br />
<br />
cout << "Hello world !" << endl;<br />
cout << "x: ";<br />
cin >> x;<br />
cout << "Voce digitou " << x << endl; <br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
== Organização de código-fonte ==<br />
<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/source_code_organization.pdf Capítulo 15 do livro ''C: A Modern Approach, 2n ed., de K. N. King'']<br />
<br />
<br />
Programas em linguagens C e C++ são usualmente organizados em um conjunto de arquivos de código-fonte de dois tipos:<br />
* '''Arquivos de cabeçalho (extensão .h):''' nesse tipo de arquivo se escrevem declarações necessárias em outros arquivos de código-fonte. Essas declarações incluem tipos de dados, [https://en.wikipedia.org/wiki/Function_prototype protótipos de funções], [[Introdução_C%2B%2B#Declara.C3.A7.C3.A3o_de_classes|classes]] e [[Introdução_C%2B%2B#Templates|templates]], variáveis globais e [http://www.cplusplus.com/doc/tutorial/preprocessor/ macros]. Com exceção de templates e macros, nesses arquivos não se escrevem implementações (corpos de funções e métodos).<br />
* '''Arquivos de implementação (extensão .cpp, .cc ou .c):''' nesses arquivos se escrevem as implementações de funções e métodos de classes. Arquivos de cabeçalhos podem ser incluídos com a diretiva [http://www.cplusplus.com/doc/tutorial/preprocessor/#include #include] para obter declarações necessárias à implementação.<br />
<br />
== Argumentos de linha de comando ==<br />
<br />
* [[Argparse|Argparse: um exemplo de uma biblioteca para facilitar o processamento de argumentos de linha de comando]]<br />
<br />
<br />
Argumentos de linha de comando são dados passados a um programa no momento de sua execução. Na época em que a linguagem C foi inventada, e quando então os sistemas Unix se popularizaram, a interface com usuários era em modo texto. Usuários interagiam com o sistema operacional por meio de um programa chamado de '''interpretador de comandos''', ou simplesmente [https://en.wikipedia.org/wiki/Shell_(computing) shell]. Para um usuário executar um programa, ele deveria digitar o nome desse programa no prompt do ''shell'' e pressionar a tecla ENTER (ou RETURN). Cabia então ao ''shell'' ordenar ao sistema operacional que o arquivo de programa solicitado fosse executado. Além do nome do programa, um usuário poderia opcionalmente especificar um ou mais argumentos, que são strings a serem passadas ao programa no momento de sua execução. Os dois exemplos a seguir mostram a execução do programa [http://manpages.ubuntu.com/manpages/bionic/man1/ls.1.html ls] por meio de um ''shell''.<br />
<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@M1:$ ls<br />
Área de trabalho Downloads Modelos Público Vídeos<br />
Documentos Imagens Música teste.sh<br />
aluno@M1:$<br />
</syntaxhighlight><br />
Execução do programa ''ls'' sem argumentos de linha de comando. O prompt do shell é a string ''aluno@M1:$''.<br />
<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@M1:$ ls -l<br />
total 48<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Área de trabalho<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Documentos<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Downloads<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Imagens<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Modelos<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Música<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Público<br />
-rw-r--r-- 1 aluno aluno 14076 abr 12 2018 teste.sh<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Vídeos<br />
aluno@M1:$<br />
</syntaxhighlight><br />
Execução do programa ''ls'' com um argumento de linha de comando (a string ''-l''). Cabe ao programa ''ls'' interpretar esse argumento, e usá-lo para desempenhar sua funcionalidade.<br />
<br />
<br />
Do ponto de vista do programador, os argumentos de linha de comando são acessíveis por meio de dois parâmetros da função ''main'', os quais são tradicionalmente denominados:<br />
* '''argc''': um número inteiro que informa quantos argumentos de linha de comando foram passados ao programa. Esse parâmetro tem no mínimo o valor 1 (um), pois o próprio nome do programa é considerado seu primeiro argumento.<br />
* '''argv''': um vetor de strings que contém os argumentos. A primeira string desse vetor é sempre o próprio nome do programa. A posição no vetor em seguida ao último argumento contém o ponteiro NULL.<br />
<br />
<br />
O programa C a seguir mostra como esses parâmetros são especificados na função ''main'', e como podem ser usados. Neste exemplo, apresentam-se na tela todos os argumentos de linha de comando (um por linha), na ordem em que foram passados ao programa.<br />
<br />
<syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main(int argc, char * argv[]) {<br />
int n;<br />
<br />
for (n=0; n < argc; n++) {<br />
printf("argv[%d]=%s\n", n, argv[n]);<br />
}<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
A versão em C++ desse exemplo é praticamente idêntica, mudando somente a forma com que os dados são mostrados na tela.<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(int argc, char * argv[]) {<br />
int n;<br />
<br />
for (n=0; n < argc; n++) {<br />
cout << "argv[" << n << "]=" << argv[n] << endl;<br />
}<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Apesar de hoje em dia as interfaces de usuário em modo texto serem menos usadas, o modelo de execução de programas continua o mesmo. Mesmo programas gráficos se valem de argumentos de linha de comando para modularem a forma com que devem funcionar (ver, por exemplo, o [http://manpages.ubuntu.com/manpages/bionic/man1/firefox.1.html manual do firefox]). Independente do tipo de interface de usuário, argumentos de linha de comando são de grande utilidade para passar informação a programas quando forem executados.<br />
<br />
= Classes e objetos =<br />
<br />
A linguagem C foi projetada segundo um paradigma de programação chamado de [https://en.wikipedia.org/wiki/Structured_programming programação estruturada]. Essa forma de expressar programas se baseia em subrotinas (funções no caso da linguagem C), blocos de instruções e laços de repetição, os quais atuam sobre variáveis que contêm os dados a serem acessados e transformados. O que se deve notar é a forma com que se costuma modelar um programa nesse caso, dando-se ênfase aos algoritmos que modificam os dados. Não é à toa que uma ferramenta de modelagem tradicional e ainda muito usada seja o fluxograma. Porém existem outras formas de pensar os problemas a serem resolvidos e expressar programas, dentre elas o [https://en.wikipedia.org/wiki/Object-oriented_programming paradigma de orientação a objetos] seguido por diversas linguagens tais como C++, Java e Python.<br />
<br />
<br />
Um programa orientado a objetos é composto por objetos que interagem. Um objeto é uma abstração que representa uma ''coisa'' que faz parte do problema a ser resolvido. Um objeto contém dados que representam seu estado (chamados de ''atributos''), e procedimentos que representam seu comportamento (chamados de ''métodos''). No caso do exemplo dos horários, um horário pode ser representado por um objeto. O estado desse objeto ''Horario'' é definido pelos valores de ''hora'', ''minuto'' e ''segundo'', e seu comportamento é dado pelos métodos ''mostreSe'' e ''acrescenta''. Isso deve ser entendido da seguinte forma: um ''objeto 'Horario'' pode ser mostrado, ao se chamar seu método 'mostreSe'', e pode ser somado a outro objeto ''Horario'', ao se chamar seu método ''acrescenta''. Essas são as únicas operações definidas para esse objeto, e assim nada mais se consegue fazer com ele ... a não ser que se definam novas operações.<br />
<br />
<br />
Muitos objetos similares podem existir. Por exemplo, pode haver muitos diferentes objetos ''Horario'', que se diferenciam por seus estados (valores de ''hora'', ''minuto'' e ''segundo''). Todos os objetos cujos estados são definidos pelo mesmo conjunto de atributos, e que possuem o mesmo comportamento (conjunto de métodos), pertencem à mesma '''classe'''. O conceito de classe é semelhante ao de ''tipo de dados'', porém tem uma implicação mais profunda. Um ''tipo de dados'' define como o conteúdo de uma variável deve ser interpretado (ex: um número inteiro, ponto flutuante, uma string, ...), porém não define os procedimentos que podem manipular essas variáveis. Desta forma, uma ''classe'' vincula a seus objetos os algoritmos que atuam sobre eles. Isso tem uma importante implicação no [http://effectivesoftwaredesign.com/2012/02/05/separation-of-concerns/ acoplamento e coesão de um programa], que são métricas fundamentais de qualidade de um projeto de software modular.<br />
<br />
<br />
<br />
== Declaração de classes ==<br />
<br />
Uma classe é declarada usando-se a palavra-chave ''class'' seguida do nome da classe:<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
// declarações internas da classe<br />
};<br />
</syntaxhighlight><br />
<br />
De certa forma, isso se assemelha à declaração de ''struct''. No entanto, as declarações internas da classe têm um significado um pouco diferente. Por exemplo, suponha-se que a classe ''MinhaClasse'' represente um número de telefone, incluindo seu código de área. A declaração seria estendida desta forma:<br />
<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// declarações dos procedimentos da classe<br />
};<br />
</syntaxhighlight><br />
<br />
A classe agora possui dois atributos:<br />
* ''string numero'': armazena o número de telefone<br />
* ''string ddd'': armazena o código DDD<br />
<br />
No exemplo, as declarações desses atributos na classe são precedidas pela cláusula ''private:''. Isso significa que esses atributos não podem ser acessados diretamente de fora da classe (por procedimentos implementados fora da classe). Logo após a declaração desses atributos, aparece a cláusula ''public:''. Ela define que o que for declarado em seguida pode ser acessado diretamente de fora da classe. Por exemplo, os métodos da classe podem ser declarados logo após ''public:''.<br />
<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// Construtor: executado quando se cria um objeto desta classe<br />
MinhaClasse(string umNumero, string umDDD);<br />
<br />
// Destrutor: executado quando se destrói um objeto desta classe<br />
~MinhaClasse();<br />
<br />
// métodos para acessar os valores dos atributos<br />
string obtemNumero();<br />
string obtemDDD();<br />
string obtemNumeroDDD();<br />
};<br />
</syntaxhighlight><br />
<br />
Um ''método'' é uma função que pertence a uma classe. A idéia é que um objeto de uma classe possui um estado dado pelos valores de seus atributos, e somente os métodos daquela classe podem acessar ou modificar esse estado. Quer dizer, somente métodos da classe podem acessar diretamente esses atributos. Dois métodos são especiais:<br />
*''construtor'': este método é executado sempre que se cria um objeto de uma classe. Ele tem por finalidade iniciar o estado daquele objeto. Isso envolve definir os valores iniciais dos atributos, e conferir se os parâmetros que porventura tenham sido passados são válidos (ex: se o número tem somente caracteres numéricos).<br />
* ''destrutor'': este método é executado quando um objeto é destruído. Ele é responsável por limpar o estado desse objeto, desfazendo qualquer ação que ele tenha iniciado. Por exemplo, se o objeto alocou memória dinamicamente em algum momento, o destrutor deve liberá-la.<br />
<br />
<br />
A declaração da classe apresentada apenas informa quais métodos ela implementa, mas não mostra como eles são implementados. Essa implementação pode ser feita de duas formas:<br />
* ''inline'': a implementação de um método é feita dentro da própria declaração da classe. Por exemplo, o método ''obtemNumeroDDD'' poderia estar implementado assim: <syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// Construtor: executado quando se cria um objeto desta classe<br />
MinhaClasse(string umNumero, string umDDD);<br />
<br />
// Destrutor: executado quando se destrói um objeto desta classe<br />
~MinhaClasse();<br />
<br />
// métodos para acessar os valores dos atributos<br />
string obtemNumero();<br />
string obtemDDD();<br />
<br />
// implementação inline<br />
string obtemNumeroDDD() {<br />
string num = ddd + '-' + numero;<br />
return num;<br />
}<br />
};<br />
</syntaxhighlight><br />
* ''fora da classe'': a implementação é feita externamente, possivelmente em outro arquivo. Deve-se declarar a classe a que pertence o método, prefixando seu nome com ''Nome_da_classe::''. No caso de ''obtemNumeroDDD'', isso poderia ser feito assim:<syntaxhighlight lang=c><br />
// deve-se prefixar o nome do método com o nome da classe, para indicar que é um método dessa classe<br />
string MinhaClasse::obtemNumeroDDD() {<br />
string num = ddd + '-' + numero;<br />
return num;<br />
}<br />
</syntaxhighlight><br />
<br />
== Criação de objetos ==<br />
<br />
Uma vez tendo declarado e implementado uma classe, podem-se criar objetos. A isso se chama ''instanciação'', e os objetos também podem ser chamados de ''instâncias''. Objetos podem ser criados diretamente, como se fossem variáveis usuais, como mostrado a seguir:<br />
<br />
<syntaxhighlight lang=c n><br />
#include "minhaclasse.h"<br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string num, ddd;<br />
<br />
cout << "Numero: ";<br />
cin >> num;<br />
cout << "DDD: ";<br />
cin >> ddd;<br />
<br />
// o construtor da classe é chamado quando se cria um objeto<br />
// Aqui, o objeto é dado pela variável "fone"<br />
MinhaClasse fone(num, ddd);<br />
<br />
cout << "Numero com DDD é " << fone.obtemNumeroDDD() << endl;<br />
<br />
// objetos são destruídos automaticamente ao final do escopo em que foram criados<br />
// o destrutor é então executado <br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Objetos podem também ser criados dinamicamente, em que a memória necessária é alocada. Para isso usa-se o operador [http://www.cplusplus.com/reference/new/operator%20new/ new] (e não a função ''malloc'' !). Objetos criados dessa forma são referenciados por ponteiros, e devem ser explicitamente destruídos usando-se o operador [http://www.cplusplus.com/reference/new/operator%20delete/ delete] (e não a função ''free'' !). O exemplo a seguir mostra a criação e destruição de objetos com ''new'' e ''delete'':<br />
<br />
<syntaxhighlight lang=c n><br />
#include "minhaclasse.h"<br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string num, ddd;<br />
// o ponteiro fone é capaz de apontar objetos de MinhaClasse<br />
MinhaClasse * fone;<br />
<br />
cout << "Numero: ";<br />
cin >> num;<br />
cout << "DDD: ";<br />
cin >> ddd;<br />
<br />
// o construtor da classe é chamado quando se cria um objeto com o operador "new"<br />
// Aqui, o objeto é dado pelo ponteiro "fone"<br />
fone = new MinhaClasse(num, ddd);<br />
<br />
cout << "Numero com DDD é " << fone->obtemNumeroDDD() << endl;<br />
<br />
// objetos dinâmico devem ser destruídos explicitamente usando o operador "delete"<br />
// o destrutor é então executado <br />
delete fone;<br />
}<br />
</syntaxhighlight><br />
<br />
=== Invocação do construtor ===<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/classes#member_initialization Inicialização dos atributos de um objeto]<br />
<br />
A criação de um objeto causa a execução do método ''construtor'' da classe. Esse método é responsável por iniciar os valores dos atributos do objeto (chamados de ''variáveis de instância''), tornando-o pronto para ser utilizado. O ''construtor'' recebe os parâmetros passados na criação do objeto (ver linhas 16 do primeiro exemplo e 18 do segundo). No exemplo em questão, o método construtor poderia fazer algo assim:<br />
<br />
<syntaxhighlight lang=c><br />
MinhaClasse::MinhaClasse(string umNumero, string umDDD) {<br />
numero = umNumero;<br />
ddd = umDDD;<br />
}<br />
</syntaxhighlight><br />
<br />
... quer dizer, apenas copiar os valores dos parâmetros para os respectivos atributos. Outra forma de implementar o construtor e iniciar os valores dos atributos é esta:<br />
<br />
<syntaxhighlight lang=c><br />
MinhaClasse::MinhaClasse(string umNumero, string umDDD) : numero(umNumero), ddd(umDDD) {<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Deve-se observar que os atributos são iniciados usando uma sintaxe especial. Logo após o nome do método construtor declara-se uma lista de inicialização de atributos. Essa lista é iniciada com ''':''', seguida dos nomes dos atributos invocados como se fosse outros objetos sendo criados. Na verdade é exatamente isso que acontece nessa forma de iniciar os atributos: eles são criados como objetos que fazem parte do objeto criado. Essa forma de iniciar atributos é imprescindível quando uma classe possui um ou mais atributos que são de fato objetos de alguma classe, e que precisam receber parâmetros ao serem criados.<br />
<br />
== Destruição de objetos ==<br />
<br />
A destruição de um objeto ocorre em duas situações:<br />
# '''Quando se chega ao fim o escopo dentro do qual o objeto foi criado:''' isso vale para objetos declarados e instanciados diretamente. Ex: <syntaxhighlight lang=c><br />
void ecoa() {<br />
string palavra; // aqui se cria um objeto string<br />
<br />
cout << "Digite uma palavra: ";<br />
cin >> palavra;<br />
cout << "Você digitou: " << palavra << endl;<br />
} // fim do escopo ... o objeto string "palavra" é destruido automaticamente<br />
</syntaxhighlight><br />
# '''Quando se destroi o objeto com o operador [http://www.cplusplus.com/reference/new/operator%20delete/ delete]:''' isso vale somente para objetos criados dinamicamente com o operador [http://www.cplusplus.com/reference/new/operator%20new/ new]. Ex: <syntaxhighlight lang=c><br />
void ecoa() {<br />
string * palavra; // aqui se declara um ponteiro para string<br />
<br />
palavra = new string; // aqui se cria dinamicamente um objeto string<br />
cout << "Digite uma palavra: ";<br />
cin >> *palavra;<br />
cout << "Você digitou: " << *palavra << endl;<br />
<br />
delete palavra; // aqui se destroi o objeto string<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
A destruição de um objeto implica liberar as áreas de memória a ele alocadas dinamicamente em sua criação, ou durante seu tempo de vida. Essa faxina deve ser feita pelo método destrutor da classe (chamado simplesmente de [http://www.cplusplus.com/doc/tutorial/classes2/#destructor ''destructor'']). Tal método é declarado da seguinte forma em uma classe:<br />
<br />
<syntaxhighlight lang=c><br />
classe Demo {<br />
public:<br />
Demo(); // constructor da classe<br />
~Demo(); // destructor da classe<br />
<br />
// demais métodos da classe<br />
};<br />
<br />
// implementação do destructor<br />
Demo::~Demo() { <br />
// limpeza do objeto<br />
}<br />
</syntaxhighlight><br />
<br />
A implementação desse método deve ser responsável pela limpeza do objeto. Apenas áreas de memória alocadas dinamicamente precisam ser liberadas. O exemplo a seguir mostra uma classe com memória alocada dinamicamente:<br />
<br />
<syntaxhighlight lang=c><br />
classe Demo {<br />
public:<br />
Demo(const string & name); // constructor da classe<br />
~Demo(); // destructor da classe<br />
<br />
// demais métodos da classe<br />
private:<br />
// atributos privativos da classe<br />
string nome;<br />
char * buffer;<br />
};<br />
<br />
// implementação do constructor<br />
Demo::Demo(const string & name) { <br />
nome = name;<br />
buffer = new char[1024]; // aloca dinamicamente 1kB<br />
}<br />
<br />
// implementação do destructor<br />
Demo::~Demo() { <br />
// libera a área de memória alocada no constructor<br />
delete buffer;<br />
}<br />
</syntaxhighlight><br />
<br />
== Um exemplo ==<br />
<br />
O exemplo abaixo pode esclarecer melhor os conceitos de classe e objeto. Ele declara uma classe ''Vetor'', que representa vetores bidimensionais. As operações sobre tais objetos são: módulo, produto escalar, subtração e escrita em um arquivo. Veja como pode ser escrita essa classe.<br />
<br />
<syntaxhighlight lang=c><br />
// a classe Vetor define objetos que representam vetores bidimensionais<br />
class Vetor {<br />
private: // as declarações abaixo são privativas (podem ser acessadas somente dentro da classe)<br />
<br />
double x, y;<br />
<br />
public: // as declarações abaixo são públicas, podendo ser acessadas de fora da classe<br />
<br />
// construtor da classe: um método especial que cria objetos desta classe<br />
Vetor(double px, double py) {<br />
// inicia o estado de um objeto<br />
x = px;<br />
y = py;<br />
}<br />
<br />
// destrutor da classe: um método especial que destrói objetos desta classe<br />
~Vetor() {} // nada demais precisa ser feito<br />
<br />
// este método retorna o módulo do vetor<br />
double modulo() {<br />
return sqrt(x*x + y*y);<br />
}<br />
<br />
// este método retorna o produto escalar deste vetor com outro vetor<br />
double produto_escalar(const Vetor & outro) {<br />
return x*outro.x + y*outro.y;<br />
}<br />
<br />
// este método calcula a soma entre este e outro vetor (este + outro),<br />
// retornando um novo vetor como resultado<br />
Vetor adicione(const Vetor & outro) {<br />
Vetor novo(x+outro.x, y+outro.y);<br />
<br />
return novo;<br />
}<br />
<br />
// este método calcula a diferença entre este e outro vetor (este - outro),<br />
// retornando um novo vetor como resultado<br />
Vetor subtraia(const Vetor & outro) {<br />
Vetor novo(x-outro.x, y-outro.y);<br />
<br />
return novo;<br />
}<br />
<br />
// este método escreve uma representação do objeto no arquivo "out"<br />
// (que é um objeto da classe ostream)<br />
void mostreSe(ostream & out) {<br />
out << "(";<br />
out << x;<br />
out << ", ";<br />
out << y;<br />
out << ")";<br />
}<br />
<br />
};<br />
</syntaxhighlight><br />
<br />
Uma vez existindo a classe ''Vetor'', pode-se escrever um programa que use objetos dessa classe. No exemplo abaixo, calcula-se o vetor resultante de dois outros vetores:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
int x, y;<br />
<br />
cout << "Coordenada X do vetor 1: ";<br />
cin >> x;<br />
cout << "Coordenada Y do vetor 1: ";<br />
cin >> y;<br />
cout << endl;<br />
<br />
// Aqui se cria o primeiro objeto Vetor<br />
Vetor v1(x, y);<br />
<br />
cout << "Coordenada X do vetor 2: ";<br />
// Aqui se lê pela entrada padrão a coordenada X<br />
cin >> x;<br />
cout << "Coordenada Y do vetor 2: ";<br />
// Aqui se lê pela entrada padrão a coordenada Y<br />
cin >> y;<br />
cout << endl;<br />
<br />
// Aqui se cria o segundo objeto Vetor<br />
Vetor v2(x, y);<br />
<br />
// Aqui se obtém a resultante dos vetores v1 e v2. Note como a operação "adicione"<br />
// do objeto "v1" é chamada.<br />
Vetor v3 = v1.adicione(v2);<br />
<br />
cout << "Vetor resultante: ";<br />
// Aqui se escreve uma representação de "v3" na tela. "cout" é um objeto da biblioteca C++ padrão<br />
// que representa a saída padrão de um processo. A saída padrão funciona como um arquivo. O objeto <br />
// "cout" é similar ao "stdout" da linguagem C.<br />
v3.mostreSe(cout);<br />
cout << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
O programa em si se apresenta como um pequeno algoritmo que lê pela entrada padrão valores de coordenadas e cria os respectivos vetores (''v1'' e ''v2''), calculando sua resultante a apresentando na saída padrão o novo vetor (''v3''). <br />
<br />
<br />
Além das regras de escrita da linguagem, o que se denomina ''sintaxe'', ressalta-se o uso dos objetos feito no programa. O pequeno programa criado trata de calcular a resultante de dois vetores bidimensionais. As ''coisas'' a serem diretamente manipuladas pelo programa são os vetores, sendo estes representado por objetos. Outros objetos usados são os arquivos que representam a entrada e saída padrão do programa (respectivamente ''cin'' e ''cout''). O programa '''usa''' os objetos da classe ''Vetor'', explorando as operações que eles oferecem. Assim, a declaração da classe ''Vetor'' se preocupa em definir o que é um objeto Vetor (seus atributos) e o que ele é capaz de fazer (seu comportamento). Já o programa apenas utiliza esses objetos.<br />
<br />
== O ponteiro predefinido ''this'' ==<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/templates/ Ver seção ''the keyword this'' neste documento]<br />
<br />
<br />
Ao se implementarem métodos de uma classe pode-se usar uma variável predefinida chamada ''this'', que é um ponteiro para o objeto no escopo do qual se executa um método. Sempre que dentro de um método for necessário eliminar uma ambiguidade quanto ao uso de um atributo do objeto, ou por clareza, pode-se usar esse ponteiro ''this''. O exemplo a seguir ilustra o uso de ''this''.<br />
<br />
<syntaxhighlight lang=c><br />
class Coisa {<br />
public:<br />
Coisa(int x, int y);<br />
~Coisa() {}<br />
// outros métodos da classe ...<br />
private:<br />
// os atributos dos objetos desta classe<br />
int x,y;<br />
};<br />
<br />
// construtor da classe Coisa: os parâmetros "x" e "y" são usados para iniciar os <br />
// atributos "x" e "y". Para resolver a ambiguidade entre parâmetros e atributos, dentro do construtor<br />
// se usa o ponteiro "this"<br />
Coisa::Coisa(int x, int y) {<br />
this->x = x;<br />
this->y = y;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Existem outros casos em que o ponteiro ''this'' tem utilidade. Um exemplo pode ser visto na [[Introdu%C3%A7%C3%A3o_C%2B%2B#Construtor_de_c.C3.B3pia|seção sobre construtor de cópia]].<br />
<br />
== Operador de atribuição ==<br />
<br />
Em C++ pode-se definir como um operador específico atua sobre um objeto. Operadores típicos são: ''='' (atribuição), ''+'' (adição), ''-'' (subtração), e [http://www.cplusplus.com/doc/tutorial/operators/ outros]. Um operador é definido por uma função ou método que implementa sua operação. No caso da Fila, um operador útil é o de atribuição, pois pode ser usado para que uma fila existente seja modificada para se tornar idêntica a outra fila. Supondo que esse operador tenha sido implementado, o exemplo a seguir mostra a fila ''f1'' sendo atribuída a ''f2'' (linha 19), a qual já existe e tem inclusive dados armazenados, e demonstra em seguida como ficou o conteúdo de ''f2''.<br />
<br />
<br />
<syntaxhighlight lang=c n><br />
#include <iostream><br />
#include "fila.h"<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
Fila f1(5);<br />
Fila f2(7);<br />
<br />
f1.enfileira(2);<br />
f1.enfileira(7);<br />
f1.enfileira(4);<br />
<br />
f2.enfileira(3);<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
f2 = f1; // atribui f1 a f2 ... f2 torna-se uma cópia de f1<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
while (not f1.vazia()) cout << "Desenfileirou de f1: " << f1.desenfileira() << endl;<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
while (not f2.vazia()) cout << "Desenfileirou de f2: " << f2.desenfileira() << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O operador de atribuição da fila pode ser declarado como mostrado abaixo:<br />
<br />
<syntaxhighlight lang=c><br />
class Fila {<br />
public:<br />
Fila(int umaCapacidade); // cria uma fila capaz de guardar "capacidade" elementos<br />
Fila(const Fila & outra);<br />
~Fila(); // destroi a fila<br />
Fila& operator=( const Fila& outra ); // OPERADOR DE ATRIBUIÇÃO<br />
// demais declarações da Fila ...<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Como se pode notar, sua declaração é muito parecida com a de um método qualquer da classe. A palavra-chave ''operator'' indica tratar-se de um método de operador, e o símbolo que aparece logo em seguida indica o operador a ser redefinido (no caso, ''=''). O único parâmetro a ser passado é o objeto a ser copiado (no caso, uma Fila). O valor retornado é uma referência ao próprio objeto que foi o destino da atribuição (aquele que foi modificado). A implementação desse método segue as regras usadas nos demais métodos:<br />
<br />
<syntaxhighlight lang=c><br />
Fila& Fila::operator=( const Fila& outra ) {<br />
// desalocar a memória de "buffer"<br />
// copiar os valores de atributos de "outra"<br />
// alocar memória para "buffer"<br />
// copiar conteúdo da "buffer" da "outra" fila<br />
<br />
// retorna uma referência ao próprio objeto <br />
return *this;<br />
}<br />
</syntaxhighlight><br />
''A implementação do método do operador de atribuição em fila.cpp''<br />
<br />
== Construtor de cópia ==<br />
<br />
Um [http://www.cplusplus.com/articles/y8hv0pDG/ construtor de cópia] é um método construtor para criar um objeto que é uma cópia idêntica a um objeto existente. Esse tipo de criação de objeto aparece em casos como este:<br />
<br />
<syntaxhighlight lang=c><br />
Fila<int> f1(10); // cria uma fila capaz de guardar 10 números inteiros<br />
<br />
f1.enfileira(5);<br />
f1.enfileira(8);<br />
f1.enfileira(2);<br />
f1.enfileira(4);<br />
<br />
Fila<int> f2 = f1; // cria a fila f2, que é uma cópia idêntica de f1<br />
<br />
f1.esvazia(); // esvazia a fila f1<br />
<br />
// Mostra o conteúdo da fila f2: deve ser igual ao que existia em f1<br />
while (not f2.vazia()) {<br />
cout << f2.desenfileira() << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
Para que o exemplo acima funcione, a classe Fila deve implementar seu construtor de cópia:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
public:<br />
// construtor de cópia: o objeto criado deve ser idêntico ao objeto "outra"<br />
Fila(const Fila<T> & outra);<br />
<br />
// demais declarações da Fila ...<br />
};<br />
</syntaxhighlight><br />
<br />
O construtor de cópia deve ser responsável por copiar o estado do ''objeto copiado'', de forma que o objeto criado seja idêntico a ele. Isso envolve copiar os valores dos atributos desses objetos, porém em certos casos isso não é suficiente. Se o objeto copiado tiver como atributos outros objetos ou variáveis criados dinamicamente, então o novo objeto deve também criar dinamicamente cópias desses objetos ou variáveis. <br />
<br />
<br />
Deve-se observar que um construtor de cópia é muito parecido com um operador de atribuição. A diferença reside no fato de que uma atribuição ocorre entre dois objetos já existentes. Por isso um objeto que recebe uma atribuição deve primeiro limpar seu estado (se necessário, o que envolve destruir eventuais objetos e variáveis dinâmicos) para depois se tornar uma cópia do outro objeto. Apesar disso, se um operador de atribuição já existir ele pode ser usado para facilmente implementar um construtor de cópia. O exemplo a seguir mostra como isso pode ser feito para a Fila:<br />
<br />
<syntaxhighlight lang=c><br />
// implementação do construtor de cópia<br />
template <typename T> Fila<T>::Fila(const Fila<T> & outra) {<br />
// primeiro devem-se atribuir valores aos atributos desta Fila <br />
// para que ela pareça vazia<br />
<br />
// em seguida, basta atribuir a "outra" Fila a este objeto<br />
// Note o uso do ponteiro predefinido "this", que sempre aponta o objeto que recebe a operação<br />
// dentro de um método de sua classe<br />
*this = outra;<br />
}<br />
</syntaxhighlight><br />
<br />
== Templates ==<br />
<br />
* [http://www.cprogramming.com/tutorial/templates.html Template classes C++]<br />
* [http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part An Idiot's Guide to C++ Templates]<br />
* [http://br.ccm.net/faq/10140-os-templates-em-c Os templates em C++]<br />
<br />
<br />
''Templates'' possibilitam a parametrização de tipos em C++. Com isso, podem-se escrever funções, structs e classes que referenciam ou armazenam dados cujos tipos sejam desconhecidos de antemão. Esses tipos são denominados ''tipos genéricos''. No nosso caso, isso será usado para generalizar as estruturas de dados a serem criadas, para que elas possam armazenar qualquer tipo de dado. Na explicação a seguir, usa-se a estrutura de dados ''Fila'' como exemplo.<br />
<br />
<br />
A declaração de uma classe template inicia com o prefixo ''template <typename T>''. A cláusula ''<typename T>'' serve para especificar um identificador para o tipo genérico a ser usado dentro da classe (no exemplo, escolheu-se o identificador ''T'', mas pode ser qualquer outra coisa). No caso da ''Fila'', deseja-se torná-la capaz de guardar qualquer tipo de dado. Quer dizer, seu funcionamento não depende do que ela estiver armazenando, portanto o tipo do dado armazenado pode ser generalizado. Esse é um bom exemplo de uso de classe template, estando exemplificado a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
<br />
// declarações de atributos e métodos da classe<br />
<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Todas as referências ao tipo genérico devem ser escritas usando o identificador especificado (no caso, ''T''). Aproveitando o exemplo da ''Fila'', deve-se observar que o atributo ''buffer'' depende do tipo genérico, pois trata-se de um vetor onde devem ser armazenados os dados enfileirados. Os métodos ''enfileira'', ''desenfileira'' e ''frente'' também dependem do tipo genérico. A declaração da classe template ''Fila'' segue abaixo, porém com alguns detalhes omitidos para ficar mais evidente o uso de template.<br />
<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
public:<br />
Fila(unsigned int N);<br />
~Fila();<br />
<br />
// enfileira um dado do tipo T<br />
void enfileira(const T & algo);<br />
<br />
// desenfileira um dado da frente da fila, e retorna uma <br />
// cópia desse dado (cujo tipo é T)<br />
T desenfileira();<br />
<br />
// Retorna uma referência ao dado de tipo T que está na frente da fila<br />
T & frente() const;<br />
<br />
bool vazia() const {return itens == 0; }<br />
bool cheia() const { return itens == capacidade;}<br />
unsigned int tamanho() const { return itens;}<br />
private:<br />
int capacidade;<br />
int itens, inicio, fim;<br />
T* buffer; // área de memória para guardar os dados de tipo T enfileirados<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Quando se declara uma classe template, tanto a declaração da classe (sua interface) quanto a implementação de seus métodos devem estar no mesmo arquivo com extensão ''.h''. Isso se deve a [http://stackoverflow.com/questions/19798325/template-compilation detalhes específicos da compilação do código-fonte]. Assim, a implementação dos métodos pode estar dentro da própria declaração da classe, como no caso dos métodos ''vazia'', ''cheia'' e ''tamanho'', ou fora da classe. Quando forem implementados fora da classe, deve-se repetir o prefixo ''template <typename T>'' na frente do nome de cada método, como mostrado a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> void Fila<T>::enfileira(const T& algo) {<br />
// implementação do método<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Uma vez declarada uma classe template, ela pode ser utilizada. Somente no momento em que uma classe é usada que o tipo genérico é especificado. Por exemplo, a ''Fila'' acima declarada pode guardar qualquer coisa, o que inclui strings e números inteiros. Para declarar duas filas, de forma que uma armazene inteiros e outra strings, deve-se usar esta sintaxe:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
// Uma fila capaz de guardar até 10 números inteiros<br />
Fila<int> f1(10);<br />
<br />
// uma fila capaz de guardar até 5 strings<br />
Fila<string> f2(5);<br />
<br />
// enfileira-se o número 23 na fila de inteiros<br />
f1.enfileira(23);<br />
<br />
// enfileira-se a string "uma coisa" na fila de strings<br />
string algo = "uma coisa";<br />
f2.enfileira(algo);<br />
<br />
// outras declarações da função main ...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Do ponto de vista da linguagem, um ''template'' define um padrão de geração de código para o compilador ([http://stackoverflow.com/questions/19798325/template-compilation maiores detalhes]). Quer dizer, um ''template'' em si não é compilável, pois ele representa código-fonte ainda incompleto. No entanto, no momento em que se usa um ''template'', o código-fonte é completado e pode ser compilado. Em outras palavras, o ''template'' da Fila se torna uma Fila de fato. O programa de teste abaixo aproveita o exemplo das filas, enfileirando e desenfileirando dados de duas filas. <br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include "fila.h"<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
// Uma fila de strings<br />
Fila<string> fila1(10);<br />
<br />
// Uma fila de inteiros<br />
Fila<int> fila2(10);<br />
<br />
// Armazena três strings na fila de strings<br />
for (int x=0; x < 3; x++) {<br />
string palavra;<br />
<br />
cout << "Digite uma palavra: ";<br />
cin >> palavra;<br />
fila1.enfileira(palavra);<br />
}<br />
<br />
// Armazena alguns números na fila de inteiros<br />
for(int x=0; x < 8; x += 1) lista2.enfileira(x);<br />
<br />
// Mostra os dados da fila de strings<br />
while (not fila1.vazia()) {<br />
cout << "desenfileirou: " << fila1.desenfileira() << endl;<br />
}<br />
<br />
// Mostra os dados da fila de inteiros<br />
while (not fila2.vazia()) {<br />
cout << "desenfileirou: " << fila2.desenfileira() << endl;<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
= Passagem de parâmetros =<br />
<br />
* [https://pt.stackoverflow.com/questions/59437/qual-a-diferen%C3%A7a-entre-passagem-por-valor-e-passagem-por-refer%C3%AAncia Uma boa explicação no forum Stack Overflow]<br />
<br />
A passagem de parâmetros em C++ pode ser feita de duas maneiras:<br />
# '''[http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#by_value Por valor]''': o parâmetro recebe uma cópia do valor que foi passado. Se o parâmetro for alterado dentro da função, o valor original não é modificado.<br />
# '''[http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#by_reference Por referência]''': o parâmetro é uma referência ao valor que foi passado. Se o parâmetro for alterado, o valor original também será modificado.<br />
<br />
'''OBS:''' o caso de um parâmetro passado por ponteiro funciona da mesma forma que em C. No caso, se o o valor apontado pelo ponteiro for alterado dentro da função, o valor original será modificado. Isso funciona de forma parecida com a passagem de parâmetro por referência, apesar de haver uma diferença sutil.<br />
<br />
Os exemplos a seguir ilustram ambas formas de passagem de parâmetros:<br />
{|border=1<br />
!Passagem por valor<br />
!Passagem por referência<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(int x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
// passagem por referência: observe o operador & <br />
// antes do nome do parâmetro<br />
int incrementa(int & x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br><br><br />
<br />
É possível também a passagem de parâmetros por referência, porém [http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#Constant_Parameters somente-leitura]. A utilidade disso é aproveitar a eficiência da passagem de parâmetro por referência, que evita uma cópia de valor, porém evitando que o valor original seja modificado dentro da função. Exemplo (experimente compilar estes programas):<br />
{|border=1<br />
!Programa 1<br />
!Programa 2<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(const int & x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(const int & x) {<br />
int y = x;<br />
<br />
y++;<br />
return y;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
= Alocação dinâmica de memória: operadores new e delete =<br />
<br />
A alocação dinâmica de memória é uma técnica para reservar e liberar memória por demanda, e sob controle do programador. Ela funciona como se o programador criasse variáveis, porém tivesse que explicitamente destrui-las. Assim, as variáveis não deixariam de existir automaticamente, quando a execução do programa saísse do escopo em que foram criadas.<br />
<br />
A alocação dinâmica está diretamente relacionada com variáveis do tipo ponteiro. Ao se alocar memória dinamicamente, obtém-se o endereço inicial da área de memória obtida, e esse endereço deve ser armazenado em um ponteiro. O uso dessa área de memória, portanto, se faz por meio desse ponteiro.<br />
<br />
A alocação dinâmica de memória na linguagem C++ se faz com o [http://www.cplusplus.com/reference/new/operator%20new/ operador new]. Esse operador aloca memória de acordo com o tipo de dados informado, e retorna um ponteiro para essa área de memória. Quando essa área de memória não for mais necessária, ela deve ser liberada com o [http://www.cplusplus.com/reference/new/operator%20delete/ operador delete]. Veja o exemplo a seguir, que mostra o uso dos operadores ''new'' e ''delete'' em uma situação muito simplificada.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
template <typename T> void mostra(const string & varname, T * val) {<br />
cout << "######################################################" << endl;<br />
cout << "Dado apontado por " << varname << " = " << *val << endl;<br />
cout << "Endereço da área de memória usada por " << varname << ": " << (void*)val << endl;<br />
cout << "Memória alocada: " << sizeof(*val) << " bytes" << endl;<br />
}<br />
<br />
int main() {<br />
// algumas variáveis<br />
// a memória para elas é alocada automaticamente<br />
int * x;<br />
double * h;<br />
<br />
// aloca dinamicamente memória para um valor do tipo int<br />
x = new int;<br />
<br />
// aloca dinamicamente memória para um valor do tipo double<br />
h = new double;<br />
<br />
// armazena valores nas áreas de memória alocadas, usando-se<br />
// os ponteiros<br />
*x = 35;<br />
*h = 6.6260715e-34;<br />
<br />
mostra("x", x); <br />
mostra("h", h); <br />
<br />
// libera as áreas de memória<br />
delete x;<br />
delete h;<br />
}<br />
</syntaxhighlight><br />
<br />
Ao executá-lo, obtém-se isto:<br />
<br />
<syntaxhighlight><br />
######################################################<br />
Dado apontado por x = 35<br />
Endereço da área de memória usada por x: 0x561931d5de70<br />
Memória alocada: 4 bytes<br />
######################################################<br />
Dado apontado por h = 6.62607e-34<br />
Endereço da área de memória usada por h: 0x561931d5de90<br />
Memória alocada: 8 bytes<br />
</syntaxhighlight><br />
<br />
== Inicialização da área de memória alocada ==<br />
<br />
Uma forma alternativa (e importante, como se poderá observar mais pra frente) de usar o operador ''new'' possibilita inicializar a área de memória assim que for alocada. O interessante dessa inicialização é que ela depende do tipo de dados para que foi alocada a memória. Para tipos de dados primitivos, como int, float, double e char, essa inicialização se limita a copiar um valor inicial. Veja como ficaria a alocação de memória do exemplo anterior com esse uso do operador ''new'':<br />
<br />
<syntaxhighlight lang="c++"><br />
// aloca dinamicamente memória para um valor do tipo int e depois para um double<br />
// e armazena valores nas áreas de memória alocadas<br />
x = new int(35);<br />
<br />
// aloca dinamicamente memória para um valor do tipo double<br />
h = new double(6.6260715e-34);<br />
<br />
mostra("x", x); <br />
mostra("h", h); <br />
</syntaxhighlight><br />
<br />
No caso de um tipos de dados que possui um [[Introdu%C3%A7%C3%A3o_C%2B%2B#Invoca.C3.A7.C3.A3o_do_construtor|construtor]], que é uma função-membro executada automaticamente quando se cria um valor desse tipo, o operador ''new'' o executa logo após alocar memória.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
struct Nome {<br />
string nome, sobrenome;<br />
<br />
// construtor: separa um nome completo, <br />
// armazenando nome e sobrenome nos respectivos atributos<br />
Nome(const string & nome_completo) {<br />
int pos = nome_completo.find(' ');<br />
nome = nome_completo.substr(0, pos);<br />
int pos2 = nome_completo.find_first_not_of(" ", pos);<br />
sobrenome = nome_completo.substr(pos2);<br />
}<br />
};<br />
<br />
int main() {<br />
auto alguem = new Nome("Dona Bilica da Silva");<br />
<br />
cout << "Nome: " << alguem->nome << endl;<br />
cout << "Sobrenome: " << alguem->sobrenome << endl;<br />
<br />
delete alguem;<br />
}<br />
</syntaxhighlight><br />
<br />
== Alocação de array (vetor) ==<br />
<br />
O exemplo a seguir mostra a alocação de memória para um vetor (''array''), em que o operador ''new'' aloca memória com capacidade de armazenar múltiplos valores de um certo tipo. Além disso, o exemplo mostra a persistência da área alocada de memória fora do escopo em que ela foi criada:<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
// cria um vetor de inteiros com tamanho "size" e preenche<br />
// todas suas posições com "valor_inicial"<br />
int * cria_vetor(int size, int valor_inicial) {<br />
if (size <= 0) return nullptr;<br />
<br />
// cria um vetor com o tamanho dado por "size"<br />
auto v = new int[size];<br />
<br />
// preenche o vetor com o valor inicial<br />
for (int i=0; i < size; i++) v[i] = valor_inicial;<br />
return v;<br />
}<br />
<br />
int main() {<br />
int size;<br />
<br />
cout << "Qual o tamanho do vetor: ";<br />
cin >> size;<br />
<br />
// v é um ponteiro para int<br />
auto v = cria_vetor(size, 99);<br />
<br />
cout << "Endereço do vetor: " << (void*)v << endl;<br />
cout << "Conteúdo do vetor: ";<br />
for (int x=0; x < size; x++) cout << v[x] << ',';<br />
cout << endl;<br />
<br />
// libera a memória do vetor<br />
delete[] v;<br />
}<br />
</syntaxhighlight><br />
<br />
Um exemplo de execução é mostrado a seguir:<br />
<syntaxhighlight><br />
Qual o tamanho do vetor: 5<br />
Endereço do vetor: 0x561a4d6a4690<br />
Conteúdo do vetor: 99,99,99,99,99,<br />
</syntaxhighlight><br />
<br />
<br />
O uso do operador ''new'' nesse exemplo foi um pouco diferente. Como se pode notar, para criar um vetor indicou-se sua capacidade entre colchetes, logo após o tipo de dados. Isso pede que se aloque memória suficiente para conter aquela quantidade de valores do tipo informado:<br />
<br />
<syntaxhighlight lang="c++"><br />
// aloca memória suficiente oara guardar "size" valores do tipo int<br />
auto v = new int[size]; <br />
</syntaxhighlight><br />
<br />
Além disso, a função ''cria_vetor'' retorna como resultado o vetor que foi alocado. Isso mostra que a área de memória reservada para o vetor sobrevive ao final da função ''cria_vetor''. Essa área de memória continuará alocada até que o [http://www.cplusplus.com/reference/new/operator%20delete/ operador delete] a libere (o que se faz ao final da função ''main'') ... ou até que o programa termine.<br />
<br />
== Resumo ==<br />
* O operador ''new'' aloca uma área de memória com capacidade suficiente para um tipo de dados indicado, e retorna um ponteiro para essa área de memória<br />
* Após alocar a memória, o operador ''new'' a inicializa ao executar o construtor para o tipo de dados<br />
* Toda área de memória alocada deve ser liberada usando o operador ''delete'', quando não for mais necessária<br />
<br />
= Funções template =<br />
<br />
* [http://www.cplusplus.com/doc/oldtutorial/templates/ Templates em maiores detalhes]<br />
<br />
<br />
Funções, assim como classes, podem ser template, em que um ou mais tipos de dados são desconhecidos em tempo de programação. Em uma função template, os tipos de dados de um ou mais parâmetros, ou do valor devolvido como resultado, são desconhecidos em tempo de projeto. Outra forma de ver funções template é perceber que o algoritmo contido na função funciona com (quase) qualquer tipo de dados. <br />
<br />
Por exemplo, imagine que uma função deva ser capaz de ordenar um vetor qualquer, independente do tipo de dados desse vetor. Tal função poderia ser declarada com um template como este:<br />
<br />
<syntaxhighlight lang=c><br />
// Função template "ordena": ordena um "vetor" de comprimento "N"<br />
template <typename T> void ordena(T vetor[], int N);<br />
</syntaxhighlight><br />
<br />
Sua implementação poderia ser esta:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> void ordena(T vetor[], int N) {<br />
int i, j;<br />
<br />
for (i=0; i < N-1; i++) {<br />
for (j=i+1; j < N; j++) {<br />
if (vetor[i] > vetor[j]) {<br />
T aux = vetor[i];<br />
vetor[i] = vetor[j];<br />
vetor[j] = aux;<br />
}<br />
}<br />
} <br />
}<br />
</syntaxhighlight><br />
<br />
A utilização de uma função template implica informar o tipo de dados desconhecido. Isso se faz ao se usar a função:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
long v1[5] = {45, 72, 12, 8, 0};<br />
string v2[7] = {"banana", "abacate", "sapoti", "maracuja", "abacaxi", "caju", "goiaba"};<br />
<br />
// aqui se usa a função ordena, e se informa que o tipo genérico é long<br />
ordena<long>(v1, 5);<br />
<br />
// ... e aqui o tipo genérico é string<br />
ordena<string>(v2, 7);<br />
}<br />
</syntaxhighlight><br />
<br />
= string =<br />
<br />
* [http://www.cplusplus.com/reference/string/string/ a classe string]<br />
<br />
<br />
Na linguagem C++ podem-se trabalhar com duas representações de string:<br />
* ''vetor de char (char * ou char [])'': essa forma é a mesma utilizada na linguagem C.<br />
* ''classe string'': objetos da classe ''string'' implementam strings com diversas facilidades, possibilitando um maior nível de abstração (fica mais fácil).<br />
<br />
<br />
A classe ''string'' foi projetada para que se possa trabalhar com strings de forma simplificada. Por exemplo, o programa abaixo mostra como criar, mostrar na tela e concatenar strings:<br />
<br />
{| border=1<br />
!Usando classe string<br />
!Usando vetor de char<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <string><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(){<br />
// declaração dos objetos string: <br />
// inicialmente eles são com strings vazias<br />
string nome;<br />
string sobrenome;<br />
<br />
// atribui "Manuel" ao objeto string "nome", <br />
// e "Alexievitvh" a "sobrenome"<br />
nome = "Manuel"<br />
sobrenome = "Alexievitch";<br />
<br />
// cria um novo objeto string, e o inicia com o <br />
// resultado da concatenação de nome e sobrenome<br />
string nome_completo = nome + ' ' + sobrenome;<br />
<br />
// mostra o objeto string na tela<br />
cout << "Nome: " << nome_completo << endl;<br />
}<br />
</syntaxhighlight>||<syntaxhighlight lang=c><br />
#include <string.h><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(){<br />
char nome[16];<br />
char sobrenome[32];<br />
<br />
strncpy(nome, "Manuel", 16);<br />
strncpy(sobrenome, "Alexievitch", 32);<br />
<br />
char nome_completo[64];<br />
strcpy(nome_completo, nome);<br />
nome_completo[strlen(nome_completo)] = ' ';<br />
nome_completo[strlen(nome_completo)] = 0;<br />
strcat(nome_completo, sobrenome);<br />
<br />
cout << "Nome: " << nome_completo << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
A classe string oferece [http://www.cplusplus.com/reference/string/string/ diversas operações], tais como:<br />
* [http://www.cplusplus.com/reference/string/string/size/ size]: Obter o comprimento da string<br />
* [http://www.cplusplus.com/reference/string/string/operator%5B%5D/ operator[]]: Obter um caractere em uma determinada posição. Esse tipo de acesso é sintaticamente idêntico ao acesso a uma posição de um vetor<br />
* [http://www.cplusplus.com/reference/string/string/operator+=/ operator+=]: anexa uma string<br />
* [http://www.cplusplus.com/reference/string/string/push_back/ push_back]: anexa um caractere<br />
* [http://www.cplusplus.com/reference/string/string/erase/ erase]: remove caracteres de uma string<br />
* [http://www.cplusplus.com/reference/string/string/replace/ replace]: substitui parte de uma string<br />
* [http://www.cplusplus.com/reference/string/string/c_str/ c_str]: retorna uma representação em vetor de char<br />
* [http://www.cplusplus.com/reference/string/string/find/ find]: encontra a primeira ocorrência de uma substring ou um caractere<br />
* [http://www.cplusplus.com/reference/string/string/rfind/ rfind]: encontra a última ocorrência de uma substring ou um caractere<br />
* [http://www.cplusplus.com/reference/string/string/substr/ substr]: gera uma substring<br />
<br />
== Lendo ou escrevendo strings em streams ==<br />
<br />
Podem-se ler ou escrever strings em streams usando os operadores ''<<'' ou ''>>''. Por exemplo, para ler uma string da entrada padrão (ex: teclado), pode-se fazer assim:<br />
<br />
<syntaxhighlight lang=c><br />
string algo;<br />
<br />
// lê uma string da entrada padrão e grava-a em "algo"<br />
cin >> algo;<br />
</syntaxhighlight><br />
<br />
<br />
Para escrever uma string em um stream (ex: um arquivo), pode-se faz desta forma:<br />
<br />
<syntaxhighlight lang=c><br />
// abre um arquivo para escrita<br />
ofstream arq("teste.txt");<br />
<br />
string algo = "Um teste";<br />
<br />
// escreve a string no arquivo<br />
arq << algo;<br />
</syntaxhighlight><br />
<br />
<br />
No caso da leitura de uma string que contenha espaços, ou mesmo de uma linha completa, deve-se usar a função [http://www.cplusplus.com/reference/string/string/getline/ getline]:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
<br />
cout << "Escreva uma frase: ";<br />
<br />
getline(cin, linha);<br />
<br />
cout << "Frase digitada é: " << linha;<br />
</syntaxhighlight><br />
<br />
A função getline usa o caractere ''newline'' (''\n'') como delimitador. Se for desejado usar outro caractere como delimitador, deve-se fazer o seguinte:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
char delimitador=',';<br />
<br />
cout << "Escreva uma frase que contenha ao menos uma vírgula: ";<br />
<br />
getline(cin, linha, delimitador);<br />
<br />
cout << "Frase digitada até a vírgula é: " << linha;<br />
</syntaxhighlight><br />
<br />
== Conversão de string para tipos numéricos ==<br />
<br />
* [[Introdução_C%2B%2B#Leitura_e_escrita_formatada|Leitura e escrita com operadores << e >>]]<br />
<br />
<br />
Em C++ há diferentes formas de converter strings para dados numéricos, e vice-versa. Podem-se, por exemplo, usar as funções da biblioteca C padrão ([http://manpages.ubuntu.com/manpages/precise/man3/scanf.3.html sscanf], [http://manpages.ubuntu.com/manpages/precise/man3/snprintf.3.html snprintf], [http://manpages.ubuntu.com/manpages/precise/man3/strtod.3.html strtod], ...). Mas uma forma particular existente em C++ explora o conceito de ''streams''. <br />
<br />
Arquivos abertos são acessados como ''streams'' em C++. Na verdade, essa é uma interface corriqueira para acesso a arquivos, estando disponível em diferentes linguagens (ex: as operações de arquivo em C, como [http://manpages.ubuntu.com/manpages/precise/man3/fscanf.3.html fscanf], [http://manpages.ubuntu.com/manpages/precise/man3/fprintf.3.html fprintf], [http://manpages.ubuntu.com/manpages/precise/man3/fread.3.html fread, fwrite], [http://manpages.ubuntu.com/manpages/precise/man3/fgets.3.html fgets], ...). Em C++ ''streams'' possibilitam ler texto de um arquivo e convertê-lo para um dado numérico, e vice-versa. Isso é feito normalmente em programas, como no exemplo abaixo:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ifstream arq("numeros.txt");<br />
int numero;<br />
string palavra;<br />
<br />
arq >> numero;<br />
arq >> palavra;<br />
<br />
cout << "numero=" << numero << endl;<br />
cout << "palavra=" << palavra << endl;<br />
<br />
arq.close();<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Se o arquivo ''numeros.txt'' possuir este conteúdo:<br />
<br />
<syntaxhighlight lang=text><br />
2015 Furious<br />
1999 Matrix<br />
</syntaxhighlight><br />
<br />
<br />
... a execução do programa exemplo, que lê apenas a primeira linha, resultará em:<br />
<br />
<syntaxhighlight lang=text><br />
numero=2015<br />
palavra=Furious<br />
</syntaxhighlight><br />
<br />
<br />
Assim, o operador ''>>'' de ''streams'' possibilita converter texto para um outro tipo de dado, dependendo do tipo da variável onde o resultado deva ser gravado. No exemplo, esse operador é usado duas vezes:<br />
<br />
<syntaxhighlight lang=c><br />
arq >> numero; // converte texto para inteiro, pois "numero" <br />
// é uma variável do tipo int<br />
arq >> palavra;// converte texto para string, pois palavra é do tipo string<br />
</syntaxhighlight><br />
<br />
<br />
Parece que C++ possibilita converter facilmente texto (string) para dado numérico SE o texto estiver guardado em um arquivo. Isso não é conveniente para converter um valor que esteja guardado em uma variável string, pois tornaria necessário escrevê-la em um arquivo temporário para depois ler desse arquivo e efetuar a conversão. De fato, se fosse assim dificilmente ''streams'' seriam usadas para converter dados em C++. No entanto existe um tipo de ''stream'' que possibilita que se acesse uma string como se fosse um arquivo. Quer dizer, a leitura e a escrita dos caracteres de uma string podem ser feitas com operações de arquivo. O exemplo abaixo mostra o uso dessa [http://www.cplusplus.com/reference/sstream/istringstream/ ''stream de string'' (ou ''stringstream'')]:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
// as classes stringstream estão em sstream<br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
istringstream stream("2015 Furious");<br />
int numero;<br />
string palavra;<br />
<br />
stream >> numero;<br />
stream >> palavra;<br />
<br />
cout << "numero=" << numero << endl;<br />
cout << "palavra=" << palavra << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O exemplo mostra uma ''stringstream'' criada com conteúdo ''2015 Furious''. Em seguida, usa-se o operador ''>>'' para ler um número inteiro e uma string. O resultado desse exemplo é idêntico ao do exemplo anterior, em que se liam esses dados de um arquivo.<br />
<br />
A possibilidade de usar ''stringstream'' para converter dados torna simples criar funções de conversão, como esta que converte string para inteiro:<br />
<br />
<syntaxhighlight lang=c><br />
int converte_para_int(const string & dado) {<br />
istringstream stream(dado);<br />
int r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Outras funções para tipos numéricos podem ser criadas da mesma forma:<br />
<br />
<syntaxhighlight lang=c><br />
float converte_para_float(const string & dado) {<br />
istringstream stream(dado);<br />
float r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
<br />
<br />
double converte_para_double(const string & dado) {<br />
istringstream stream(dado);<br />
double r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Note que são todas muito parecidas. A única diferença entre elas é o tipo do dado numérico da conversão. Assim, é natural substitui-las por uma função ''template'':<br />
<br />
<syntaxhighlight lang=c><br />
template <class T> T converte(const string & dado) {<br />
istringstream stream(dado);<br />
T r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Essa função ''template'' seria usada da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
template <class T> T converte(const string & dado) {<br />
istringstream stream(dado);<br />
T r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
<br />
int main() {<br />
string algo1 = "2015";<br />
string algo2 = "3.1416";<br />
string algo3 = "xyz";<br />
int ano;<br />
float pi;<br />
<br />
ano = converte<int>(algo1);<br />
pi = converte<float>(algo2);<br />
<br />
cout << "ano=" << ano << endl;<br />
cout << "pi=" << pi << endl;<br />
<br />
try {<br />
ano = converte<int>(algo3);<br />
cout << "Outro ano=" << ano << endl;<br />
} catch (int e) {<br />
cout << "Erro de conversão: " << algo3 << " não é um int" << endl;<br />
}<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
= ''streams'' e arquivos =<br />
<br />
Em diversas linguagens de programação o conceito de ''stream'' (''fluxo'' ou ''correnteza'') é utilizado para o acesso a arquivos em disco. Por ''stream'' entende-se um mecanismo e leitura e escrita em que dados fluem sucessivamente. Dessa forma, ao se escrever em um arquivo fazem-se sucessivas operações de escrita, e os dados são armazenados na ordem em que essas operações se realizaram. Algo parecido acontece na leitura de um arquivo, em que as operações de leitura realizadas fornecem dados de acordo com a ordem em que estão gravados no arquivo. <br />
<br />
<br />
O acesso a arquivos apresenta algumas diferenças nas linguagens C e C++. Em C++ existem algumas classes para a manipulação de arquivos. Desta forma, arquivos nesta linguagem são acessados por meio de objetos dessas classes. No exemplo abaixo, apresentam-se dois programas em C e C++ para ler as linhas de um arquivo e mostrá-las na tela. <br />
<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <stdio.h><br />
#include <errno.h><br />
<br />
#define MAX_SIZE 10240<br />
<br />
int main() {<br />
FILE * arq;<br />
char linha[MAX_SIZE];<br />
<br />
// abre o arquivo<br />
arq = fopen("/etc/hosts", "r");<br />
<br />
// testa se conseguiu abrir o arquivo<br />
if (arq == NULL) {<br />
perror("Ao abrir /etc/hosts");<br />
return errno;<br />
}<br />
<br />
// lê cada linha do arquivo, mostrando-a na tela<br />
while (fgets(linha, MAX_SIZE, arq)) {<br />
printf("%s", linha);<br />
}<br />
<br />
// fecha o arquivo<br />
fclose(arq);<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
#include <stdio.h><br />
#include <errno.h><br />
<br />
#define MAX_SIZE 10240<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
// cria o objeto "arq" da classe "ifstream", que representa um arquivo para leitura<br />
// a criação desse objeto já abre o arquivo<br />
ifstream arq("/etc/hosts");<br />
<br />
// verifica se o arquivo foi de fato aberto<br />
if (! arq.is_open()) {<br />
perror("Ao abrir /etc/hosts");<br />
return errno;<br />
}<br />
<br />
// lê cada linha do arquivo, apresentando-a na tela<br />
string linha;<br />
while (getline(arq, linha)) {<br />
cout << linha << endl;<br />
}<br />
<br />
// observe que o arquivo não precisa ser fechado ... isso ocorre automaticamente<br />
// quando o objeto for destruído, ficando a cargo de seu destrutor<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
Os exemplos acima demonstram que a sintaxe no acesso a arquivos pode ser diferente, porém funcionalmente parece haver uma equivalência entre as duas formas de acesso. De fato tudo que se consegue fazer em C++ é possível fazer em C, mudando apenas a praticidade ou conveniência na forma com que se expressa isso nessas linguagens. Porém como a linguagem C já é bem conhecida por vocês, interessa ver o que se pode fazer em C++.<br />
<br />
Em C++ existem três classes para acessar arquivos:<br />
* [http://www.cplusplus.com/reference/fstream/ofstream/ ofstream]: acesso a arquivos em modo escrita. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ofstream arq("demo.txt");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
arq << "Iniciando uma gravação de várias linhas inúteis ..." << endl;<br />
<br />
for (int i=0; i < 10; i++) {<br />
arq << "Linha " << i << endl; <br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
* [http://www.cplusplus.com/reference/fstream/ifstream/ ifstream]: acesso a arquivos em modo leitura. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ifstream arq("/etc/hosts");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
while (not arq.eof()) {<br />
string algo;<br />
<br />
arq >> algo;<br />
cout << "Leu isto: " << algo << endl;<br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
* [http://www.cplusplus.com/reference/fstream/ fstream]: acesso a arquivos em modo leitura/escrita. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
#define MAX_LINE 10240<br />
<br />
int main() {<br />
fstream arq("demo.txt");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
for (int i=0; i < 10; i++) {<br />
arq << "Linha " << i << endl; <br />
}<br />
arq.flush();<br />
<br />
arq.seekg(0);<br />
<br />
while (not arq.eof()) {<br />
char linha[MAX_LINE];<br />
<br />
arq.getline(linha, MAX_LINE);<br />
cout << "Leu: " << linha << endl;<br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
<br />
O interessante em C++ é que a saída padrão e a entrada padrão são representados por objetos ''stream''. De fato, veja como estão declarados esses objetos na biblioteca C++ padrão:<br />
* [http://www.cplusplus.com/reference/iostream/cout/ cout]: saída padrão<br />
* [http://www.cplusplus.com/reference/iostream/cin/ cin]: entrada padrão<br />
* [http://www.cplusplus.com/reference/iostream/cerr/ cerr]: saída de erros padrão<br />
<br />
== Leitura e escrita formatada ==<br />
<br />
''streams'' implementam leitura e escrita formatadas por meio dos operadores [http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ ''>>''] (leitura) e [http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ ''<<''] (escrita). Esses operadores fazem a conversão automática entre ''string'' e outros tipos de dados.<br />
<br />
A leitura de um ''stream'' pode ser feita como no exemplo a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
int x;<br />
<br />
cout << "Digite um número inteiro: ";<br />
<br />
// aqui se faz a leitura de um número inteiro<br />
cin >> x;<br />
<br />
cout << "Você digitou " << x << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Nesse exemplo, a leitura é feita de ''cin'', uma ''stream'' que representa a console (usualmente o teclado). Lê-se um número inteiro digitado pelo usuário, o qual é armazenado na variável ''x''. A conversão de ''string'' para inteiro é feita automaticamente, porque a variável onde se deseja armazenar o valor lido é do tipo ''int''. Assim, a conversão depende do tipo da variável onde se deve armazenar o valor lido. Este outro exemplo reforça a questão da conversão de tipo:<br />
<br />
<syntaxhighlight lang=c><br />
char algo;<br />
int numero;<br />
<br />
cout << "Digite um caractere qualquer seguido de um número (ex: !33): ";<br />
cin >> algo;<br />
cin >> numero;<br />
<br />
cout << "Você digitou: " << algo << numero << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Nesse novo exemplo, dois valores são lidos: um valor do tipo char seguido de um int. O primeiro valor corresponde a um único caractere, e o segundo a um ou mais caracteres numéricos consecutivos. As conversões são desencadeadas pelos tipos das variáveis usados nas leituras. Algo similar acontece quando se escrevem dados em um ''stream''.<br />
<br />
<br />
O exemplo a seguir mostra a escrita de alguns valores em ''cout'', um ''stream'' que representa também a console (usualmente a tela):<br />
<br />
<syntaxhighlight lang=c><br />
double pi = 3.1416;<br />
char letra = 'H';<br />
<br />
// escreve um valor do tipo char<br />
cout << letra;<br />
<br />
// escreve um valor do tipo string (char*)<br />
cout << " = ";<br />
<br />
// escreve um valor do tipo double<br />
cout << pi;<br />
<br />
// endl corresponde a \n (newline)<br />
cout << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Como mostra o exemplo, são escritos valores do tipo ''char'', , ''char*'' e ''double''. Em todos os casos, a conversão automática entre esses valores e string depende do tipo da variável ou constante onde está o valor a ser escrito. <br />
<br />
=== Lendo linha por linha ===<br />
<br />
Este outro exemplo mostra uma forma simples de ler todas as linhas de um arquivo. A função [http://www.cplusplus.com/reference/string/string/getline/ getline] extrai uma linha a cada vez que é chamda. Neste exemplo, o efeito final será ler linha por linha do arquivo:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
ifstream arq("teste.txt");<br />
<br />
// enquanto conseguir ler uma string do arquivo ...<br />
// quando chegar ao fim do arquivo, a leitura irá falhar<br />
while (getline(arq, linha)) {<br />
// faz algo com o conteúdo de "linha"<br />
}<br />
</syntaxhighlight><br />
<br />
=== Lendo palavra por palavra ===<br />
<br />
Este outro exemplo mostra uma forma simples de ler todos os valores de um arquivo. O operador ''>>'' extrai um valor a cada vez que é executado sobre o arquivo. Neste exemplo, o efeito final será ler palavra por palavra do arquivo:<br />
<br />
<syntaxhighlight lang=c><br />
string palavra;<br />
ifstream arq("teste.txt");<br />
<br />
// enquanto conseguir ler uma string do arquivo ...<br />
// quando chegar ao fim do arquivo, a leitura irá falhar<br />
while (arq >> palavra) {<br />
// faz algo com o conteúdo de "palavra"<br />
}<br />
</syntaxhighlight><br />
<br />
Deve-se notar que o operador ''>>'' considera como delimitadores os caracteres ''brancos'' (espaço, TAB, newline).<br />
<br />
<br />
A escrita e leitura formatada está implementada para os tipos elementares de C e C++ (int, long, short, char, char*, string, bool, float, double). Isso significa que essas operações não funcionam para novos tipos de dados ou classes classes, a não ser que se [[Introdução_C%2B%2B#Sobrecarga_de_operador|implementem esses operadores de leitura e escrita para esses novos tipos]].<br />
<br />
== Operações de streams ==<br />
<br />
''streams'' oferecem várias operações para leitura e escrita de dados. Algumas mais comuns são listadas a seguir, junto com exemplos.<br />
<br />
{| border=1<br />
!Operação<br />
!Entrada<br />
!Saída<br />
!Para que serve<br />
!Exemplo<br />
|-<br />
| [http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ >>] || x|| ||leitura formatada || <syntaxhighlight lang=c>int x;<br />
double y;<br />
string palavra;<br />
<br />
// lê um número inteiro<br />
cin >> x;<br />
<br />
// lê um número double<br />
cin >> y;<br />
<br />
// lê uma string<br />
cin >> palavra;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ <<] || ||x ||escrita formatada ||<syntaxhighlight lang=c>int x = 5;<br />
double y=3.1416;<br />
string palavra="alguma coisa";<br />
<br />
// escreve um número inteiro seguido de uma vírgula<br />
cout << x << ", ";<br />
<br />
// escreve um número double seguido de uma vírgula<br />
cout << y << ", ";<br />
<br />
// escreve uma string seguida de nova linha<br />
cout << palavra << endl;<br />
<br />
// outra forma de escrever os três valores <br />
cout << x << ", " << y << ", " << palavra << endl;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/string/string/getline/ getline] || x|| ||lê uma linha (até encontrar '\n') || <syntaxhighlight lang=c>string linha;<br />
<br />
getline(cin, linha);<br />
<br />
cout << "Linha: " << linha << endl;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/istream/istream/ignore/ ignore] || x|| ||lê e descarta caracteres ||<syntaxhighlight lang=c><br />
cout << "Tecle ENTER para continuar";<br />
cin.ignore(256, '\n'); // lê e descarta até 256 caracteres, ou até ler '\n'<br />
</syntaxhighlight><br />
|-<br />
| [http://www.cplusplus.com/reference/ios/ios/eof/ eof] || x||x ||Verifica se chegou ao fim da stream|| <syntaxhighlight lang=c><br />
ifstream arq("/etc/hosts");<br />
<br />
while (true) {<br />
string linha;<br />
<br />
getline(arq, linha);<br />
if (arq.eof()) break; // se não conseguir ler algo (fim de arquivo)<br />
cout << linha << endl;<br />
}<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/fstream/ifstream/is_open/ is_open] || x||x||Verifica se arquivo foi aberto|| <syntaxhighlight lang=c><br />
ifstream arq("/etc/hosts");<br />
<br />
if (not arq.is_open()) {<br />
cout << "Erro: não abriu o arquivo" << endl;<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
== Acessando strings como se fossem arquivos ==<br />
<br />
Em C++ esse conceito de ''stream'' é levado um pouco além. Além de arquivos e a entrada e saída padrão, é possível também manipular ''strings'' como se fossem ''streams''. Quer dizer, pode-se escrever em uma ''string'' (criá-la) ou extrair partes de uma ''string'' como se estivesse acessando um arquivo. Isso possibilita que funções ou objetos que escrevem ou lêem em arquivos possam fazer o mesmo em memória, o que pode ser útil em diferentes programas. <br />
<br />
O uso de ''strings'' como se fossem ''streams'' é implementado por três classes:<br />
* [http://www.cplusplus.com/reference/sstream/ostringstream/ ostringstream]: possibilita escrever em uma ''string''<br />
* [http://www.cplusplus.com/reference/sstream/istringstream/ istringstream]: possibilita ler de uma ''string''<br />
* [http://www.cplusplus.com/reference/sstream/stringstream/ stringstream]: possibilita ler e escrever em uma ''string''<br />
<br />
<br />
O exemplo mais simples envolve criar uma string a partir dos valores de algumas variáveis. Veja como isso era feito em C e como se faz em C++:<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
printf("Dia: ");<br />
scanf("%d", &dia);<br />
printf("Mes: ");<br />
scanf("%d", &mes);<br />
printf("Ano: ");<br />
scanf("%d", &ano);<br />
<br />
snprintf(data, 32, "%d/%d/%d", dia, mes, ano);<br />
<br />
printf("Data: %s\n", data);<br />
<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int dia, mes, ano;<br />
<br />
cout << "Dia: ";<br />
cin >> dia;<br />
cout << "Mes: ";<br />
cin >> mes;<br />
cout << "Ano: ";<br />
cin >> ano;<br />
<br />
//cria-se uma stringstream para escrita<br />
ostringstream out;<br />
<br />
// escreve-se na stringstream<br />
out << dia << "/";<br />
out << mes << "/";<br />
out << ano;<br />
<br />
// Aqui se obtém o conteúdo armazenado na stringstream<br />
cout << "Data: " << out.str() << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
Estes outros exemplos mostram a extração de dados que existem em strings:<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
| <syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
printf("Data (dia/mes/ano): ");<br />
fgets(data, 32, stdin); // lê uma linha<br />
<br />
// extrai os dados da linha<br />
sscanf(data, "%d/%d/%d", &dia, &mes, &ano);<br />
<br />
// Aqui se mostram os dados extraídos da linha<br />
printf("Dia: %d\n", dia);<br />
printf("Mes: %d\n", mes);<br />
printf("Ano: %d\n", ano);<br />
}<br />
</syntaxhighlight>|| <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
cout << "Data (dia/mes/ano): "; <br />
cin.getline(data, 32);<br />
<br />
//cria-se uma stringstream para leitura<br />
istringstream inp(data);<br />
char separador;<br />
<br />
// lê-se da stringstream<br />
inp >> dia;<br />
inp >> separador;<br />
inp >> mes;<br />
inp >> separador;<br />
inp >> ano;<br />
<br />
// Aqui se mostram os dados extraídos da stringstream<br />
cout << "Dia: " << dia << endl;<br />
cout << "Mes: " << mes << endl;<br />
cout << "Ano: " << ano << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
= Sobrecarga de operador =<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/templates/#overloading_operators Operator overloading]: uma explicação mais detalhada sobre o assunto. Inclui também uma tabela com os operadores que podem ser redefinidos.<br />
<br />
<br />
Operadores C++ podem ser redefinidos, o que se chama sobrecarga de operador (''operator overloading''). Assim, dependendo do tipo de dados ou da classe do valor, variável ou objeto que recebe a operação, o operador pode funcionar de uma forma específica. Um operador pode ser implementado como uma função, que pode ou não ser membro de uma classe.<br />
<br />
<br />
O nome da função que implementa um operador é formado pela palavra chave ''operator'' seguida do operador que se deseja implementar. Por exemplo, para o operador ''=='' a função se chama ''operator==''. O tipo do valor de retorno dessa função depende do operador a ser implementado (ex: o operador == retorna um valor booleano, mas o operador = retorna uma referência à variável ou objeto que foi alvo da operação). A quantidade de parâmetros dessa função também dependem do operador em questão, e os tipos de desses parâmetros dependem dos tipos de dados envolvidos na operação.<br />
<br />
<br />
Um operador pode ser implementado de duas formas:<br />
# '''Como um método de uma classe:''' um método implementa a operação a ser realizada quando se usa o operador com um objeto dessa classe. A execução desse método acontece no escopo do objeto que recebe a operação (ex: em operadores unários é o próprio objeto alvo do operador, e em operadores binários é o objeto que aparece à esquerda do operador).<br />
# '''Como uma função:''' uma função implementa a operação a ser realizada quando se usa o operador. Essa função recebe como parâmetros as variáveis ou objetos envolvidos na operação.<br />
<br />
<br />
Dois exemplos são apresentados para esclarecer a sobrecarga de operadores usando funções que não são membros de classe (i.e. não são métodos):<br />
* '''Operador unário !:''' o operador ''!'' corresponde à operação NÃO, mas ele pode ser redefinido para um tipo de dados específico. Suponha-se que se deseje que o operador ''!'' aplicado a uma string deve retornar ''true'' se ela for vazia, e ''false'' caso contrário. Isso pode ser feito redefinido o operador ''!'' para string da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
bool operator!(const string & s) {<br />
if (s.size() == 0) return true;<br />
return false;<br />
}<br />
</syntaxhighlight><br />
<br />
* '''Operador binário ==''': o operador ''=='' serve para comparar dois valores, resultando em ''true'' se eles forem considerados iguais, e ''false'' caso contrário. Suponha-se que se deseje que esse operador, quando aplicado a string, resulte em ''true'' se duas string tiverem mesmo comprimento. Isso pode ser feito da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
bool operator==(constr string & s1, const string & s2) {<br />
return s1.size() == s2.size();<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Esses dois operadores podem ser exemplificados também como métodos uma classe. Usando-se a classe Fila, ambos operadores podem ser implementados da seguinte forma. O operador unário ''!'' deve retornar ''true'' se fila estiver vazia, e o operador ''=='' deve retornar ''true'' se as filas forem iguais:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
private:<br />
// atributos da fila<br />
public:<br />
// métodos da fila<br />
<br />
bool operator!() const {<br />
return vazia();<br />
}<br />
<br />
bool operator==(const Fila<T> & outra) const {<br />
// para serem iguais, devem ter mesma quantidade de dados<br />
if (itens == outra.itens) { <br />
// ... e os dados devem ser iguais e estarem na mesma ordem<br />
int n = itens;<br />
<br />
while (n > 0) {<br />
T dado1 = desenfileira();<br />
T dado2 = outra.desenfileira();<br />
enfileira(dado1);<br />
enfileira(dado2);<br />
if (dado1 != dado2) return false;<br />
n--;<br />
}<br />
return true;<br />
}<br />
return false;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
== Sobrecarga de operadores << e >> de streams ==<br />
<br />
Pode-se desejar que objetos de uma classe possam ser escritos em ''streams'' diretamente por meio do operador ''<<''. Para descobrir uma solução para esse problema, deve-se entender como o operador ''<<'' está definido. E basicamente ele está implementado de duas formas:<br />
# [http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ Na classe ostream]: a classe ''ostream'' representa arquivos/streams abertos para escrita, e já possui implementações desse operador para tipos básicos de C++.<br />
# '''Em funções de sobrecarga de operador ([http://www.tutorialspoint.com/cplusplus/cpp_overloading.htm operator overloading]):''' podem-se definir funções que implementam esse operador para novos tipos/classes. Por exemplo, existe [http://www.cplusplus.com/reference/string/string/operator%3C%3C/ uma dessas funções para a classe string]. Um exemplo de função de sobrecarga de operador para um novo tipo de dados segue abaixo: <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
// Define-se um novo tipo de dados<br />
struct Ponto {<br />
int x,y;<br />
};<br />
<br />
// Define-se o operador << de ostream para poder escrever um Ponto.<br />
// Esse operador mostra o ponto da seguinte forma: (x,y)<br />
ostream& operator<<(ostream &out, const Ponto& p) {<br />
out << "(" << p.x << "," << p.y << ")";<br />
return out;<br />
}<br />
<br />
// Agora pode-se usar o operador << para valor do tipo "Ponto"<br />
int main() {<br />
Ponto p1 = {1,1}, p2 = {10,20};<br />
<br />
cout << "Ponto 1: " << p1 << endl;<br />
cout << "Ponto 2: " << p2 << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O mesmo vale para o operador ''>>''. Para que se possa ler diretamente de um ''stream'' um valor de um novo tipo de dados ou classe, esse operador precisa ser definido.<br />
<br />
= Exceções =<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/exceptions/ Uma explicação detalhada sobre exceções]<br />
<br />
<br />
Condições de erro podem ser avisadas por meio de exceções. Por exemplo, no caso da lista considera-se erro tentar obter um valor em uma posição inexistente. A operação para obter um dado da lista deve, portanto, comunicar de alguma forma que esse acesso inválido aconteceu. Outro exemplo mais simples envolve a conversão de uma string numérica com a função stoi. Se a string não contiver um número inteiro, ocorre um erro. O programa a seguir demonstra esse caso, mostrando o erro:<br />
<br />
<syntaxhighlight lang=c><br />
#include <string><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string n1 = "123";<br />
string n2 = "abc";<br />
int x1, x2;<br />
<br />
// esta conversão é feita com sucesso<br />
x1 = stoi(n1);<br />
<br />
cout << "Primeira conversão: " << x1 << endl;<br />
<br />
// ... mas esta causa um erro <br />
x2 = stoi(n2);<br />
<br />
cout << "Segunda conversão: " << x2 << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Ao se compilar e executar esse programa, obtém-se este resultado, que revela o erro de execução:<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@curl:~$ g++ -o erro -std=c++11 erro.cpp <br />
aluno@curl:~$ ./erro<br />
Primeira conversão: 123<br />
terminate called after throwing an instance of 'std::invalid_argument'<br />
what(): stoi<br />
Abortado (imagem do núcleo gravada)<br />
</syntaxhighlight><br />
<br />
<br />
O erro manifestado no programa, e que causou sua terminação abrupta, se chama exceção. O mecanismo de exceções existente na linguagem C++ possibilita expressar e tratar condições de erro de uma forma mais prática. Um algoritmo pode disparar uma exceção se detectar uma situação anômala, interrompendo a execução do programa. Essa interrupção causa a execução de um outro trecho de código, responsável por tratar a exceção. Sendo assim, na parte do código onde pode ocorrer uma exceção, deve-se capturá-la e tratá-la. Para isso usa-se a construção ''try ... catch'', que possibilita executar um tratador de exceção. No exemplo de conversão de string numérica, o uso de ''try .. catch'' ficaria assim:<br />
<br />
<syntaxhighlight lang=c><br />
string n1 = "123";<br />
string n2 = "abc";<br />
int x1, x2;<br />
<br />
try {<br />
// esta conversão é feita com sucesso<br />
x1 = stoi(n1);<br />
cout << "Primeira conversão: " << x1 << endl;<br />
} catch (...) {<br />
cout << "Erro de conversão: " << n1 << " não é uma string numérica inteira !" << endl;<br />
}<br />
<br />
try {<br />
// esta conversão dispara uma exceção<br />
x2 = stoi(n2);<br />
cout << "Segunda conversão: " << x2 << endl;<br />
} catch (...) {<br />
cout << "Erro de conversão: " << n2 << " não é uma string numérica inteira !" << endl;<br />
}<br />
<br />
return 0;<br />
</syntaxhighlight><br />
<br />
<br />
No exemplo acima, o bloco ''try .. catch'' foi usado de forma a capturar qualquer exceção, o que se define com ''catch (...)''. No entanto, exceções podem ser de diferentes tipos, tais como números, string, ou mesmo objetos. Uma exceção portanto é representada por algum valor informativo, e esse valor pertence a algum tipo de dados ou classe. Com isso, diferentes tipos de exceção podem ser disparadas em um trecho de código, e para capturá-las e tratá-las individualmente é necessário definir tratadores de exceção específicos. Por exemplo, considere que um trecho de código possa disparar exceções do tipo int, string, e possivelmente outras. A forma de tratá-las poderia ser assim:<br />
<br />
<syntaxhighlight lang=c><br />
try {<br />
// trecho de código que pode disparar diferentes tipos de exceções<br />
} catch (int e1) { <br />
// aqui se tratam exceções do tipo int<br />
} catch (string e2) {<br />
// aqui se tratam exceções do tipo string<br />
} catch (...) {<br />
// aqui se tratam demais exceções de tipos quaisquer<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Por outro lado, quando se programa um algoritmo (embutido em uma função ou método de classe), erros ou situações inesperadas que forem detectadas implicam o disparo de uma exceção por meio da palavra chave ''throw''. O valor da exceção pode ser qualquer, e no exemplo a seguir é representado por um número inteiro:<br />
<br />
<syntaxhighlight lang=c><br />
void maiusculas(string & palavra) {<br />
if (palavra.size() == 0) throw 1; // string vazia !!!<br />
<br />
for (int i=0; i < palavra.size(); i++) palavra[i] = toupper(palavra[i]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
'''OBS:''' se uma exceção não for capturada usando ''try ... catch'', ela causará o término do programa.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=Introdu%C3%A7%C3%A3o_C%2B%2B&diff=171824Introdução C++2020-11-08T21:08:38Z<p>Msobral: /* streams e arquivos */</p>
<hr />
<div>__toc__<br />
<br />
= Bibliografia = <br />
<br />
* [http://www.cplusplus.com/doc/tutorial/ Tutorial sobre linguagem C++]<br />
* [http://glu.fcfrp.usp.br/tulio/materiais/c++.pdf Introdução a C++ (USP)]<br />
* [http://www.inf.ufrgs.br/~johann/cpp2004/ Introdução a C++ (UFRGS)]<br />
* [http://orion.lcg.ufrj.br/C++/curso/ Introdução a C++ (UFRJ)]<br />
* [http://www.cplusplus.com/ Cplusplus.com: um sítio com muita informação sobre C++ (incluindo um guia de referência da biblioteca C++ padrão)]<br />
* [http://www.icce.rug.nl/documents/cplusplus/ C++ Annotations (muito bom e aprofundado)]<br />
* [https://isocpp.org/ News, Status & Discussion about Standard C++]<br />
* [https://pihisall.wordpress.com/2007/03/15/aprenda-a-programar-em-dez-anos/ Aprenda a programar em 10 anos !]<br />
* [http://www.johndcook.com/blog/2011/06/14/why-do-c-folks-make-things-so-complicated/ Por que os caras de C++ fazem tudo tão complicado ?]<br />
* [http://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798 Organização de arquivos de código-fonte]<br />
<br />
<!-- Tópicos para tutoriais de C++:<br />
<br />
- cout: http://www.tiexpert.net/programacao/c/cout.php<br />
<br />
- cin: http://www.tiexpert.net/programacao/c/cin.php<br />
<br />
- biblioteca ctype (achei interessante): http://www.tiexpert.net/programacao/c/ctype.php<br />
<br />
- Operador condicional ternário ?: : http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.35 curso basico<br />
<br />
- Valores default para funções: http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.44 curso basico<br />
<br />
- Sobrecarga de operador para classes: http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf p.30 curso avançado<br />
<br />
- Template: http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf p.52<br />
<br />
- Processamento de arquivos: http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf p.59<br />
http://dcm.ffclrp.usp.br/~augusto/teaching/ici/Arquivos-Texto-CPP.pdf Alguns exemplos, porém um pouco mais complexo.<br />
<br />
- Comparativo entre C e C++: http://www-usr.inf.ufsm.br/~pozzer/disciplinas/cg_5_oo_c++.pdf p.8<br />
<br />
- Exceções try-catch, throw: http://www.inf.pucrs.br/~pinho/PRGSWB/Apoio/Excecoes/Excecoes.html <br />
https://www.youtube.com/watch?v=-g3HR44neDg Vídeo com códigos disponíveis com exemplos simples de exceções e classe de exceção.<br />
Código1: https://gist.github.com/marcoscastro/1ec08c1f944759ef7a1c<br />
Código2: https://gist.github.com/marcoscastro/e8f939b583fdaf84ed52<br />
<br />
- http://www.pontov.com.br/files/cpp/roadmapcpp/ApostilaProgramacaoCppv045.pdf Apostila com diversos conteúdos, muito boa.<br />
p.84: Novidades e vantagens C++ em relação ao C.<br />
p.121: Namespace<br />
p.241: Sobrecarga de Operador<br />
<br />
- Programando em C, C++, 'A Bíblia'. Kris Jams, Lars Klander. <br />
824.Resolvendo o Escopo Global<br />
838.Usando a palavra-chave CONST em C++<br />
839.Usando a palavra-chave ENUM em C++<br />
841.Alocando memória com new<br />
843.Testando a falta de espaço livre<br />
864.Compreendendo a Sobrecarga<br />
865. Sobrecaregando as funções<br />
<br />
- http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-096-introduction-to-c-january-iap-2011/assignments/ Curso aberto com diversas apostilas com exercícios e soluções.<br />
<br />
Bibliografia:<br />
<br />
- http://www.tiexpert.net/programacao/c São bastante instrutivos e didáticos, porém, sem exercícios.<br />
<br />
- http://norton.net.br/wordpress/wp-content/uploads/2014/08/apostilacpp.pdf Todos os tópicos possuem exemplos e exercícios baseados nos exemplos.<br />
<br />
- http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf Bem didática com exemplos e exercícios.<br />
<br />
- http://www.inf.pucrs.br/~pinho/PRGSWB/Apoio/Excecoes/Excecoes.html<br />
<br />
- http://www.inf.ufrgs.br/pet/cursos/C++%202009/apostila.pdf <br />
<br />
- http://dcm.ffclrp.usp.br/~augusto/teaching/ici/Arquivos-Texto-CPP.pdf<br />
<br />
- http://www.pontov.com.br/files/cpp/roadmapcpp/ApostilaProgramacaoCppv045.pdf<br />
<br />
- http://www.cplusplus.com/forum/articles/12974/ Lista de exercícios. Está em inglês porém detalha quais requisitos para resolvê-los.<br />
<br />
- https://en.wikibooks.org/wiki/C%2B%2B_Programming/Exercises Wiki em construção, possui alguns exercícios.<br />
<br />
- Programando em C, C++, 'A Bíblia'. Kris Jams, Lars Klander.<br />
<br />
- http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-096-introduction-to-c-january-iap-2011/<br />
--><br />
<br />
= Introdução =<br />
<br />
A linguagem de programação C++ estende a linguagem C, de forma a aderir ao paradigma de orientação a objetos. Com isso, a linguagem oferece construções que possibilitam a expressão de programas modelados segundo uma análise orientada a objetos. A linguagem se apresenta como um superconjunto da linguagem C, o que significa que um programa em C pode ser visto também como um programa C++, mas não o contrário. <br />
<br />
Este primeiro exemplo apresenta o clássico programa de demonstração ''hello world'' escrito em C++:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
cout << "Hello world !" << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
Para compilar este exemplo, deve-se gravá-lo em um arquivo com extensão '''.cc''' ou '''.cpp'''. O compilador C++ disponível no Linux se chama [http://manpages.ubuntu.com/manpages/trusty/man1/gcc.1.html g++], sendo da mesma família de compiladores do [http://manpages.ubuntu.com/manpages/trusty/man1/gcc.1.html gcc]. Supondo que o nome do arquivo seja ''hello.cc'', pode-se compilá-lo assim:<br />
<br />
<syntaxhighlight lang=bash><br />
g++ -o hello hello.cc<br />
</syntaxhighlight><br />
<br />
O comando acima deve gerar um arquivo executável chamado ''hello''. Para executá-lo, faça o seguinte:<br />
<br />
<syntaxhighlight lang=bash><br />
./hello<br />
</syntaxhighlight><br />
<br />
O exemplo acima pode ser estendido para mostrar como ler dados do teclado:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <stdio.h><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int x;<br />
<br />
cout << "Hello world !" << endl;<br />
cout << "x: ";<br />
cin >> x;<br />
cout << "Voce digitou " << x << endl; <br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
== Organização de código-fonte ==<br />
<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/source_code_organization.pdf Capítulo 15 do livro ''C: A Modern Approach, 2n ed., de K. N. King'']<br />
<br />
<br />
Programas em linguagens C e C++ são usualmente organizados em um conjunto de arquivos de código-fonte de dois tipos:<br />
* '''Arquivos de cabeçalho (extensão .h):''' nesse tipo de arquivo se escrevem declarações necessárias em outros arquivos de código-fonte. Essas declarações incluem tipos de dados, [https://en.wikipedia.org/wiki/Function_prototype protótipos de funções], [[Introdução_C%2B%2B#Declara.C3.A7.C3.A3o_de_classes|classes]] e [[Introdução_C%2B%2B#Templates|templates]], variáveis globais e [http://www.cplusplus.com/doc/tutorial/preprocessor/ macros]. Com exceção de templates e macros, nesses arquivos não se escrevem implementações (corpos de funções e métodos).<br />
* '''Arquivos de implementação (extensão .cpp, .cc ou .c):''' nesses arquivos se escrevem as implementações de funções e métodos de classes. Arquivos de cabeçalhos podem ser incluídos com a diretiva [http://www.cplusplus.com/doc/tutorial/preprocessor/#include #include] para obter declarações necessárias à implementação.<br />
<br />
== Argumentos de linha de comando ==<br />
<br />
* [[Argparse|Argparse: um exemplo de uma biblioteca para facilitar o processamento de argumentos de linha de comando]]<br />
<br />
<br />
Argumentos de linha de comando são dados passados a um programa no momento de sua execução. Na época em que a linguagem C foi inventada, e quando então os sistemas Unix se popularizaram, a interface com usuários era em modo texto. Usuários interagiam com o sistema operacional por meio de um programa chamado de '''interpretador de comandos''', ou simplesmente [https://en.wikipedia.org/wiki/Shell_(computing) shell]. Para um usuário executar um programa, ele deveria digitar o nome desse programa no prompt do ''shell'' e pressionar a tecla ENTER (ou RETURN). Cabia então ao ''shell'' ordenar ao sistema operacional que o arquivo de programa solicitado fosse executado. Além do nome do programa, um usuário poderia opcionalmente especificar um ou mais argumentos, que são strings a serem passadas ao programa no momento de sua execução. Os dois exemplos a seguir mostram a execução do programa [http://manpages.ubuntu.com/manpages/bionic/man1/ls.1.html ls] por meio de um ''shell''.<br />
<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@M1:$ ls<br />
Área de trabalho Downloads Modelos Público Vídeos<br />
Documentos Imagens Música teste.sh<br />
aluno@M1:$<br />
</syntaxhighlight><br />
Execução do programa ''ls'' sem argumentos de linha de comando. O prompt do shell é a string ''aluno@M1:$''.<br />
<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@M1:$ ls -l<br />
total 48<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Área de trabalho<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Documentos<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Downloads<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Imagens<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Modelos<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Música<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Público<br />
-rw-r--r-- 1 aluno aluno 14076 abr 12 2018 teste.sh<br />
drwxr-xr-x 2 aluno aluno 4096 abr 12 2018 Vídeos<br />
aluno@M1:$<br />
</syntaxhighlight><br />
Execução do programa ''ls'' com um argumento de linha de comando (a string ''-l''). Cabe ao programa ''ls'' interpretar esse argumento, e usá-lo para desempenhar sua funcionalidade.<br />
<br />
<br />
Do ponto de vista do programador, os argumentos de linha de comando são acessíveis por meio de dois parâmetros da função ''main'', os quais são tradicionalmente denominados:<br />
* '''argc''': um número inteiro que informa quantos argumentos de linha de comando foram passados ao programa. Esse parâmetro tem no mínimo o valor 1 (um), pois o próprio nome do programa é considerado seu primeiro argumento.<br />
* '''argv''': um vetor de strings que contém os argumentos. A primeira string desse vetor é sempre o próprio nome do programa. A posição no vetor em seguida ao último argumento contém o ponteiro NULL.<br />
<br />
<br />
O programa C a seguir mostra como esses parâmetros são especificados na função ''main'', e como podem ser usados. Neste exemplo, apresentam-se na tela todos os argumentos de linha de comando (um por linha), na ordem em que foram passados ao programa.<br />
<br />
<syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main(int argc, char * argv[]) {<br />
int n;<br />
<br />
for (n=0; n < argc; n++) {<br />
printf("argv[%d]=%s\n", n, argv[n]);<br />
}<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
A versão em C++ desse exemplo é praticamente idêntica, mudando somente a forma com que os dados são mostrados na tela.<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(int argc, char * argv[]) {<br />
int n;<br />
<br />
for (n=0; n < argc; n++) {<br />
cout << "argv[" << n << "]=" << argv[n] << endl;<br />
}<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Apesar de hoje em dia as interfaces de usuário em modo texto serem menos usadas, o modelo de execução de programas continua o mesmo. Mesmo programas gráficos se valem de argumentos de linha de comando para modularem a forma com que devem funcionar (ver, por exemplo, o [http://manpages.ubuntu.com/manpages/bionic/man1/firefox.1.html manual do firefox]). Independente do tipo de interface de usuário, argumentos de linha de comando são de grande utilidade para passar informação a programas quando forem executados.<br />
<br />
= Classes e objetos =<br />
<br />
A linguagem C foi projetada segundo um paradigma de programação chamado de [https://en.wikipedia.org/wiki/Structured_programming programação estruturada]. Essa forma de expressar programas se baseia em subrotinas (funções no caso da linguagem C), blocos de instruções e laços de repetição, os quais atuam sobre variáveis que contêm os dados a serem acessados e transformados. O que se deve notar é a forma com que se costuma modelar um programa nesse caso, dando-se ênfase aos algoritmos que modificam os dados. Não é à toa que uma ferramenta de modelagem tradicional e ainda muito usada seja o fluxograma. Porém existem outras formas de pensar os problemas a serem resolvidos e expressar programas, dentre elas o [https://en.wikipedia.org/wiki/Object-oriented_programming paradigma de orientação a objetos] seguido por diversas linguagens tais como C++, Java e Python.<br />
<br />
<br />
Um programa orientado a objetos é composto por objetos que interagem. Um objeto é uma abstração que representa uma ''coisa'' que faz parte do problema a ser resolvido. Um objeto contém dados que representam seu estado (chamados de ''atributos''), e procedimentos que representam seu comportamento (chamados de ''métodos''). No caso do exemplo dos horários, um horário pode ser representado por um objeto. O estado desse objeto ''Horario'' é definido pelos valores de ''hora'', ''minuto'' e ''segundo'', e seu comportamento é dado pelos métodos ''mostreSe'' e ''acrescenta''. Isso deve ser entendido da seguinte forma: um ''objeto 'Horario'' pode ser mostrado, ao se chamar seu método 'mostreSe'', e pode ser somado a outro objeto ''Horario'', ao se chamar seu método ''acrescenta''. Essas são as únicas operações definidas para esse objeto, e assim nada mais se consegue fazer com ele ... a não ser que se definam novas operações.<br />
<br />
<br />
Muitos objetos similares podem existir. Por exemplo, pode haver muitos diferentes objetos ''Horario'', que se diferenciam por seus estados (valores de ''hora'', ''minuto'' e ''segundo''). Todos os objetos cujos estados são definidos pelo mesmo conjunto de atributos, e que possuem o mesmo comportamento (conjunto de métodos), pertencem à mesma '''classe'''. O conceito de classe é semelhante ao de ''tipo de dados'', porém tem uma implicação mais profunda. Um ''tipo de dados'' define como o conteúdo de uma variável deve ser interpretado (ex: um número inteiro, ponto flutuante, uma string, ...), porém não define os procedimentos que podem manipular essas variáveis. Desta forma, uma ''classe'' vincula a seus objetos os algoritmos que atuam sobre eles. Isso tem uma importante implicação no [http://effectivesoftwaredesign.com/2012/02/05/separation-of-concerns/ acoplamento e coesão de um programa], que são métricas fundamentais de qualidade de um projeto de software modular.<br />
<br />
<br />
<br />
== Declaração de classes ==<br />
<br />
Uma classe é declarada usando-se a palavra-chave ''class'' seguida do nome da classe:<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
// declarações internas da classe<br />
};<br />
</syntaxhighlight><br />
<br />
De certa forma, isso se assemelha à declaração de ''struct''. No entanto, as declarações internas da classe têm um significado um pouco diferente. Por exemplo, suponha-se que a classe ''MinhaClasse'' represente um número de telefone, incluindo seu código de área. A declaração seria estendida desta forma:<br />
<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// declarações dos procedimentos da classe<br />
};<br />
</syntaxhighlight><br />
<br />
A classe agora possui dois atributos:<br />
* ''string numero'': armazena o número de telefone<br />
* ''string ddd'': armazena o código DDD<br />
<br />
No exemplo, as declarações desses atributos na classe são precedidas pela cláusula ''private:''. Isso significa que esses atributos não podem ser acessados diretamente de fora da classe (por procedimentos implementados fora da classe). Logo após a declaração desses atributos, aparece a cláusula ''public:''. Ela define que o que for declarado em seguida pode ser acessado diretamente de fora da classe. Por exemplo, os métodos da classe podem ser declarados logo após ''public:''.<br />
<br />
<br />
<syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// Construtor: executado quando se cria um objeto desta classe<br />
MinhaClasse(string umNumero, string umDDD);<br />
<br />
// Destrutor: executado quando se destrói um objeto desta classe<br />
~MinhaClasse();<br />
<br />
// métodos para acessar os valores dos atributos<br />
string obtemNumero();<br />
string obtemDDD();<br />
string obtemNumeroDDD();<br />
};<br />
</syntaxhighlight><br />
<br />
Um ''método'' é uma função que pertence a uma classe. A idéia é que um objeto de uma classe possui um estado dado pelos valores de seus atributos, e somente os métodos daquela classe podem acessar ou modificar esse estado. Quer dizer, somente métodos da classe podem acessar diretamente esses atributos. Dois métodos são especiais:<br />
*''construtor'': este método é executado sempre que se cria um objeto de uma classe. Ele tem por finalidade iniciar o estado daquele objeto. Isso envolve definir os valores iniciais dos atributos, e conferir se os parâmetros que porventura tenham sido passados são válidos (ex: se o número tem somente caracteres numéricos).<br />
* ''destrutor'': este método é executado quando um objeto é destruído. Ele é responsável por limpar o estado desse objeto, desfazendo qualquer ação que ele tenha iniciado. Por exemplo, se o objeto alocou memória dinamicamente em algum momento, o destrutor deve liberá-la.<br />
<br />
<br />
A declaração da classe apresentada apenas informa quais métodos ela implementa, mas não mostra como eles são implementados. Essa implementação pode ser feita de duas formas:<br />
* ''inline'': a implementação de um método é feita dentro da própria declaração da classe. Por exemplo, o método ''obtemNumeroDDD'' poderia estar implementado assim: <syntaxhighlight lang=c><br />
class MinhaClasse {<br />
private:<br />
string numero;<br />
string ddd;<br />
public:<br />
// Construtor: executado quando se cria um objeto desta classe<br />
MinhaClasse(string umNumero, string umDDD);<br />
<br />
// Destrutor: executado quando se destrói um objeto desta classe<br />
~MinhaClasse();<br />
<br />
// métodos para acessar os valores dos atributos<br />
string obtemNumero();<br />
string obtemDDD();<br />
<br />
// implementação inline<br />
string obtemNumeroDDD() {<br />
string num = ddd + '-' + numero;<br />
return num;<br />
}<br />
};<br />
</syntaxhighlight><br />
* ''fora da classe'': a implementação é feita externamente, possivelmente em outro arquivo. Deve-se declarar a classe a que pertence o método, prefixando seu nome com ''Nome_da_classe::''. No caso de ''obtemNumeroDDD'', isso poderia ser feito assim:<syntaxhighlight lang=c><br />
// deve-se prefixar o nome do método com o nome da classe, para indicar que é um método dessa classe<br />
string MinhaClasse::obtemNumeroDDD() {<br />
string num = ddd + '-' + numero;<br />
return num;<br />
}<br />
</syntaxhighlight><br />
<br />
== Criação de objetos ==<br />
<br />
Uma vez tendo declarado e implementado uma classe, podem-se criar objetos. A isso se chama ''instanciação'', e os objetos também podem ser chamados de ''instâncias''. Objetos podem ser criados diretamente, como se fossem variáveis usuais, como mostrado a seguir:<br />
<br />
<syntaxhighlight lang=c n><br />
#include "minhaclasse.h"<br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string num, ddd;<br />
<br />
cout << "Numero: ";<br />
cin >> num;<br />
cout << "DDD: ";<br />
cin >> ddd;<br />
<br />
// o construtor da classe é chamado quando se cria um objeto<br />
// Aqui, o objeto é dado pela variável "fone"<br />
MinhaClasse fone(num, ddd);<br />
<br />
cout << "Numero com DDD é " << fone.obtemNumeroDDD() << endl;<br />
<br />
// objetos são destruídos automaticamente ao final do escopo em que foram criados<br />
// o destrutor é então executado <br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Objetos podem também ser criados dinamicamente, em que a memória necessária é alocada. Para isso usa-se o operador [http://www.cplusplus.com/reference/new/operator%20new/ new] (e não a função ''malloc'' !). Objetos criados dessa forma são referenciados por ponteiros, e devem ser explicitamente destruídos usando-se o operador [http://www.cplusplus.com/reference/new/operator%20delete/ delete] (e não a função ''free'' !). O exemplo a seguir mostra a criação e destruição de objetos com ''new'' e ''delete'':<br />
<br />
<syntaxhighlight lang=c n><br />
#include "minhaclasse.h"<br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string num, ddd;<br />
// o ponteiro fone é capaz de apontar objetos de MinhaClasse<br />
MinhaClasse * fone;<br />
<br />
cout << "Numero: ";<br />
cin >> num;<br />
cout << "DDD: ";<br />
cin >> ddd;<br />
<br />
// o construtor da classe é chamado quando se cria um objeto com o operador "new"<br />
// Aqui, o objeto é dado pelo ponteiro "fone"<br />
fone = new MinhaClasse(num, ddd);<br />
<br />
cout << "Numero com DDD é " << fone->obtemNumeroDDD() << endl;<br />
<br />
// objetos dinâmico devem ser destruídos explicitamente usando o operador "delete"<br />
// o destrutor é então executado <br />
delete fone;<br />
}<br />
</syntaxhighlight><br />
<br />
=== Invocação do construtor ===<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/classes#member_initialization Inicialização dos atributos de um objeto]<br />
<br />
A criação de um objeto causa a execução do método ''construtor'' da classe. Esse método é responsável por iniciar os valores dos atributos do objeto (chamados de ''variáveis de instância''), tornando-o pronto para ser utilizado. O ''construtor'' recebe os parâmetros passados na criação do objeto (ver linhas 16 do primeiro exemplo e 18 do segundo). No exemplo em questão, o método construtor poderia fazer algo assim:<br />
<br />
<syntaxhighlight lang=c><br />
MinhaClasse::MinhaClasse(string umNumero, string umDDD) {<br />
numero = umNumero;<br />
ddd = umDDD;<br />
}<br />
</syntaxhighlight><br />
<br />
... quer dizer, apenas copiar os valores dos parâmetros para os respectivos atributos. Outra forma de implementar o construtor e iniciar os valores dos atributos é esta:<br />
<br />
<syntaxhighlight lang=c><br />
MinhaClasse::MinhaClasse(string umNumero, string umDDD) : numero(umNumero), ddd(umDDD) {<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Deve-se observar que os atributos são iniciados usando uma sintaxe especial. Logo após o nome do método construtor declara-se uma lista de inicialização de atributos. Essa lista é iniciada com ''':''', seguida dos nomes dos atributos invocados como se fosse outros objetos sendo criados. Na verdade é exatamente isso que acontece nessa forma de iniciar os atributos: eles são criados como objetos que fazem parte do objeto criado. Essa forma de iniciar atributos é imprescindível quando uma classe possui um ou mais atributos que são de fato objetos de alguma classe, e que precisam receber parâmetros ao serem criados.<br />
<br />
== Destruição de objetos ==<br />
<br />
A destruição de um objeto ocorre em duas situações:<br />
# '''Quando se chega ao fim o escopo dentro do qual o objeto foi criado:''' isso vale para objetos declarados e instanciados diretamente. Ex: <syntaxhighlight lang=c><br />
void ecoa() {<br />
string palavra; // aqui se cria um objeto string<br />
<br />
cout << "Digite uma palavra: ";<br />
cin >> palavra;<br />
cout << "Você digitou: " << palavra << endl;<br />
} // fim do escopo ... o objeto string "palavra" é destruido automaticamente<br />
</syntaxhighlight><br />
# '''Quando se destroi o objeto com o operador [http://www.cplusplus.com/reference/new/operator%20delete/ delete]:''' isso vale somente para objetos criados dinamicamente com o operador [http://www.cplusplus.com/reference/new/operator%20new/ new]. Ex: <syntaxhighlight lang=c><br />
void ecoa() {<br />
string * palavra; // aqui se declara um ponteiro para string<br />
<br />
palavra = new string; // aqui se cria dinamicamente um objeto string<br />
cout << "Digite uma palavra: ";<br />
cin >> *palavra;<br />
cout << "Você digitou: " << *palavra << endl;<br />
<br />
delete palavra; // aqui se destroi o objeto string<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
A destruição de um objeto implica liberar as áreas de memória a ele alocadas dinamicamente em sua criação, ou durante seu tempo de vida. Essa faxina deve ser feita pelo método destrutor da classe (chamado simplesmente de [http://www.cplusplus.com/doc/tutorial/classes2/#destructor ''destructor'']). Tal método é declarado da seguinte forma em uma classe:<br />
<br />
<syntaxhighlight lang=c><br />
classe Demo {<br />
public:<br />
Demo(); // constructor da classe<br />
~Demo(); // destructor da classe<br />
<br />
// demais métodos da classe<br />
};<br />
<br />
// implementação do destructor<br />
Demo::~Demo() { <br />
// limpeza do objeto<br />
}<br />
</syntaxhighlight><br />
<br />
A implementação desse método deve ser responsável pela limpeza do objeto. Apenas áreas de memória alocadas dinamicamente precisam ser liberadas. O exemplo a seguir mostra uma classe com memória alocada dinamicamente:<br />
<br />
<syntaxhighlight lang=c><br />
classe Demo {<br />
public:<br />
Demo(const string & name); // constructor da classe<br />
~Demo(); // destructor da classe<br />
<br />
// demais métodos da classe<br />
private:<br />
// atributos privativos da classe<br />
string nome;<br />
char * buffer;<br />
};<br />
<br />
// implementação do constructor<br />
Demo::Demo(const string & name) { <br />
nome = name;<br />
buffer = new char[1024]; // aloca dinamicamente 1kB<br />
}<br />
<br />
// implementação do destructor<br />
Demo::~Demo() { <br />
// libera a área de memória alocada no constructor<br />
delete buffer;<br />
}<br />
</syntaxhighlight><br />
<br />
== Um exemplo ==<br />
<br />
O exemplo abaixo pode esclarecer melhor os conceitos de classe e objeto. Ele declara uma classe ''Vetor'', que representa vetores bidimensionais. As operações sobre tais objetos são: módulo, produto escalar, subtração e escrita em um arquivo. Veja como pode ser escrita essa classe.<br />
<br />
<syntaxhighlight lang=c><br />
// a classe Vetor define objetos que representam vetores bidimensionais<br />
class Vetor {<br />
private: // as declarações abaixo são privativas (podem ser acessadas somente dentro da classe)<br />
<br />
double x, y;<br />
<br />
public: // as declarações abaixo são públicas, podendo ser acessadas de fora da classe<br />
<br />
// construtor da classe: um método especial que cria objetos desta classe<br />
Vetor(double px, double py) {<br />
// inicia o estado de um objeto<br />
x = px;<br />
y = py;<br />
}<br />
<br />
// destrutor da classe: um método especial que destrói objetos desta classe<br />
~Vetor() {} // nada demais precisa ser feito<br />
<br />
// este método retorna o módulo do vetor<br />
double modulo() {<br />
return sqrt(x*x + y*y);<br />
}<br />
<br />
// este método retorna o produto escalar deste vetor com outro vetor<br />
double produto_escalar(const Vetor & outro) {<br />
return x*outro.x + y*outro.y;<br />
}<br />
<br />
// este método calcula a soma entre este e outro vetor (este + outro),<br />
// retornando um novo vetor como resultado<br />
Vetor adicione(const Vetor & outro) {<br />
Vetor novo(x+outro.x, y+outro.y);<br />
<br />
return novo;<br />
}<br />
<br />
// este método calcula a diferença entre este e outro vetor (este - outro),<br />
// retornando um novo vetor como resultado<br />
Vetor subtraia(const Vetor & outro) {<br />
Vetor novo(x-outro.x, y-outro.y);<br />
<br />
return novo;<br />
}<br />
<br />
// este método escreve uma representação do objeto no arquivo "out"<br />
// (que é um objeto da classe ostream)<br />
void mostreSe(ostream & out) {<br />
out << "(";<br />
out << x;<br />
out << ", ";<br />
out << y;<br />
out << ")";<br />
}<br />
<br />
};<br />
</syntaxhighlight><br />
<br />
Uma vez existindo a classe ''Vetor'', pode-se escrever um programa que use objetos dessa classe. No exemplo abaixo, calcula-se o vetor resultante de dois outros vetores:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
int x, y;<br />
<br />
cout << "Coordenada X do vetor 1: ";<br />
cin >> x;<br />
cout << "Coordenada Y do vetor 1: ";<br />
cin >> y;<br />
cout << endl;<br />
<br />
// Aqui se cria o primeiro objeto Vetor<br />
Vetor v1(x, y);<br />
<br />
cout << "Coordenada X do vetor 2: ";<br />
// Aqui se lê pela entrada padrão a coordenada X<br />
cin >> x;<br />
cout << "Coordenada Y do vetor 2: ";<br />
// Aqui se lê pela entrada padrão a coordenada Y<br />
cin >> y;<br />
cout << endl;<br />
<br />
// Aqui se cria o segundo objeto Vetor<br />
Vetor v2(x, y);<br />
<br />
// Aqui se obtém a resultante dos vetores v1 e v2. Note como a operação "adicione"<br />
// do objeto "v1" é chamada.<br />
Vetor v3 = v1.adicione(v2);<br />
<br />
cout << "Vetor resultante: ";<br />
// Aqui se escreve uma representação de "v3" na tela. "cout" é um objeto da biblioteca C++ padrão<br />
// que representa a saída padrão de um processo. A saída padrão funciona como um arquivo. O objeto <br />
// "cout" é similar ao "stdout" da linguagem C.<br />
v3.mostreSe(cout);<br />
cout << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
O programa em si se apresenta como um pequeno algoritmo que lê pela entrada padrão valores de coordenadas e cria os respectivos vetores (''v1'' e ''v2''), calculando sua resultante a apresentando na saída padrão o novo vetor (''v3''). <br />
<br />
<br />
Além das regras de escrita da linguagem, o que se denomina ''sintaxe'', ressalta-se o uso dos objetos feito no programa. O pequeno programa criado trata de calcular a resultante de dois vetores bidimensionais. As ''coisas'' a serem diretamente manipuladas pelo programa são os vetores, sendo estes representado por objetos. Outros objetos usados são os arquivos que representam a entrada e saída padrão do programa (respectivamente ''cin'' e ''cout''). O programa '''usa''' os objetos da classe ''Vetor'', explorando as operações que eles oferecem. Assim, a declaração da classe ''Vetor'' se preocupa em definir o que é um objeto Vetor (seus atributos) e o que ele é capaz de fazer (seu comportamento). Já o programa apenas utiliza esses objetos.<br />
<br />
== O ponteiro predefinido ''this'' ==<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/templates/ Ver seção ''the keyword this'' neste documento]<br />
<br />
<br />
Ao se implementarem métodos de uma classe pode-se usar uma variável predefinida chamada ''this'', que é um ponteiro para o objeto no escopo do qual se executa um método. Sempre que dentro de um método for necessário eliminar uma ambiguidade quanto ao uso de um atributo do objeto, ou por clareza, pode-se usar esse ponteiro ''this''. O exemplo a seguir ilustra o uso de ''this''.<br />
<br />
<syntaxhighlight lang=c><br />
class Coisa {<br />
public:<br />
Coisa(int x, int y);<br />
~Coisa() {}<br />
// outros métodos da classe ...<br />
private:<br />
// os atributos dos objetos desta classe<br />
int x,y;<br />
};<br />
<br />
// construtor da classe Coisa: os parâmetros "x" e "y" são usados para iniciar os <br />
// atributos "x" e "y". Para resolver a ambiguidade entre parâmetros e atributos, dentro do construtor<br />
// se usa o ponteiro "this"<br />
Coisa::Coisa(int x, int y) {<br />
this->x = x;<br />
this->y = y;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Existem outros casos em que o ponteiro ''this'' tem utilidade. Um exemplo pode ser visto na [[Introdu%C3%A7%C3%A3o_C%2B%2B#Construtor_de_c.C3.B3pia|seção sobre construtor de cópia]].<br />
<br />
== Operador de atribuição ==<br />
<br />
Em C++ pode-se definir como um operador específico atua sobre um objeto. Operadores típicos são: ''='' (atribuição), ''+'' (adição), ''-'' (subtração), e [http://www.cplusplus.com/doc/tutorial/operators/ outros]. Um operador é definido por uma função ou método que implementa sua operação. No caso da Fila, um operador útil é o de atribuição, pois pode ser usado para que uma fila existente seja modificada para se tornar idêntica a outra fila. Supondo que esse operador tenha sido implementado, o exemplo a seguir mostra a fila ''f1'' sendo atribuída a ''f2'' (linha 19), a qual já existe e tem inclusive dados armazenados, e demonstra em seguida como ficou o conteúdo de ''f2''.<br />
<br />
<br />
<syntaxhighlight lang=c n><br />
#include <iostream><br />
#include "fila.h"<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
Fila f1(5);<br />
Fila f2(7);<br />
<br />
f1.enfileira(2);<br />
f1.enfileira(7);<br />
f1.enfileira(4);<br />
<br />
f2.enfileira(3);<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
f2 = f1; // atribui f1 a f2 ... f2 torna-se uma cópia de f1<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
while (not f1.vazia()) cout << "Desenfileirou de f1: " << f1.desenfileira() << endl;<br />
<br />
cout << "Comprimento de f1: " << f1.comprimento() << endl;<br />
cout << "Comprimento de f2: " << f2.comprimento() << endl;<br />
<br />
while (not f2.vazia()) cout << "Desenfileirou de f2: " << f2.desenfileira() << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O operador de atribuição da fila pode ser declarado como mostrado abaixo:<br />
<br />
<syntaxhighlight lang=c><br />
class Fila {<br />
public:<br />
Fila(int umaCapacidade); // cria uma fila capaz de guardar "capacidade" elementos<br />
Fila(const Fila & outra);<br />
~Fila(); // destroi a fila<br />
Fila& operator=( const Fila& outra ); // OPERADOR DE ATRIBUIÇÃO<br />
// demais declarações da Fila ...<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Como se pode notar, sua declaração é muito parecida com a de um método qualquer da classe. A palavra-chave ''operator'' indica tratar-se de um método de operador, e o símbolo que aparece logo em seguida indica o operador a ser redefinido (no caso, ''=''). O único parâmetro a ser passado é o objeto a ser copiado (no caso, uma Fila). O valor retornado é uma referência ao próprio objeto que foi o destino da atribuição (aquele que foi modificado). A implementação desse método segue as regras usadas nos demais métodos:<br />
<br />
<syntaxhighlight lang=c><br />
Fila& Fila::operator=( const Fila& outra ) {<br />
// desalocar a memória de "buffer"<br />
// copiar os valores de atributos de "outra"<br />
// alocar memória para "buffer"<br />
// copiar conteúdo da "buffer" da "outra" fila<br />
<br />
// retorna uma referência ao próprio objeto <br />
return *this;<br />
}<br />
</syntaxhighlight><br />
''A implementação do método do operador de atribuição em fila.cpp''<br />
<br />
== Construtor de cópia ==<br />
<br />
Um [http://www.cplusplus.com/articles/y8hv0pDG/ construtor de cópia] é um método construtor para criar um objeto que é uma cópia idêntica a um objeto existente. Esse tipo de criação de objeto aparece em casos como este:<br />
<br />
<syntaxhighlight lang=c><br />
Fila<int> f1(10); // cria uma fila capaz de guardar 10 números inteiros<br />
<br />
f1.enfileira(5);<br />
f1.enfileira(8);<br />
f1.enfileira(2);<br />
f1.enfileira(4);<br />
<br />
Fila<int> f2 = f1; // cria a fila f2, que é uma cópia idêntica de f1<br />
<br />
f1.esvazia(); // esvazia a fila f1<br />
<br />
// Mostra o conteúdo da fila f2: deve ser igual ao que existia em f1<br />
while (not f2.vazia()) {<br />
cout << f2.desenfileira() << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
Para que o exemplo acima funcione, a classe Fila deve implementar seu construtor de cópia:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
public:<br />
// construtor de cópia: o objeto criado deve ser idêntico ao objeto "outra"<br />
Fila(const Fila<T> & outra);<br />
<br />
// demais declarações da Fila ...<br />
};<br />
</syntaxhighlight><br />
<br />
O construtor de cópia deve ser responsável por copiar o estado do ''objeto copiado'', de forma que o objeto criado seja idêntico a ele. Isso envolve copiar os valores dos atributos desses objetos, porém em certos casos isso não é suficiente. Se o objeto copiado tiver como atributos outros objetos ou variáveis criados dinamicamente, então o novo objeto deve também criar dinamicamente cópias desses objetos ou variáveis. <br />
<br />
<br />
Deve-se observar que um construtor de cópia é muito parecido com um operador de atribuição. A diferença reside no fato de que uma atribuição ocorre entre dois objetos já existentes. Por isso um objeto que recebe uma atribuição deve primeiro limpar seu estado (se necessário, o que envolve destruir eventuais objetos e variáveis dinâmicos) para depois se tornar uma cópia do outro objeto. Apesar disso, se um operador de atribuição já existir ele pode ser usado para facilmente implementar um construtor de cópia. O exemplo a seguir mostra como isso pode ser feito para a Fila:<br />
<br />
<syntaxhighlight lang=c><br />
// implementação do construtor de cópia<br />
template <typename T> Fila<T>::Fila(const Fila<T> & outra) {<br />
// primeiro devem-se atribuir valores aos atributos desta Fila <br />
// para que ela pareça vazia<br />
<br />
// em seguida, basta atribuir a "outra" Fila a este objeto<br />
// Note o uso do ponteiro predefinido "this", que sempre aponta o objeto que recebe a operação<br />
// dentro de um método de sua classe<br />
*this = outra;<br />
}<br />
</syntaxhighlight><br />
<br />
== Templates ==<br />
<br />
* [http://www.cprogramming.com/tutorial/templates.html Template classes C++]<br />
* [http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part An Idiot's Guide to C++ Templates]<br />
* [http://br.ccm.net/faq/10140-os-templates-em-c Os templates em C++]<br />
<br />
<br />
''Templates'' possibilitam a parametrização de tipos em C++. Com isso, podem-se escrever funções, structs e classes que referenciam ou armazenam dados cujos tipos sejam desconhecidos de antemão. Esses tipos são denominados ''tipos genéricos''. No nosso caso, isso será usado para generalizar as estruturas de dados a serem criadas, para que elas possam armazenar qualquer tipo de dado. Na explicação a seguir, usa-se a estrutura de dados ''Fila'' como exemplo.<br />
<br />
<br />
A declaração de uma classe template inicia com o prefixo ''template <typename T>''. A cláusula ''<typename T>'' serve para especificar um identificador para o tipo genérico a ser usado dentro da classe (no exemplo, escolheu-se o identificador ''T'', mas pode ser qualquer outra coisa). No caso da ''Fila'', deseja-se torná-la capaz de guardar qualquer tipo de dado. Quer dizer, seu funcionamento não depende do que ela estiver armazenando, portanto o tipo do dado armazenado pode ser generalizado. Esse é um bom exemplo de uso de classe template, estando exemplificado a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
<br />
// declarações de atributos e métodos da classe<br />
<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Todas as referências ao tipo genérico devem ser escritas usando o identificador especificado (no caso, ''T''). Aproveitando o exemplo da ''Fila'', deve-se observar que o atributo ''buffer'' depende do tipo genérico, pois trata-se de um vetor onde devem ser armazenados os dados enfileirados. Os métodos ''enfileira'', ''desenfileira'' e ''frente'' também dependem do tipo genérico. A declaração da classe template ''Fila'' segue abaixo, porém com alguns detalhes omitidos para ficar mais evidente o uso de template.<br />
<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
public:<br />
Fila(unsigned int N);<br />
~Fila();<br />
<br />
// enfileira um dado do tipo T<br />
void enfileira(const T & algo);<br />
<br />
// desenfileira um dado da frente da fila, e retorna uma <br />
// cópia desse dado (cujo tipo é T)<br />
T desenfileira();<br />
<br />
// Retorna uma referência ao dado de tipo T que está na frente da fila<br />
T & frente() const;<br />
<br />
bool vazia() const {return itens == 0; }<br />
bool cheia() const { return itens == capacidade;}<br />
unsigned int tamanho() const { return itens;}<br />
private:<br />
int capacidade;<br />
int itens, inicio, fim;<br />
T* buffer; // área de memória para guardar os dados de tipo T enfileirados<br />
};<br />
</syntaxhighlight><br />
<br />
<br />
Quando se declara uma classe template, tanto a declaração da classe (sua interface) quanto a implementação de seus métodos devem estar no mesmo arquivo com extensão ''.h''. Isso se deve a [http://stackoverflow.com/questions/19798325/template-compilation detalhes específicos da compilação do código-fonte]. Assim, a implementação dos métodos pode estar dentro da própria declaração da classe, como no caso dos métodos ''vazia'', ''cheia'' e ''tamanho'', ou fora da classe. Quando forem implementados fora da classe, deve-se repetir o prefixo ''template <typename T>'' na frente do nome de cada método, como mostrado a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> void Fila<T>::enfileira(const T& algo) {<br />
// implementação do método<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Uma vez declarada uma classe template, ela pode ser utilizada. Somente no momento em que uma classe é usada que o tipo genérico é especificado. Por exemplo, a ''Fila'' acima declarada pode guardar qualquer coisa, o que inclui strings e números inteiros. Para declarar duas filas, de forma que uma armazene inteiros e outra strings, deve-se usar esta sintaxe:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
// Uma fila capaz de guardar até 10 números inteiros<br />
Fila<int> f1(10);<br />
<br />
// uma fila capaz de guardar até 5 strings<br />
Fila<string> f2(5);<br />
<br />
// enfileira-se o número 23 na fila de inteiros<br />
f1.enfileira(23);<br />
<br />
// enfileira-se a string "uma coisa" na fila de strings<br />
string algo = "uma coisa";<br />
f2.enfileira(algo);<br />
<br />
// outras declarações da função main ...<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Do ponto de vista da linguagem, um ''template'' define um padrão de geração de código para o compilador ([http://stackoverflow.com/questions/19798325/template-compilation maiores detalhes]). Quer dizer, um ''template'' em si não é compilável, pois ele representa código-fonte ainda incompleto. No entanto, no momento em que se usa um ''template'', o código-fonte é completado e pode ser compilado. Em outras palavras, o ''template'' da Fila se torna uma Fila de fato. O programa de teste abaixo aproveita o exemplo das filas, enfileirando e desenfileirando dados de duas filas. <br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include "fila.h"<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
// Uma fila de strings<br />
Fila<string> fila1(10);<br />
<br />
// Uma fila de inteiros<br />
Fila<int> fila2(10);<br />
<br />
// Armazena três strings na fila de strings<br />
for (int x=0; x < 3; x++) {<br />
string palavra;<br />
<br />
cout << "Digite uma palavra: ";<br />
cin >> palavra;<br />
fila1.enfileira(palavra);<br />
}<br />
<br />
// Armazena alguns números na fila de inteiros<br />
for(int x=0; x < 8; x += 1) lista2.enfileira(x);<br />
<br />
// Mostra os dados da fila de strings<br />
while (not fila1.vazia()) {<br />
cout << "desenfileirou: " << fila1.desenfileira() << endl;<br />
}<br />
<br />
// Mostra os dados da fila de inteiros<br />
while (not fila2.vazia()) {<br />
cout << "desenfileirou: " << fila2.desenfileira() << endl;<br />
}<br />
<br />
}<br />
</syntaxhighlight><br />
<br />
= Passagem de parâmetros =<br />
<br />
* [https://pt.stackoverflow.com/questions/59437/qual-a-diferen%C3%A7a-entre-passagem-por-valor-e-passagem-por-refer%C3%AAncia Uma boa explicação no forum Stack Overflow]<br />
<br />
A passagem de parâmetros em C++ pode ser feita de duas maneiras:<br />
# '''[http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#by_value Por valor]''': o parâmetro recebe uma cópia do valor que foi passado. Se o parâmetro for alterado dentro da função, o valor original não é modificado.<br />
# '''[http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#by_reference Por referência]''': o parâmetro é uma referência ao valor que foi passado. Se o parâmetro for alterado, o valor original também será modificado.<br />
<br />
'''OBS:''' o caso de um parâmetro passado por ponteiro funciona da mesma forma que em C. No caso, se o o valor apontado pelo ponteiro for alterado dentro da função, o valor original será modificado. Isso funciona de forma parecida com a passagem de parâmetro por referência, apesar de haver uma diferença sutil.<br />
<br />
Os exemplos a seguir ilustram ambas formas de passagem de parâmetros:<br />
{|border=1<br />
!Passagem por valor<br />
!Passagem por referência<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(int x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
// passagem por referência: observe o operador & <br />
// antes do nome do parâmetro<br />
int incrementa(int & x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br><br><br />
<br />
É possível também a passagem de parâmetros por referência, porém [http://en.wikibooks.org/wiki/C%2B%2B_Programming/Code/Statements/Functions#Constant_Parameters somente-leitura]. A utilidade disso é aproveitar a eficiência da passagem de parâmetro por referência, que evita uma cópia de valor, porém evitando que o valor original seja modificado dentro da função. Exemplo (experimente compilar estes programas):<br />
{|border=1<br />
!Programa 1<br />
!Programa 2<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(const int & x) {<br />
x++;<br />
return x;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int incrementa(const int & x) {<br />
int y = x;<br />
<br />
y++;<br />
return y;<br />
}<br />
<br />
int main() {<br />
int valor = 10;<br />
int resultado;<br />
<br />
resultado = incrementa(valor);<br />
cout << "Resultado=" << resultado;<br />
cout << ", e valor=" << valor << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
= Alocação dinâmica de memória: operadores new e delete =<br />
<br />
A alocação dinâmica de memória é uma técnica para reservar e liberar memória por demanda, e sob controle do programador. Ela funciona como se o programador criasse variáveis, porém tivesse que explicitamente destrui-las. Assim, as variáveis não deixariam de existir automaticamente, quando a execução do programa saísse do escopo em que foram criadas.<br />
<br />
A alocação dinâmica está diretamente relacionada com variáveis do tipo ponteiro. Ao se alocar memória dinamicamente, obtém-se o endereço inicial da área de memória obtida, e esse endereço deve ser armazenado em um ponteiro. O uso dessa área de memória, portanto, se faz por meio desse ponteiro.<br />
<br />
A alocação dinâmica de memória na linguagem C++ se faz com o [http://www.cplusplus.com/reference/new/operator%20new/ operador new]. Esse operador aloca memória de acordo com o tipo de dados informado, e retorna um ponteiro para essa área de memória. Quando essa área de memória não for mais necessária, ela deve ser liberada com o [http://www.cplusplus.com/reference/new/operator%20delete/ operador delete]. Veja o exemplo a seguir, que mostra o uso dos operadores ''new'' e ''delete'' em uma situação muito simplificada.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
template <typename T> void mostra(const string & varname, T * val) {<br />
cout << "######################################################" << endl;<br />
cout << "Dado apontado por " << varname << " = " << *val << endl;<br />
cout << "Endereço da área de memória usada por " << varname << ": " << (void*)val << endl;<br />
cout << "Memória alocada: " << sizeof(*val) << " bytes" << endl;<br />
}<br />
<br />
int main() {<br />
// algumas variáveis<br />
// a memória para elas é alocada automaticamente<br />
int * x;<br />
double * h;<br />
<br />
// aloca dinamicamente memória para um valor do tipo int<br />
x = new int;<br />
<br />
// aloca dinamicamente memória para um valor do tipo double<br />
h = new double;<br />
<br />
// armazena valores nas áreas de memória alocadas, usando-se<br />
// os ponteiros<br />
*x = 35;<br />
*h = 6.6260715e-34;<br />
<br />
mostra("x", x); <br />
mostra("h", h); <br />
<br />
// libera as áreas de memória<br />
delete x;<br />
delete h;<br />
}<br />
</syntaxhighlight><br />
<br />
Ao executá-lo, obtém-se isto:<br />
<br />
<syntaxhighlight><br />
######################################################<br />
Dado apontado por x = 35<br />
Endereço da área de memória usada por x: 0x561931d5de70<br />
Memória alocada: 4 bytes<br />
######################################################<br />
Dado apontado por h = 6.62607e-34<br />
Endereço da área de memória usada por h: 0x561931d5de90<br />
Memória alocada: 8 bytes<br />
</syntaxhighlight><br />
<br />
== Inicialização da área de memória alocada ==<br />
<br />
Uma forma alternativa (e importante, como se poderá observar mais pra frente) de usar o operador ''new'' possibilita inicializar a área de memória assim que for alocada. O interessante dessa inicialização é que ela depende do tipo de dados para que foi alocada a memória. Para tipos de dados primitivos, como int, float, double e char, essa inicialização se limita a copiar um valor inicial. Veja como ficaria a alocação de memória do exemplo anterior com esse uso do operador ''new'':<br />
<br />
<syntaxhighlight lang="c++"><br />
// aloca dinamicamente memória para um valor do tipo int e depois para um double<br />
// e armazena valores nas áreas de memória alocadas<br />
x = new int(35);<br />
<br />
// aloca dinamicamente memória para um valor do tipo double<br />
h = new double(6.6260715e-34);<br />
<br />
mostra("x", x); <br />
mostra("h", h); <br />
</syntaxhighlight><br />
<br />
No caso de um tipos de dados que possui um [[Introdu%C3%A7%C3%A3o_C%2B%2B#Invoca.C3.A7.C3.A3o_do_construtor|construtor]], que é uma função-membro executada automaticamente quando se cria um valor desse tipo, o operador ''new'' o executa logo após alocar memória.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
struct Nome {<br />
string nome, sobrenome;<br />
<br />
// construtor: separa um nome completo, <br />
// armazenando nome e sobrenome nos respectivos atributos<br />
Nome(const string & nome_completo) {<br />
int pos = nome_completo.find(' ');<br />
nome = nome_completo.substr(0, pos);<br />
int pos2 = nome_completo.find_first_not_of(" ", pos);<br />
sobrenome = nome_completo.substr(pos2);<br />
}<br />
};<br />
<br />
int main() {<br />
auto alguem = new Nome("Dona Bilica da Silva");<br />
<br />
cout << "Nome: " << alguem->nome << endl;<br />
cout << "Sobrenome: " << alguem->sobrenome << endl;<br />
<br />
delete alguem;<br />
}<br />
</syntaxhighlight><br />
<br />
== Alocação de array (vetor) ==<br />
<br />
O exemplo a seguir mostra a alocação de memória para um vetor (''array''), em que o operador ''new'' aloca memória com capacidade de armazenar múltiplos valores de um certo tipo. Além disso, o exemplo mostra a persistência da área alocada de memória fora do escopo em que ela foi criada:<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
// cria um vetor de inteiros com tamanho "size" e preenche<br />
// todas suas posições com "valor_inicial"<br />
int * cria_vetor(int size, int valor_inicial) {<br />
if (size <= 0) return nullptr;<br />
<br />
// cria um vetor com o tamanho dado por "size"<br />
auto v = new int[size];<br />
<br />
// preenche o vetor com o valor inicial<br />
for (int i=0; i < size; i++) v[i] = valor_inicial;<br />
return v;<br />
}<br />
<br />
int main() {<br />
int size;<br />
<br />
cout << "Qual o tamanho do vetor: ";<br />
cin >> size;<br />
<br />
// v é um ponteiro para int<br />
auto v = cria_vetor(size, 99);<br />
<br />
cout << "Endereço do vetor: " << (void*)v << endl;<br />
cout << "Conteúdo do vetor: ";<br />
for (int x=0; x < size; x++) cout << v[x] << ',';<br />
cout << endl;<br />
<br />
// libera a memória do vetor<br />
delete[] v;<br />
}<br />
</syntaxhighlight><br />
<br />
Um exemplo de execução é mostrado a seguir:<br />
<syntaxhighlight><br />
Qual o tamanho do vetor: 5<br />
Endereço do vetor: 0x561a4d6a4690<br />
Conteúdo do vetor: 99,99,99,99,99,<br />
</syntaxhighlight><br />
<br />
<br />
O uso do operador ''new'' nesse exemplo foi um pouco diferente. Como se pode notar, para criar um vetor indicou-se sua capacidade entre colchetes, logo após o tipo de dados. Isso pede que se aloque memória suficiente para conter aquela quantidade de valores do tipo informado:<br />
<br />
<syntaxhighlight lang="c++"><br />
// aloca memória suficiente oara guardar "size" valores do tipo int<br />
auto v = new int[size]; <br />
</syntaxhighlight><br />
<br />
Além disso, a função ''cria_vetor'' retorna como resultado o vetor que foi alocado. Isso mostra que a área de memória reservada para o vetor sobrevive ao final da função ''cria_vetor''. Essa área de memória continuará alocada até que o [http://www.cplusplus.com/reference/new/operator%20delete/ operador delete] a libere (o que se faz ao final da função ''main'') ... ou até que o programa termine.<br />
<br />
== Resumo ==<br />
* O operador ''new'' aloca uma área de memória com capacidade suficiente para um tipo de dados indicado, e retorna um ponteiro para essa área de memória<br />
* Após alocar a memória, o operador ''new'' a inicializa ao executar o construtor para o tipo de dados<br />
* Toda área de memória alocada deve ser liberada usando o operador ''delete'', quando não for mais necessária<br />
<br />
= Funções template =<br />
<br />
* [http://www.cplusplus.com/doc/oldtutorial/templates/ Templates em maiores detalhes]<br />
<br />
<br />
Funções, assim como classes, podem ser template, em que um ou mais tipos de dados são desconhecidos em tempo de programação. Em uma função template, os tipos de dados de um ou mais parâmetros, ou do valor devolvido como resultado, são desconhecidos em tempo de projeto. Outra forma de ver funções template é perceber que o algoritmo contido na função funciona com (quase) qualquer tipo de dados. <br />
<br />
Por exemplo, imagine que uma função deva ser capaz de ordenar um vetor qualquer, independente do tipo de dados desse vetor. Tal função poderia ser declarada com um template como este:<br />
<br />
<syntaxhighlight lang=c><br />
// Função template "ordena": ordena um "vetor" de comprimento "N"<br />
template <typename T> void ordena(T vetor[], int N);<br />
</syntaxhighlight><br />
<br />
Sua implementação poderia ser esta:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> void ordena(T vetor[], int N) {<br />
int i, j;<br />
<br />
for (i=0; i < N-1; i++) {<br />
for (j=i+1; j < N; j++) {<br />
if (vetor[i] > vetor[j]) {<br />
T aux = vetor[i];<br />
vetor[i] = vetor[j];<br />
vetor[j] = aux;<br />
}<br />
}<br />
} <br />
}<br />
</syntaxhighlight><br />
<br />
A utilização de uma função template implica informar o tipo de dados desconhecido:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
long v1[5] = {45, 72, 12, 8, 0};<br />
string v2[7] = {"banana", "abacate", "sapoti", "maracuja", "abacaxi", "caju", "goiaba"};<br />
<br />
ordena<long>(v1, 5);<br />
ordena<string>(v2, 7);<br />
}<br />
</syntaxhighlight><br />
<br />
= string =<br />
<br />
* [http://www.cplusplus.com/reference/string/string/ a classe string]<br />
<br />
<br />
Na linguagem C++ podem-se trabalhar com duas representações de string:<br />
* ''vetor de char (char * ou char [])'': essa forma é a mesma utilizada na linguagem C.<br />
* ''classe string'': objetos da classe ''string'' implementam strings com diversas facilidades, possibilitando um maior nível de abstração (fica mais fácil).<br />
<br />
<br />
A classe ''string'' foi projetada para que se possa trabalhar com strings de forma simplificada. Por exemplo, o programa abaixo mostra como criar, mostrar na tela e concatenar strings:<br />
<br />
{| border=1<br />
!Usando classe string<br />
!Usando vetor de char<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <string><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(){<br />
// declaração dos objetos string: <br />
// inicialmente eles são com strings vazias<br />
string nome;<br />
string sobrenome;<br />
<br />
// atribui "Manuel" ao objeto string "nome", <br />
// e "Alexievitvh" a "sobrenome"<br />
nome = "Manuel"<br />
sobrenome = "Alexievitch";<br />
<br />
// cria um novo objeto string, e o inicia com o <br />
// resultado da concatenação de nome e sobrenome<br />
string nome_completo = nome + ' ' + sobrenome;<br />
<br />
// mostra o objeto string na tela<br />
cout << "Nome: " << nome_completo << endl;<br />
}<br />
</syntaxhighlight>||<syntaxhighlight lang=c><br />
#include <string.h><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main(){<br />
char nome[16];<br />
char sobrenome[32];<br />
<br />
strncpy(nome, "Manuel", 16);<br />
strncpy(sobrenome, "Alexievitch", 32);<br />
<br />
char nome_completo[64];<br />
strcpy(nome_completo, nome);<br />
nome_completo[strlen(nome_completo)] = ' ';<br />
nome_completo[strlen(nome_completo)] = 0;<br />
strcat(nome_completo, sobrenome);<br />
<br />
cout << "Nome: " << nome_completo << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
A classe string oferece [http://www.cplusplus.com/reference/string/string/ diversas operações], tais como:<br />
* [http://www.cplusplus.com/reference/string/string/size/ size]: Obter o comprimento da string<br />
* [http://www.cplusplus.com/reference/string/string/operator%5B%5D/ operator[]]: Obter um caractere em uma determinada posição. Esse tipo de acesso é sintaticamente idêntico ao acesso a uma posição de um vetor<br />
* [http://www.cplusplus.com/reference/string/string/operator+=/ operator+=]: anexa uma string<br />
* [http://www.cplusplus.com/reference/string/string/push_back/ push_back]: anexa um caractere<br />
* [http://www.cplusplus.com/reference/string/string/erase/ erase]: remove caracteres de uma string<br />
* [http://www.cplusplus.com/reference/string/string/replace/ replace]: substitui parte de uma string<br />
* [http://www.cplusplus.com/reference/string/string/c_str/ c_str]: retorna uma representação em vetor de char<br />
* [http://www.cplusplus.com/reference/string/string/find/ find]: encontra a primeira ocorrência de uma substring ou um caractere<br />
* [http://www.cplusplus.com/reference/string/string/rfind/ rfind]: encontra a última ocorrência de uma substring ou um caractere<br />
* [http://www.cplusplus.com/reference/string/string/substr/ substr]: gera uma substring<br />
<br />
== Lendo ou escrevendo strings em streams ==<br />
<br />
Podem-se ler ou escrever strings em streams usando os operadores ''<<'' ou ''>>''. Por exemplo, para ler uma string da entrada padrão (ex: teclado), pode-se fazer assim:<br />
<br />
<syntaxhighlight lang=c><br />
string algo;<br />
<br />
// lê uma string da entrada padrão e grava-a em "algo"<br />
cin >> algo;<br />
</syntaxhighlight><br />
<br />
<br />
Para escrever uma string em um stream (ex: um arquivo), pode-se faz desta forma:<br />
<br />
<syntaxhighlight lang=c><br />
// abre um arquivo para escrita<br />
ofstream arq("teste.txt");<br />
<br />
string algo = "Um teste";<br />
<br />
// escreve a string no arquivo<br />
arq << algo;<br />
</syntaxhighlight><br />
<br />
<br />
No caso da leitura de uma string que contenha espaços, ou mesmo de uma linha completa, deve-se usar a função [http://www.cplusplus.com/reference/string/string/getline/ getline]:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
<br />
cout << "Escreva uma frase: ";<br />
<br />
getline(cin, linha);<br />
<br />
cout << "Frase digitada é: " << linha;<br />
</syntaxhighlight><br />
<br />
A função getline usa o caractere ''newline'' (''\n'') como delimitador. Se for desejado usar outro caractere como delimitador, deve-se fazer o seguinte:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
char delimitador=',';<br />
<br />
cout << "Escreva uma frase que contenha ao menos uma vírgula: ";<br />
<br />
getline(cin, linha, delimitador);<br />
<br />
cout << "Frase digitada até a vírgula é: " << linha;<br />
</syntaxhighlight><br />
<br />
== Conversão de string para tipos numéricos ==<br />
<br />
* [[Introdução_C%2B%2B#Leitura_e_escrita_formatada|Leitura e escrita com operadores << e >>]]<br />
<br />
<br />
Em C++ há diferentes formas de converter strings para dados numéricos, e vice-versa. Podem-se, por exemplo, usar as funções da biblioteca C padrão ([http://manpages.ubuntu.com/manpages/precise/man3/scanf.3.html sscanf], [http://manpages.ubuntu.com/manpages/precise/man3/snprintf.3.html snprintf], [http://manpages.ubuntu.com/manpages/precise/man3/strtod.3.html strtod], ...). Mas uma forma particular existente em C++ explora o conceito de ''streams''. <br />
<br />
Arquivos abertos são acessados como ''streams'' em C++. Na verdade, essa é uma interface corriqueira para acesso a arquivos, estando disponível em diferentes linguagens (ex: as operações de arquivo em C, como [http://manpages.ubuntu.com/manpages/precise/man3/fscanf.3.html fscanf], [http://manpages.ubuntu.com/manpages/precise/man3/fprintf.3.html fprintf], [http://manpages.ubuntu.com/manpages/precise/man3/fread.3.html fread, fwrite], [http://manpages.ubuntu.com/manpages/precise/man3/fgets.3.html fgets], ...). Em C++ ''streams'' possibilitam ler texto de um arquivo e convertê-lo para um dado numérico, e vice-versa. Isso é feito normalmente em programas, como no exemplo abaixo:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ifstream arq("numeros.txt");<br />
int numero;<br />
string palavra;<br />
<br />
arq >> numero;<br />
arq >> palavra;<br />
<br />
cout << "numero=" << numero << endl;<br />
cout << "palavra=" << palavra << endl;<br />
<br />
arq.close();<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Se o arquivo ''numeros.txt'' possuir este conteúdo:<br />
<br />
<syntaxhighlight lang=text><br />
2015 Furious<br />
1999 Matrix<br />
</syntaxhighlight><br />
<br />
<br />
... a execução do programa exemplo, que lê apenas a primeira linha, resultará em:<br />
<br />
<syntaxhighlight lang=text><br />
numero=2015<br />
palavra=Furious<br />
</syntaxhighlight><br />
<br />
<br />
Assim, o operador ''>>'' de ''streams'' possibilita converter texto para um outro tipo de dado, dependendo do tipo da variável onde o resultado deva ser gravado. No exemplo, esse operador é usado duas vezes:<br />
<br />
<syntaxhighlight lang=c><br />
arq >> numero; // converte texto para inteiro, pois "numero" <br />
// é uma variável do tipo int<br />
arq >> palavra;// converte texto para string, pois palavra é do tipo string<br />
</syntaxhighlight><br />
<br />
<br />
Parece que C++ possibilita converter facilmente texto (string) para dado numérico SE o texto estiver guardado em um arquivo. Isso não é conveniente para converter um valor que esteja guardado em uma variável string, pois tornaria necessário escrevê-la em um arquivo temporário para depois ler desse arquivo e efetuar a conversão. De fato, se fosse assim dificilmente ''streams'' seriam usadas para converter dados em C++. No entanto existe um tipo de ''stream'' que possibilita que se acesse uma string como se fosse um arquivo. Quer dizer, a leitura e a escrita dos caracteres de uma string podem ser feitas com operações de arquivo. O exemplo abaixo mostra o uso dessa [http://www.cplusplus.com/reference/sstream/istringstream/ ''stream de string'' (ou ''stringstream'')]:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
// as classes stringstream estão em sstream<br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
istringstream stream("2015 Furious");<br />
int numero;<br />
string palavra;<br />
<br />
stream >> numero;<br />
stream >> palavra;<br />
<br />
cout << "numero=" << numero << endl;<br />
cout << "palavra=" << palavra << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O exemplo mostra uma ''stringstream'' criada com conteúdo ''2015 Furious''. Em seguida, usa-se o operador ''>>'' para ler um número inteiro e uma string. O resultado desse exemplo é idêntico ao do exemplo anterior, em que se liam esses dados de um arquivo.<br />
<br />
A possibilidade de usar ''stringstream'' para converter dados torna simples criar funções de conversão, como esta que converte string para inteiro:<br />
<br />
<syntaxhighlight lang=c><br />
int converte_para_int(const string & dado) {<br />
istringstream stream(dado);<br />
int r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Outras funções para tipos numéricos podem ser criadas da mesma forma:<br />
<br />
<syntaxhighlight lang=c><br />
float converte_para_float(const string & dado) {<br />
istringstream stream(dado);<br />
float r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
<br />
<br />
double converte_para_double(const string & dado) {<br />
istringstream stream(dado);<br />
double r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Note que são todas muito parecidas. A única diferença entre elas é o tipo do dado numérico da conversão. Assim, é natural substitui-las por uma função ''template'':<br />
<br />
<syntaxhighlight lang=c><br />
template <class T> T converte(const string & dado) {<br />
istringstream stream(dado);<br />
T r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Essa função ''template'' seria usada da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
template <class T> T converte(const string & dado) {<br />
istringstream stream(dado);<br />
T r;<br />
<br />
stream >> r;<br />
if (stream.fail()) throw 1; // erro de conversão<br />
<br />
return r;<br />
}<br />
<br />
int main() {<br />
string algo1 = "2015";<br />
string algo2 = "3.1416";<br />
string algo3 = "xyz";<br />
int ano;<br />
float pi;<br />
<br />
ano = converte<int>(algo1);<br />
pi = converte<float>(algo2);<br />
<br />
cout << "ano=" << ano << endl;<br />
cout << "pi=" << pi << endl;<br />
<br />
try {<br />
ano = converte<int>(algo3);<br />
cout << "Outro ano=" << ano << endl;<br />
} catch (int e) {<br />
cout << "Erro de conversão: " << algo3 << " não é um int" << endl;<br />
}<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
= ''streams'' e arquivos =<br />
<br />
Em diversas linguagens de programação o conceito de ''stream'' (''fluxo'' ou ''correnteza'') é utilizado para o acesso a arquivos em disco. Por ''stream'' entende-se um mecanismo e leitura e escrita em que dados fluem sucessivamente. Dessa forma, ao se escrever em um arquivo fazem-se sucessivas operações de escrita, e os dados são armazenados na ordem em que essas operações se realizaram. Algo parecido acontece na leitura de um arquivo, em que as operações de leitura realizadas fornecem dados de acordo com a ordem em que estão gravados no arquivo. <br />
<br />
<br />
O acesso a arquivos apresenta algumas diferenças nas linguagens C e C++. Em C++ existem algumas classes para a manipulação de arquivos. Desta forma, arquivos nesta linguagem são acessados por meio de objetos dessas classes. No exemplo abaixo, apresentam-se dois programas em C e C++ para ler as linhas de um arquivo e mostrá-las na tela. <br />
<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <stdio.h><br />
#include <errno.h><br />
<br />
#define MAX_SIZE 10240<br />
<br />
int main() {<br />
FILE * arq;<br />
char linha[MAX_SIZE];<br />
<br />
// abre o arquivo<br />
arq = fopen("/etc/hosts", "r");<br />
<br />
// testa se conseguiu abrir o arquivo<br />
if (arq == NULL) {<br />
perror("Ao abrir /etc/hosts");<br />
return errno;<br />
}<br />
<br />
// lê cada linha do arquivo, mostrando-a na tela<br />
while (fgets(linha, MAX_SIZE, arq)) {<br />
printf("%s", linha);<br />
}<br />
<br />
// fecha o arquivo<br />
fclose(arq);<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
#include <stdio.h><br />
#include <errno.h><br />
<br />
#define MAX_SIZE 10240<br />
<br />
using namespace std;<br />
<br />
int main() {<br />
// cria o objeto "arq" da classe "ifstream", que representa um arquivo para leitura<br />
// a criação desse objeto já abre o arquivo<br />
ifstream arq("/etc/hosts");<br />
<br />
// verifica se o arquivo foi de fato aberto<br />
if (! arq.is_open()) {<br />
perror("Ao abrir /etc/hosts");<br />
return errno;<br />
}<br />
<br />
// lê cada linha do arquivo, apresentando-a na tela<br />
string linha;<br />
while (getline(arq, linha)) {<br />
cout << linha << endl;<br />
}<br />
<br />
// observe que o arquivo não precisa ser fechado ... isso ocorre automaticamente<br />
// quando o objeto for destruído, ficando a cargo de seu destrutor<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
Os exemplos acima demonstram que a sintaxe no acesso a arquivos pode ser diferente, porém funcionalmente parece haver uma equivalência entre as duas formas de acesso. De fato tudo que se consegue fazer em C++ é possível fazer em C, mudando apenas a praticidade ou conveniência na forma com que se expressa isso nessas linguagens. Porém como a linguagem C já é bem conhecida por vocês, interessa ver o que se pode fazer em C++.<br />
<br />
Em C++ existem três classes para acessar arquivos:<br />
* [http://www.cplusplus.com/reference/fstream/ofstream/ ofstream]: acesso a arquivos em modo escrita. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ofstream arq("demo.txt");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
arq << "Iniciando uma gravação de várias linhas inúteis ..." << endl;<br />
<br />
for (int i=0; i < 10; i++) {<br />
arq << "Linha " << i << endl; <br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
* [http://www.cplusplus.com/reference/fstream/ifstream/ ifstream]: acesso a arquivos em modo leitura. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
ifstream arq("/etc/hosts");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
while (not arq.eof()) {<br />
string algo;<br />
<br />
arq >> algo;<br />
cout << "Leu isto: " << algo << endl;<br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
* [http://www.cplusplus.com/reference/fstream/ fstream]: acesso a arquivos em modo leitura/escrita. {{collapse top|Exemplo}}<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <fstream><br />
<br />
using namespace std;<br />
<br />
#define MAX_LINE 10240<br />
<br />
int main() {<br />
fstream arq("demo.txt");<br />
<br />
if (not arq.is_open()) {<br />
cerr << "Algum erro ao abrir o arquivo ..." << endl;<br />
return 0;<br />
}<br />
<br />
for (int i=0; i < 10; i++) {<br />
arq << "Linha " << i << endl; <br />
}<br />
arq.flush();<br />
<br />
arq.seekg(0);<br />
<br />
while (not arq.eof()) {<br />
char linha[MAX_LINE];<br />
<br />
arq.getline(linha, MAX_LINE);<br />
cout << "Leu: " << linha << endl;<br />
}<br />
}<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
<br />
O interessante em C++ é que a saída padrão e a entrada padrão são representados por objetos ''stream''. De fato, veja como estão declarados esses objetos na biblioteca C++ padrão:<br />
* [http://www.cplusplus.com/reference/iostream/cout/ cout]: saída padrão<br />
* [http://www.cplusplus.com/reference/iostream/cin/ cin]: entrada padrão<br />
* [http://www.cplusplus.com/reference/iostream/cerr/ cerr]: saída de erros padrão<br />
<br />
== Leitura e escrita formatada ==<br />
<br />
''streams'' implementam leitura e escrita formatadas por meio dos operadores [http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ ''>>''] (leitura) e [http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ ''<<''] (escrita). Esses operadores fazem a conversão automática entre ''string'' e outros tipos de dados.<br />
<br />
A leitura de um ''stream'' pode ser feita como no exemplo a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
int x;<br />
<br />
cout << "Digite um número inteiro: ";<br />
<br />
// aqui se faz a leitura de um número inteiro<br />
cin >> x;<br />
<br />
cout << "Você digitou " << x << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Nesse exemplo, a leitura é feita de ''cin'', uma ''stream'' que representa a console (usualmente o teclado). Lê-se um número inteiro digitado pelo usuário, o qual é armazenado na variável ''x''. A conversão de ''string'' para inteiro é feita automaticamente, porque a variável onde se deseja armazenar o valor lido é do tipo ''int''. Assim, a conversão depende do tipo da variável onde se deve armazenar o valor lido. Este outro exemplo reforça a questão da conversão de tipo:<br />
<br />
<syntaxhighlight lang=c><br />
char algo;<br />
int numero;<br />
<br />
cout << "Digite um caractere qualquer seguido de um número (ex: !33): ";<br />
cin >> algo;<br />
cin >> numero;<br />
<br />
cout << "Você digitou: " << algo << numero << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Nesse novo exemplo, dois valores são lidos: um valor do tipo char seguido de um int. O primeiro valor corresponde a um único caractere, e o segundo a um ou mais caracteres numéricos consecutivos. As conversões são desencadeadas pelos tipos das variáveis usados nas leituras. Algo similar acontece quando se escrevem dados em um ''stream''.<br />
<br />
<br />
O exemplo a seguir mostra a escrita de alguns valores em ''cout'', um ''stream'' que representa também a console (usualmente a tela):<br />
<br />
<syntaxhighlight lang=c><br />
double pi = 3.1416;<br />
char letra = 'H';<br />
<br />
// escreve um valor do tipo char<br />
cout << letra;<br />
<br />
// escreve um valor do tipo string (char*)<br />
cout << " = ";<br />
<br />
// escreve um valor do tipo double<br />
cout << pi;<br />
<br />
// endl corresponde a \n (newline)<br />
cout << endl;<br />
</syntaxhighlight><br />
<br />
<br />
Como mostra o exemplo, são escritos valores do tipo ''char'', , ''char*'' e ''double''. Em todos os casos, a conversão automática entre esses valores e string depende do tipo da variável ou constante onde está o valor a ser escrito. <br />
<br />
=== Lendo linha por linha ===<br />
<br />
Este outro exemplo mostra uma forma simples de ler todas as linhas de um arquivo. A função [http://www.cplusplus.com/reference/string/string/getline/ getline] extrai uma linha a cada vez que é chamda. Neste exemplo, o efeito final será ler linha por linha do arquivo:<br />
<br />
<syntaxhighlight lang=c><br />
string linha;<br />
ifstream arq("teste.txt");<br />
<br />
// enquanto conseguir ler uma string do arquivo ...<br />
// quando chegar ao fim do arquivo, a leitura irá falhar<br />
while (getline(arq, linha)) {<br />
// faz algo com o conteúdo de "linha"<br />
}<br />
</syntaxhighlight><br />
<br />
=== Lendo palavra por palavra ===<br />
<br />
Este outro exemplo mostra uma forma simples de ler todos os valores de um arquivo. O operador ''>>'' extrai um valor a cada vez que é executado sobre o arquivo. Neste exemplo, o efeito final será ler palavra por palavra do arquivo:<br />
<br />
<syntaxhighlight lang=c><br />
string palavra;<br />
ifstream arq("teste.txt");<br />
<br />
// enquanto conseguir ler uma string do arquivo ...<br />
// quando chegar ao fim do arquivo, a leitura irá falhar<br />
while (arq >> palavra) {<br />
// faz algo com o conteúdo de "palavra"<br />
}<br />
</syntaxhighlight><br />
<br />
Deve-se notar que o operador ''>>'' considera como delimitadores os caracteres ''brancos'' (espaço, TAB, newline).<br />
<br />
<br />
A escrita e leitura formatada está implementada para os tipos elementares de C e C++ (int, long, short, char, char*, string, bool, float, double). Isso significa que essas operações não funcionam para novos tipos de dados ou classes classes, a não ser que se [[Introdução_C%2B%2B#Sobrecarga_de_operador|implementem esses operadores de leitura e escrita para esses novos tipos]].<br />
<br />
== Operações de streams ==<br />
<br />
''streams'' oferecem várias operações para leitura e escrita de dados. Algumas mais comuns são listadas a seguir, junto com exemplos.<br />
<br />
{| border=1<br />
!Operação<br />
!Entrada<br />
!Saída<br />
!Para que serve<br />
!Exemplo<br />
|-<br />
| [http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ >>] || x|| ||leitura formatada || <syntaxhighlight lang=c>int x;<br />
double y;<br />
string palavra;<br />
<br />
// lê um número inteiro<br />
cin >> x;<br />
<br />
// lê um número double<br />
cin >> y;<br />
<br />
// lê uma string<br />
cin >> palavra;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ <<] || ||x ||escrita formatada ||<syntaxhighlight lang=c>int x = 5;<br />
double y=3.1416;<br />
string palavra="alguma coisa";<br />
<br />
// escreve um número inteiro seguido de uma vírgula<br />
cout << x << ", ";<br />
<br />
// escreve um número double seguido de uma vírgula<br />
cout << y << ", ";<br />
<br />
// escreve uma string seguida de nova linha<br />
cout << palavra << endl;<br />
<br />
// outra forma de escrever os três valores <br />
cout << x << ", " << y << ", " << palavra << endl;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/string/string/getline/ getline] || x|| ||lê uma linha (até encontrar '\n') || <syntaxhighlight lang=c>string linha;<br />
<br />
getline(cin, linha);<br />
<br />
cout << "Linha: " << linha << endl;<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/istream/istream/ignore/ ignore] || x|| ||lê e descarta caracteres ||<syntaxhighlight lang=c><br />
cout << "Tecle ENTER para continuar";<br />
cin.ignore(256, '\n'); // lê e descarta até 256 caracteres, ou até ler '\n'<br />
</syntaxhighlight><br />
|-<br />
| [http://www.cplusplus.com/reference/ios/ios/eof/ eof] || x||x ||Verifica se chegou ao fim da stream|| <syntaxhighlight lang=c><br />
ifstream arq("/etc/hosts");<br />
<br />
while (true) {<br />
string linha;<br />
<br />
getline(arq, linha);<br />
if (arq.eof()) break; // se não conseguir ler algo (fim de arquivo)<br />
cout << linha << endl;<br />
}<br />
</syntaxhighlight><br />
|-<br />
|[http://www.cplusplus.com/reference/fstream/ifstream/is_open/ is_open] || x||x||Verifica se arquivo foi aberto|| <syntaxhighlight lang=c><br />
ifstream arq("/etc/hosts");<br />
<br />
if (not arq.is_open()) {<br />
cout << "Erro: não abriu o arquivo" << endl;<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
== Acessando strings como se fossem arquivos ==<br />
<br />
Em C++ esse conceito de ''stream'' é levado um pouco além. Além de arquivos e a entrada e saída padrão, é possível também manipular ''strings'' como se fossem ''streams''. Quer dizer, pode-se escrever em uma ''string'' (criá-la) ou extrair partes de uma ''string'' como se estivesse acessando um arquivo. Isso possibilita que funções ou objetos que escrevem ou lêem em arquivos possam fazer o mesmo em memória, o que pode ser útil em diferentes programas. <br />
<br />
O uso de ''strings'' como se fossem ''streams'' é implementado por três classes:<br />
* [http://www.cplusplus.com/reference/sstream/ostringstream/ ostringstream]: possibilita escrever em uma ''string''<br />
* [http://www.cplusplus.com/reference/sstream/istringstream/ istringstream]: possibilita ler de uma ''string''<br />
* [http://www.cplusplus.com/reference/sstream/stringstream/ stringstream]: possibilita ler e escrever em uma ''string''<br />
<br />
<br />
O exemplo mais simples envolve criar uma string a partir dos valores de algumas variáveis. Veja como isso era feito em C e como se faz em C++:<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
|<syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
printf("Dia: ");<br />
scanf("%d", &dia);<br />
printf("Mes: ");<br />
scanf("%d", &mes);<br />
printf("Ano: ");<br />
scanf("%d", &ano);<br />
<br />
snprintf(data, 32, "%d/%d/%d", dia, mes, ano);<br />
<br />
printf("Data: %s\n", data);<br />
<br />
}<br />
</syntaxhighlight> || <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int dia, mes, ano;<br />
<br />
cout << "Dia: ";<br />
cin >> dia;<br />
cout << "Mes: ";<br />
cin >> mes;<br />
cout << "Ano: ";<br />
cin >> ano;<br />
<br />
//cria-se uma stringstream para escrita<br />
ostringstream out;<br />
<br />
// escreve-se na stringstream<br />
out << dia << "/";<br />
out << mes << "/";<br />
out << ano;<br />
<br />
// Aqui se obtém o conteúdo armazenado na stringstream<br />
cout << "Data: " << out.str() << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
<br />
Estes outros exemplos mostram a extração de dados que existem em strings:<br />
<br />
{| border="1"<br />
!Linguagem C<br />
!Linguagem C++<br />
|-<br />
| <syntaxhighlight lang=c><br />
#include <stdio.h><br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
printf("Data (dia/mes/ano): ");<br />
fgets(data, 32, stdin); // lê uma linha<br />
<br />
// extrai os dados da linha<br />
sscanf(data, "%d/%d/%d", &dia, &mes, &ano);<br />
<br />
// Aqui se mostram os dados extraídos da linha<br />
printf("Dia: %d\n", dia);<br />
printf("Mes: %d\n", mes);<br />
printf("Ano: %d\n", ano);<br />
}<br />
</syntaxhighlight>|| <syntaxhighlight lang=c><br />
#include <iostream><br />
#include <sstream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
int dia, mes, ano;<br />
char data[32];<br />
<br />
cout << "Data (dia/mes/ano): "; <br />
cin.getline(data, 32);<br />
<br />
//cria-se uma stringstream para leitura<br />
istringstream inp(data);<br />
char separador;<br />
<br />
// lê-se da stringstream<br />
inp >> dia;<br />
inp >> separador;<br />
inp >> mes;<br />
inp >> separador;<br />
inp >> ano;<br />
<br />
// Aqui se mostram os dados extraídos da stringstream<br />
cout << "Dia: " << dia << endl;<br />
cout << "Mes: " << mes << endl;<br />
cout << "Ano: " << ano << endl;<br />
}<br />
</syntaxhighlight><br />
|}<br />
<br />
= Sobrecarga de operador =<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/templates/#overloading_operators Operator overloading]: uma explicação mais detalhada sobre o assunto. Inclui também uma tabela com os operadores que podem ser redefinidos.<br />
<br />
<br />
Operadores C++ podem ser redefinidos, o que se chama sobrecarga de operador (''operator overloading''). Assim, dependendo do tipo de dados ou da classe do valor, variável ou objeto que recebe a operação, o operador pode funcionar de uma forma específica. Um operador pode ser implementado como uma função, que pode ou não ser membro de uma classe.<br />
<br />
<br />
O nome da função que implementa um operador é formado pela palavra chave ''operator'' seguida do operador que se deseja implementar. Por exemplo, para o operador ''=='' a função se chama ''operator==''. O tipo do valor de retorno dessa função depende do operador a ser implementado (ex: o operador == retorna um valor booleano, mas o operador = retorna uma referência à variável ou objeto que foi alvo da operação). A quantidade de parâmetros dessa função também dependem do operador em questão, e os tipos de desses parâmetros dependem dos tipos de dados envolvidos na operação.<br />
<br />
<br />
Um operador pode ser implementado de duas formas:<br />
# '''Como um método de uma classe:''' um método implementa a operação a ser realizada quando se usa o operador com um objeto dessa classe. A execução desse método acontece no escopo do objeto que recebe a operação (ex: em operadores unários é o próprio objeto alvo do operador, e em operadores binários é o objeto que aparece à esquerda do operador).<br />
# '''Como uma função:''' uma função implementa a operação a ser realizada quando se usa o operador. Essa função recebe como parâmetros as variáveis ou objetos envolvidos na operação.<br />
<br />
<br />
Dois exemplos são apresentados para esclarecer a sobrecarga de operadores usando funções que não são membros de classe (i.e. não são métodos):<br />
* '''Operador unário !:''' o operador ''!'' corresponde à operação NÃO, mas ele pode ser redefinido para um tipo de dados específico. Suponha-se que se deseje que o operador ''!'' aplicado a uma string deve retornar ''true'' se ela for vazia, e ''false'' caso contrário. Isso pode ser feito redefinido o operador ''!'' para string da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
bool operator!(const string & s) {<br />
if (s.size() == 0) return true;<br />
return false;<br />
}<br />
</syntaxhighlight><br />
<br />
* '''Operador binário ==''': o operador ''=='' serve para comparar dois valores, resultando em ''true'' se eles forem considerados iguais, e ''false'' caso contrário. Suponha-se que se deseje que esse operador, quando aplicado a string, resulte em ''true'' se duas string tiverem mesmo comprimento. Isso pode ser feito da seguinte forma:<br />
<br />
<syntaxhighlight lang=c><br />
bool operator==(constr string & s1, const string & s2) {<br />
return s1.size() == s2.size();<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Esses dois operadores podem ser exemplificados também como métodos uma classe. Usando-se a classe Fila, ambos operadores podem ser implementados da seguinte forma. O operador unário ''!'' deve retornar ''true'' se fila estiver vazia, e o operador ''=='' deve retornar ''true'' se as filas forem iguais:<br />
<br />
<syntaxhighlight lang=c><br />
template <typename T> class Fila {<br />
private:<br />
// atributos da fila<br />
public:<br />
// métodos da fila<br />
<br />
bool operator!() const {<br />
return vazia();<br />
}<br />
<br />
bool operator==(const Fila<T> & outra) const {<br />
// para serem iguais, devem ter mesma quantidade de dados<br />
if (itens == outra.itens) { <br />
// ... e os dados devem ser iguais e estarem na mesma ordem<br />
int n = itens;<br />
<br />
while (n > 0) {<br />
T dado1 = desenfileira();<br />
T dado2 = outra.desenfileira();<br />
enfileira(dado1);<br />
enfileira(dado2);<br />
if (dado1 != dado2) return false;<br />
n--;<br />
}<br />
return true;<br />
}<br />
return false;<br />
}<br />
};<br />
</syntaxhighlight><br />
<br />
== Sobrecarga de operadores << e >> de streams ==<br />
<br />
Pode-se desejar que objetos de uma classe possam ser escritos em ''streams'' diretamente por meio do operador ''<<''. Para descobrir uma solução para esse problema, deve-se entender como o operador ''<<'' está definido. E basicamente ele está implementado de duas formas:<br />
# [http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ Na classe ostream]: a classe ''ostream'' representa arquivos/streams abertos para escrita, e já possui implementações desse operador para tipos básicos de C++.<br />
# '''Em funções de sobrecarga de operador ([http://www.tutorialspoint.com/cplusplus/cpp_overloading.htm operator overloading]):''' podem-se definir funções que implementam esse operador para novos tipos/classes. Por exemplo, existe [http://www.cplusplus.com/reference/string/string/operator%3C%3C/ uma dessas funções para a classe string]. Um exemplo de função de sobrecarga de operador para um novo tipo de dados segue abaixo: <syntaxhighlight lang=c><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
// Define-se um novo tipo de dados<br />
struct Ponto {<br />
int x,y;<br />
};<br />
<br />
// Define-se o operador << de ostream para poder escrever um Ponto.<br />
// Esse operador mostra o ponto da seguinte forma: (x,y)<br />
ostream& operator<<(ostream &out, const Ponto& p) {<br />
out << "(" << p.x << "," << p.y << ")";<br />
return out;<br />
}<br />
<br />
// Agora pode-se usar o operador << para valor do tipo "Ponto"<br />
int main() {<br />
Ponto p1 = {1,1}, p2 = {10,20};<br />
<br />
cout << "Ponto 1: " << p1 << endl;<br />
cout << "Ponto 2: " << p2 << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
O mesmo vale para o operador ''>>''. Para que se possa ler diretamente de um ''stream'' um valor de um novo tipo de dados ou classe, esse operador precisa ser definido.<br />
<br />
= Exceções =<br />
<br />
* [http://www.cplusplus.com/doc/tutorial/exceptions/ Uma explicação detalhada sobre exceções]<br />
<br />
<br />
Condições de erro podem ser avisadas por meio de exceções. Por exemplo, no caso da lista considera-se erro tentar obter um valor em uma posição inexistente. A operação para obter um dado da lista deve, portanto, comunicar de alguma forma que esse acesso inválido aconteceu. Outro exemplo mais simples envolve a conversão de uma string numérica com a função stoi. Se a string não contiver um número inteiro, ocorre um erro. O programa a seguir demonstra esse caso, mostrando o erro:<br />
<br />
<syntaxhighlight lang=c><br />
#include <string><br />
#include <iostream><br />
<br />
using namespace std;<br />
<br />
int main() {<br />
string n1 = "123";<br />
string n2 = "abc";<br />
int x1, x2;<br />
<br />
// esta conversão é feita com sucesso<br />
x1 = stoi(n1);<br />
<br />
cout << "Primeira conversão: " << x1 << endl;<br />
<br />
// ... mas esta causa um erro <br />
x2 = stoi(n2);<br />
<br />
cout << "Segunda conversão: " << x2 << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Ao se compilar e executar esse programa, obtém-se este resultado, que revela o erro de execução:<br />
<br />
<syntaxhighlight lang=bash><br />
aluno@curl:~$ g++ -o erro -std=c++11 erro.cpp <br />
aluno@curl:~$ ./erro<br />
Primeira conversão: 123<br />
terminate called after throwing an instance of 'std::invalid_argument'<br />
what(): stoi<br />
Abortado (imagem do núcleo gravada)<br />
</syntaxhighlight><br />
<br />
<br />
O erro manifestado no programa, e que causou sua terminação abrupta, se chama exceção. O mecanismo de exceções existente na linguagem C++ possibilita expressar e tratar condições de erro de uma forma mais prática. Um algoritmo pode disparar uma exceção se detectar uma situação anômala, interrompendo a execução do programa. Essa interrupção causa a execução de um outro trecho de código, responsável por tratar a exceção. Sendo assim, na parte do código onde pode ocorrer uma exceção, deve-se capturá-la e tratá-la. Para isso usa-se a construção ''try ... catch'', que possibilita executar um tratador de exceção. No exemplo de conversão de string numérica, o uso de ''try .. catch'' ficaria assim:<br />
<br />
<syntaxhighlight lang=c><br />
string n1 = "123";<br />
string n2 = "abc";<br />
int x1, x2;<br />
<br />
try {<br />
// esta conversão é feita com sucesso<br />
x1 = stoi(n1);<br />
cout << "Primeira conversão: " << x1 << endl;<br />
} catch (...) {<br />
cout << "Erro de conversão: " << n1 << " não é uma string numérica inteira !" << endl;<br />
}<br />
<br />
try {<br />
// esta conversão dispara uma exceção<br />
x2 = stoi(n2);<br />
cout << "Segunda conversão: " << x2 << endl;<br />
} catch (...) {<br />
cout << "Erro de conversão: " << n2 << " não é uma string numérica inteira !" << endl;<br />
}<br />
<br />
return 0;<br />
</syntaxhighlight><br />
<br />
<br />
No exemplo acima, o bloco ''try .. catch'' foi usado de forma a capturar qualquer exceção, o que se define com ''catch (...)''. No entanto, exceções podem ser de diferentes tipos, tais como números, string, ou mesmo objetos. Uma exceção portanto é representada por algum valor informativo, e esse valor pertence a algum tipo de dados ou classe. Com isso, diferentes tipos de exceção podem ser disparadas em um trecho de código, e para capturá-las e tratá-las individualmente é necessário definir tratadores de exceção específicos. Por exemplo, considere que um trecho de código possa disparar exceções do tipo int, string, e possivelmente outras. A forma de tratá-las poderia ser assim:<br />
<br />
<syntaxhighlight lang=c><br />
try {<br />
// trecho de código que pode disparar diferentes tipos de exceções<br />
} catch (int e1) { <br />
// aqui se tratam exceções do tipo int<br />
} catch (string e2) {<br />
// aqui se tratam exceções do tipo string<br />
} catch (...) {<br />
// aqui se tratam demais exceções de tipos quaisquer<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Por outro lado, quando se programa um algoritmo (embutido em uma função ou método de classe), erros ou situações inesperadas que forem detectadas implicam o disparo de uma exceção por meio da palavra chave ''throw''. O valor da exceção pode ser qualquer, e no exemplo a seguir é representado por um número inteiro:<br />
<br />
<syntaxhighlight lang=c><br />
void maiusculas(string & palavra) {<br />
if (palavra.size() == 0) throw 1; // string vazia !!!<br />
<br />
for (int i=0; i < palavra.size(); i++) palavra[i] = toupper(palavra[i]);<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
'''OBS:''' se uma exceção não for capturada usando ''try ... catch'', ela causará o término do programa.</div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PRG29003:_Etapa_2:_Projeto_de_estruturas_de_dados&diff=171380PRG29003: Etapa 2: Projeto de estruturas de dados2020-10-22T19:08:34Z<p>Msobral: /* Alternativa */</p>
<hr />
<div>__toc__<br />
<br />
= Introdução =<br />
<br />
Desde o início do semestre foi usada a [https://www.geeksforgeeks.org/the-c-standard-template-library-stl/ biblioteca STL], que contém implementações das estruturas de dados estudadas. Na primeira etapa da disciplina se enfatizou conhecer e usar essas estruturas de dados. Na segunda etapa o foco está no projeto de uma estrutura de dados, e o resultado esperado é a criação de estruturas de dados pelas equipes. Podem ser criadas versões que reproduzam (possivelmente com um toque pessoal) as características das estruturas de dados estudadas, ou mesmo novas estruturas de dados, diferentes daquelas conhecidas.<br />
<br />
As estruturas de dados que já conhecemos são:<br />
* '''Lineares''': filas, pilhas e listas<br />
* '''Associativas''': tabelas hash, conjuntos e árvores de pesquisa binária<br />
<br />
<br />
Mais especificamente os '''objetivos de aprendizagem''' desta unidade são:<br />
<br />
# Desenvolver (criar) uma estrutura de dados que possa ser utilizada em programas, possuindo uma interface de programação bem definida, e incluindo os algoritmos específicos necessários para a eficiência de suas operações quanto ao uso de memória e tempo computacional.<br />
# Avaliar o projeto de uma estrutura de dados, usando sua documentação como referência para emitir um julgamento sobre sua eficiência e usabilidade<br />
<br />
<br />
Algumas das estruturas conhecidas são bastante simples, e não serviriam como objeto de estudo nesta etapa da disciplina (refiro-me especificamente a filas e pilhas). As demais têm complexidade adequada para serem desenvolvidas neste último mês de aula. Além delas, outras estruturas de dados podem ser escolhidas:<br />
* [https://en.wikipedia.org/wiki/Trie Trie]: uma ''trie'' é um tipo de árvore n-ária (que pode ter um número ''n'' de ramos por nodo), em que os dados estão armazenados nos ramos, e não nos nodos. Esse tipo de árvore armazena prefixos dos dados, então são adequadas para dados formados por cadeias de elementos (ex: strings, endereços IP, sequências de bits em geral, ...). Um uso conhecido para tries é como dicionário de termos para um sistema do tipo auto-completar. Uma variação de tries é [https://en.wikipedia.org/wiki/Radix_tree radix tree].<br />
* [https://en.wikipedia.org/wiki/Double-ended_queue#Implementations Array Deques]: um array deque é um tipo de fila que usa um array dinâmico (i.e. que pode ser expandido ou contraído) para armazenar dados. Ela possibilita a inserção e remoção eficiente de dados de seus extremos, e o acesso a qualquer dado pode ser feito com tempo constante (i.e. o custo de tempo computacional dessa operação é ''O(1)'').<br />
* [https://en.wikipedia.org/wiki/Hashed_array_tree Hashed Array Tree]: um hashed array tree (ou HAT) é parecido com um array deque, porém sua estrutura interna faz um melhor uso de memória. Apesar do nome, ela nada tem a ver com tabelas hash.<br />
* [https://en.wikipedia.org/wiki/Unrolled_linked_list Lista ''desenrolada'']: uma lista ''desenrolada'' é parecida com uma lista usual, porém ela possibilita armazenar múltiplos dados em cada nodo da lista. Isso traz algumas vantagens quanto ao uso de memória e localização dos dados.<br />
* [https://en.wikipedia.org/wiki/Bloom_filter Filtros Bloom]: um filtro ''Bloom'' serve para informar sobre a existência ou não de um dado, porém probabilisticamente. Ele pode resultar em falsos positivos, quando retorna verdadeiro para um dado inexistente ou desconhecido, mas nunca retorna falsos negativos. Assim, se um filtro informa que um dado é desconhecido ou inexistente, com certeza isso é verdade. Essa estrutura de dados possui [https://en.wikipedia.org/wiki/Bloom_filter#Examples várias aplicações importantes].<br />
* ... e possivelmente [https://en.wikipedia.org/wiki/List_of_data_structures#Linear_data_structures outras] !!!<br />
<br />
= Descrição da avaliação =<br />
<br />
A realização desse último projeto será avaliada da seguinte forma:<br />
# Cada equipe deve entregar a implementação de sua estrutura de dados, acompanhada de sua documentação<br />
#* A ''implementação'' da estrutura de dados corresponde ao seu código-fonte<br />
#* A ''documentação'' é composta pelo seguinte:<br />
#*# Uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados<br />
#*# Declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados<br />
#*# Instruções sobre como compilar programas que usem a estrutura de dados<br />
# A estrutura de dados deve ser '''avaliada individualmente por colegas de outras equipes''': <br />
#* Cada avaliador deve avaliar uma estrutura de dados, escolhida aleatoriamente pelo professor<br />
#* ''Cada avaliador deve usar a estrutura de dados'': isso implica escrever um programa de teste que verifique cada operação da estrutura de dados<br />
#* ''Avaliação será feita usando um formulário fornecido pelo professor'': esse formulário possuirá itens a serem observados e ponderados na avaliação<br />
#* Cada avaliador deverá entregar ao professor o seu formulário preenchido, acompanhado de comentários sobre como avaliou a estrutura de dados, e os programas de teste que foram criados<br />
# Ao final desse processo, cada estudante será avaliado da seguinte forma:<br />
#* '''Peso 4''': A média das avaliações feitas pelos colegas avaliadores sobre a estrutura de dados de sua equipe<br />
#* '''Peso 6''': A avaliação do professor sobre a qualidade de suas avaliações<br />
#* '''OBS:''' a avaliação será ZERO caso a equipe do estudante não apresente sua estrutura de dados<br />
<br />
'''Datas importantes''':<br />
* 29/09: início do projeto da estrutura de dados<br />
* 13/10: entrega das estruturas de dados pelas equipes, incluindo documentação<br />
* 13/10: sorteio dos avaliadores e início das avaliações por colegas<br />
* 16/10: entrega das avaliações dos colegas<br />
* 20/10: publicação das avaliações pelo professor<br />
<br />
=== Alternativa ===<br />
<br />
O projeto 4 pode ser avaliado desta outra forma:<br />
# Cada equipe deve entregar a implementação de sua estrutura de dados, acompanhada de sua documentação<br />
#* A ''implementação'' da estrutura de dados corresponde ao seu código-fonte<br />
#* A ''documentação'' é composta pelo seguinte:<br />
#*# Uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados<br />
#*# Declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados<br />
#*# Instruções sobre como compilar programas que usem a estrutura de dados<br />
# Cada estudante deve escrever um programa que demonstre o uso da estrutura de dados de sua equipe<br />
#* O problema resolvido deve ser explicado, incluindo como a estrutura de dados foi usada e como ela facilitou a solução<br />
#* Esse programa deve verificar cada operação da estrutura de dados<br />
# Ao final desse processo, cada estudante será avaliado da seguinte forma:<br />
#* '''Peso 4''': A avaliação da estrutura de dados feita por sua equipe<br />
#* '''Peso 6''': A avaliação do seu programa de demonstração<br />
#* '''OBS:''' a avaliação do projeto será ZERO caso o estudante não apresente seu programa de demonstração<br />
<br />
<!--<br />
#* A documentação deve ser composta de uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados, e da declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados. Instruções sobre como compilar programas que usem a estrutura de dados também devem ser incluídas.<br />
#* A implementação da estrutura de dados corresponde ao seu código-fonte<br />
--><br />
<br />
= Requisitos para escrever estruturas de dados =<br />
<br />
O projeto de uma estrutura de dados envolve alguns requisitos. <br />
<br />
O mais evidente é ter clara a '''finalidade da estrutura de dados''', o que significa entender e prever o tipo de uso que se pode fazer dela. Uma consequência desse requisito é identificar as '''operações''' que podem ser feitas sobre essa estrutura de dados. A finalidade da estrutura, e seu conjunto de operações, tem forte correlação com a forma com que os dados são armazenados em memória.<br />
<br />
O requisito seguinte diz respeito à '''organização dos dados em memória''' nessa estrutura de dados. Existem diversas técnicas para armazenar e organizar os dados em memória, de forma que as operações definidas possam ser realizadas com a eficiência projetada. A '''alocação dinâmica de memória''', e esquemas de endereçamento indireto (uso de ponteiros), são comuns ao se projetar o uso de memória em uma estrutura de dados.<br />
<br />
Um outro requisito envolve escolher ou projetar '''algoritmos eficientes''' para as operações da estrutura de dados. Esses algoritmos têm forte dependência da forma com que os dados são organizados em memória. A eficiência desses algoritmos tem relevância, implicando compromissos entre menores tempos computacionais e usos de memória.<br />
<br />
== Alocação de memória ==<br />
<br />
Alocação de memória significa reservar uma certa quantidade de memória do computador para um uso específico pelo programa. A forma mais simples de alocar memória é criar variáveis. Quando se declara uma variável, implicitamente aloca-se a memória necessária para armazenar seu conteúdo. Essa alocação é definida pelo compilador ao se compilar o programa. Para ter uma ideia de como isso funciona, veja este exemplo.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
// Esta função mostra informações sobre uma variável<br />
// Ela é uma função template para funcionar com qualquer tipo de variável<br />
// Parâmetros:<br />
// varname: nome da variável<br />
// val: uma referência à variável a ser mostrada<br />
template <typename T> void mostra(const string & varname, T & val) {<br />
cout << "######################################################" << endl;<br />
<br />
// mostra o valor da variável<br />
cout << varname << " = " << val << endl;<br />
<br />
// mostra o endereço da variável<br />
T * ptr = &val;<br />
cout << "Endereço de " << varname << ": " << (void*)ptr << endl;<br />
<br />
// Mostra a quantidade de memória alocada à variável<br />
cout << "Memória alocada: " << sizeof(T) << " bytes" << endl;<br />
}<br />
<br />
int main() {<br />
// algumas variáveis<br />
// a memória para elas é alocada automaticamente<br />
int x = 35;<br />
float y = 3.1416;<br />
double h = 6.62607015e-34;<br />
char c = 'A';<br />
char v[8] = {'a','b','c','d','e','f','g',0};<br />
<br />
mostra("x", x);<br />
mostra("y", y);<br />
mostra("h", h);<br />
mostra("c", c);<br />
mostra("v", v);<br />
}<br />
</syntaxhighlight><br />
<br />
Ao executá-lo, o resultado é este:<br />
<br />
<syntaxhighlight><br />
######################################################<br />
x = 35<br />
Endereço de x: 0x7ffd895a65e0<br />
Memória alocada: 4 bytes<br />
######################################################<br />
y = 3.1416<br />
Endereço de y: 0x7ffd895a65e4<br />
Memória alocada: 4 bytes<br />
######################################################<br />
h = 6.62607e-34<br />
Endereço de h: 0x7ffd895a65e8<br />
Memória alocada: 8 bytes<br />
######################################################<br />
c = A<br />
Endereço de c: 0x7ffd895a65de<br />
Memória alocada: 1 bytes<br />
######################################################<br />
v = abcdefg<br />
Endereço de v: 0x7ffd895a6610<br />
Memória alocada: 8 bytes<br />
</syntaxhighlight><br />
<br />
Observe que cada variável possui um endereço de memória diferente (mostrado em hexadecimal). Dependendo do tipo de variável, a quantidade de memória alocada pode variar. O que determina quanta memória é necessária é o tipo da variável, não o dado que será armazenado. O compilador sabe quanta memória cada tipo de dados precisa, e por isso reserva a quantidade adequada para cada variável. Essa forma de usar memória é muito prática para o programador, que não precisa se preocupar com a alocação e liberação de memória para suas variáveis. Porém isso apresenta algumas limitações.<br />
<br />
A primeira dificuldade aparece quando não se sabe exatamente quantos dados serão armazenados. Por exemplo, desejam-se armazenar números em um vetor, mas não se sabe exatamente quantos números serão fornecidos ao programa. Se forem usadas variáveis com alocação automática, o programador precisará criar um vetor cujo tamanho deve ser estimado pela quantidade de dados que provavelmente podem ser fornecidos no pior caso. Isso implica dois problemas:<br />
# Se a estimativa estiver incorreta, mais dados do que se pensou podem ser fornecidos e não haveria lugar no vetor para todos eles.<br />
# Se na maioria das vezes a quantidade de dados for bem menor do que o estimado, o vetor terá boa parte de sua capacidade ociosa. Isso significa que o programa estará reservando mais memória do que o necessário, e isso pode ter consequências negativas (lembre que memória é um recurso finito).<br />
<br />
A segunda dificuldade é mais sutil. As variáveis existem apenas no escopo em que foram declaradas. Além de as variáveis de uma função não serem acessíveis em outra função, elas deixam de existir quando termina a função em que foram declaradas. Uma variável deixar de existir significa que a memória a ela alocada foi liberada, e pode ser usada para outros propósitos no programa. Portanto, se uma função armazena dados que devem estar disponíveis em outras funções, uma outra forma de alocar a memória deve ser usada. Esses dados devem ser armazenados em uma área de memória que não seja liberada automaticamente, quando terminar o escopo em que foi alocada. <br />
<br />
Para usar memória sem essas limitações, recorre-se à técnica de [[Introdução_C%2B%2B#Aloca.C3.A7.C3.A3o_din.C3.A2mica_de_mem.C3.B3ria%3A_operadores_new_e_delete|alocação dinâmica de memória]].<br />
<br />
=== CURIOSIDADE: como um processo usa a memória ===<br />
<br />
Um processo, que é um programa em execução, usa memória para guardar tanto seus dados (variáveis e constantes) quanto suas instruções (o programa em si). A forma com que cada processo ocupa a memória depende do sistema operacional. No caso do Linux, o diagrama abaixo mostra de forma simplificada como um processo se organiza em memória (maiores detalhes no link abaixo da figura, e na disciplina de [[SOP29005-2014-1|Sistemas Operacionais da 5a fase]] ... [[MIC-EngTel#MIC29004_-_MICROPROCESSADORES|Microprocessadores da 4a fase]] também ajuda a entender essa questão).<br />
<br />
<br />
[[imagem:Prg2-LinuxFlexibleAddressSpaceLayout.png|500px]]<br />
''<br>Anatomia de um processo em memória<br>(obtido de http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/)''<br />
<br />
<br />
Segundo esse diagrama, um processo aloca regiões de memória para diferentes finalidades. Por exemplo, as instruções de programa ficam no segmento ''Text'', as variáveis dinâmicas alocadas com ''malloc'' (linguagem C) ou operador ''new'' (C++) ficam no segmento ''heap'', e as variáveis locais e argumentos de função ficam em ''stack''.<br />
<br />
=== Experimento: alocação de memória ===<br />
<br />
Compile e use os dois programas a seguir para comparar as limitações na alocação de memória na pilha e no ''heap''. Ao executá-los, informa a quantidade de memória a ser alocada (em MB). Com ambos programas, experimente valores variados, tais como 2, 4, 6, 8, 10, 50, 100, 1000.<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/mempilha.cpp Alocação na pilha]<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/memheap.cpp Alocação no heap]<br />
'''OBS''': você pode compilá-los e executá-los diretamente na linha de comando:<br />
<syntaxhighlight lang="bash"><br />
aluno@micro:~$ g++ -std=c++11 -o mempilha mempilha.cpp<br />
aluno@micro:~$ ./mempilha<br />
</syntaxhighlight></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PRG29003:_Etapa_2:_Projeto_de_estruturas_de_dados&diff=171332PRG29003: Etapa 2: Projeto de estruturas de dados2020-10-22T12:19:47Z<p>Msobral: /* Alternativa */</p>
<hr />
<div>__toc__<br />
<br />
= Introdução =<br />
<br />
Desde o início do semestre foi usada a [https://www.geeksforgeeks.org/the-c-standard-template-library-stl/ biblioteca STL], que contém implementações das estruturas de dados estudadas. Na primeira etapa da disciplina se enfatizou conhecer e usar essas estruturas de dados. Na segunda etapa o foco está no projeto de uma estrutura de dados, e o resultado esperado é a criação de estruturas de dados pelas equipes. Podem ser criadas versões que reproduzam (possivelmente com um toque pessoal) as características das estruturas de dados estudadas, ou mesmo novas estruturas de dados, diferentes daquelas conhecidas.<br />
<br />
As estruturas de dados que já conhecemos são:<br />
* '''Lineares''': filas, pilhas e listas<br />
* '''Associativas''': tabelas hash, conjuntos e árvores de pesquisa binária<br />
<br />
<br />
Mais especificamente os '''objetivos de aprendizagem''' desta unidade são:<br />
<br />
# Desenvolver (criar) uma estrutura de dados que possa ser utilizada em programas, possuindo uma interface de programação bem definida, e incluindo os algoritmos específicos necessários para a eficiência de suas operações quanto ao uso de memória e tempo computacional.<br />
# Avaliar o projeto de uma estrutura de dados, usando sua documentação como referência para emitir um julgamento sobre sua eficiência e usabilidade<br />
<br />
<br />
Algumas das estruturas conhecidas são bastante simples, e não serviriam como objeto de estudo nesta etapa da disciplina (refiro-me especificamente a filas e pilhas). As demais têm complexidade adequada para serem desenvolvidas neste último mês de aula. Além delas, outras estruturas de dados podem ser escolhidas:<br />
* [https://en.wikipedia.org/wiki/Trie Trie]: uma ''trie'' é um tipo de árvore n-ária (que pode ter um número ''n'' de ramos por nodo), em que os dados estão armazenados nos ramos, e não nos nodos. Esse tipo de árvore armazena prefixos dos dados, então são adequadas para dados formados por cadeias de elementos (ex: strings, endereços IP, sequências de bits em geral, ...). Um uso conhecido para tries é como dicionário de termos para um sistema do tipo auto-completar. Uma variação de tries é [https://en.wikipedia.org/wiki/Radix_tree radix tree].<br />
* [https://en.wikipedia.org/wiki/Double-ended_queue#Implementations Array Deques]: um array deque é um tipo de fila que usa um array dinâmico (i.e. que pode ser expandido ou contraído) para armazenar dados. Ela possibilita a inserção e remoção eficiente de dados de seus extremos, e o acesso a qualquer dado pode ser feito com tempo constante (i.e. o custo de tempo computacional dessa operação é ''O(1)'').<br />
* [https://en.wikipedia.org/wiki/Hashed_array_tree Hashed Array Tree]: um hashed array tree (ou HAT) é parecido com um array deque, porém sua estrutura interna faz um melhor uso de memória. Apesar do nome, ela nada tem a ver com tabelas hash.<br />
* [https://en.wikipedia.org/wiki/Unrolled_linked_list Lista ''desenrolada'']: uma lista ''desenrolada'' é parecida com uma lista usual, porém ela possibilita armazenar múltiplos dados em cada nodo da lista. Isso traz algumas vantagens quanto ao uso de memória e localização dos dados.<br />
* [https://en.wikipedia.org/wiki/Bloom_filter Filtros Bloom]: um filtro ''Bloom'' serve para informar sobre a existência ou não de um dado, porém probabilisticamente. Ele pode resultar em falsos positivos, quando retorna verdadeiro para um dado inexistente ou desconhecido, mas nunca retorna falsos negativos. Assim, se um filtro informa que um dado é desconhecido ou inexistente, com certeza isso é verdade. Essa estrutura de dados possui [https://en.wikipedia.org/wiki/Bloom_filter#Examples várias aplicações importantes].<br />
* ... e possivelmente [https://en.wikipedia.org/wiki/List_of_data_structures#Linear_data_structures outras] !!!<br />
<br />
= Descrição da avaliação =<br />
<br />
A realização desse último projeto será avaliada da seguinte forma:<br />
# Cada equipe deve entregar a implementação de sua estrutura de dados, acompanhada de sua documentação<br />
#* A ''implementação'' da estrutura de dados corresponde ao seu código-fonte<br />
#* A ''documentação'' é composta pelo seguinte:<br />
#*# Uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados<br />
#*# Declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados<br />
#*# Instruções sobre como compilar programas que usem a estrutura de dados<br />
# A estrutura de dados deve ser '''avaliada individualmente por colegas de outras equipes''': <br />
#* Cada avaliador deve avaliar uma estrutura de dados, escolhida aleatoriamente pelo professor<br />
#* ''Cada avaliador deve usar a estrutura de dados'': isso implica escrever um programa de teste que verifique cada operação da estrutura de dados<br />
#* ''Avaliação será feita usando um formulário fornecido pelo professor'': esse formulário possuirá itens a serem observados e ponderados na avaliação<br />
#* Cada avaliador deverá entregar ao professor o seu formulário preenchido, acompanhado de comentários sobre como avaliou a estrutura de dados, e os programas de teste que foram criados<br />
# Ao final desse processo, cada estudante será avaliado da seguinte forma:<br />
#* '''Peso 4''': A média das avaliações feitas pelos colegas avaliadores sobre a estrutura de dados de sua equipe<br />
#* '''Peso 6''': A avaliação do professor sobre a qualidade de suas avaliações<br />
#* '''OBS:''' a avaliação será ZERO caso a equipe do estudante não apresente sua estrutura de dados<br />
<br />
'''Datas importantes''':<br />
* 29/09: início do projeto da estrutura de dados<br />
* 13/10: entrega das estruturas de dados pelas equipes, incluindo documentação<br />
* 13/10: sorteio dos avaliadores e início das avaliações por colegas<br />
* 16/10: entrega das avaliações dos colegas<br />
* 20/10: publicação das avaliações pelo professor<br />
<br />
=== Alternativa ===<br />
<br />
O projeto 4 pode ser avaliado desta outra forma:<br />
# Cada equipe deve entregar a implementação de sua estrutura de dados, acompanhada de sua documentação<br />
#* A ''implementação'' da estrutura de dados corresponde ao seu código-fonte<br />
#* A ''documentação'' é composta pelo seguinte:<br />
#*# Uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados<br />
#*# Declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados<br />
#*# Instruções sobre como compilar programas que usem a estrutura de dados<br />
# Cada estudante deve escrever um programa que demonstre o uso da estrutura de dados de sua equipe<br />
#* O problema resolvido deve ser explicado, incluindo como a estrutura de dados foi usada e como ela facilitou a solução<br />
#* Esse programa deve verificar cada operação da estrutura de dados<br />
# Ao final desse processo, cada estudante será avaliado da seguinte forma:<br />
#* '''Peso 4''': A avaliação da estrutura de dados feita por sua equipe<br />
#* '''Peso 6''': A avaliação do seu programa de demonstração<br />
#* '''OBS:''' a avaliação individual será ZERO caso o estudante não apresente seu programa de demonstração<br />
<br />
<!--<br />
#* A documentação deve ser composta de uma ''descrição da estrutura de dados'', que informe seu propósito e como os dados são nela armazenados, e da declaração da API da estrutura de dados devidamente comentada. Essa API é formada pelos tipos de dados e operações (funções) que um programa precisará conhecer para poder usar sua estrutura de dados. Instruções sobre como compilar programas que usem a estrutura de dados também devem ser incluídas.<br />
#* A implementação da estrutura de dados corresponde ao seu código-fonte<br />
--><br />
<br />
= Requisitos para escrever estruturas de dados =<br />
<br />
O projeto de uma estrutura de dados envolve alguns requisitos. <br />
<br />
O mais evidente é ter clara a '''finalidade da estrutura de dados''', o que significa entender e prever o tipo de uso que se pode fazer dela. Uma consequência desse requisito é identificar as '''operações''' que podem ser feitas sobre essa estrutura de dados. A finalidade da estrutura, e seu conjunto de operações, tem forte correlação com a forma com que os dados são armazenados em memória.<br />
<br />
O requisito seguinte diz respeito à '''organização dos dados em memória''' nessa estrutura de dados. Existem diversas técnicas para armazenar e organizar os dados em memória, de forma que as operações definidas possam ser realizadas com a eficiência projetada. A '''alocação dinâmica de memória''', e esquemas de endereçamento indireto (uso de ponteiros), são comuns ao se projetar o uso de memória em uma estrutura de dados.<br />
<br />
Um outro requisito envolve escolher ou projetar '''algoritmos eficientes''' para as operações da estrutura de dados. Esses algoritmos têm forte dependência da forma com que os dados são organizados em memória. A eficiência desses algoritmos tem relevância, implicando compromissos entre menores tempos computacionais e usos de memória.<br />
<br />
== Alocação de memória ==<br />
<br />
Alocação de memória significa reservar uma certa quantidade de memória do computador para um uso específico pelo programa. A forma mais simples de alocar memória é criar variáveis. Quando se declara uma variável, implicitamente aloca-se a memória necessária para armazenar seu conteúdo. Essa alocação é definida pelo compilador ao se compilar o programa. Para ter uma ideia de como isso funciona, veja este exemplo.<br />
<br />
<syntaxhighlight lang="c++"><br />
#include <iostream><br />
#include <string><br />
<br />
using namespace std;<br />
<br />
// Esta função mostra informações sobre uma variável<br />
// Ela é uma função template para funcionar com qualquer tipo de variável<br />
// Parâmetros:<br />
// varname: nome da variável<br />
// val: uma referência à variável a ser mostrada<br />
template <typename T> void mostra(const string & varname, T & val) {<br />
cout << "######################################################" << endl;<br />
<br />
// mostra o valor da variável<br />
cout << varname << " = " << val << endl;<br />
<br />
// mostra o endereço da variável<br />
T * ptr = &val;<br />
cout << "Endereço de " << varname << ": " << (void*)ptr << endl;<br />
<br />
// Mostra a quantidade de memória alocada à variável<br />
cout << "Memória alocada: " << sizeof(T) << " bytes" << endl;<br />
}<br />
<br />
int main() {<br />
// algumas variáveis<br />
// a memória para elas é alocada automaticamente<br />
int x = 35;<br />
float y = 3.1416;<br />
double h = 6.62607015e-34;<br />
char c = 'A';<br />
char v[8] = {'a','b','c','d','e','f','g',0};<br />
<br />
mostra("x", x);<br />
mostra("y", y);<br />
mostra("h", h);<br />
mostra("c", c);<br />
mostra("v", v);<br />
}<br />
</syntaxhighlight><br />
<br />
Ao executá-lo, o resultado é este:<br />
<br />
<syntaxhighlight><br />
######################################################<br />
x = 35<br />
Endereço de x: 0x7ffd895a65e0<br />
Memória alocada: 4 bytes<br />
######################################################<br />
y = 3.1416<br />
Endereço de y: 0x7ffd895a65e4<br />
Memória alocada: 4 bytes<br />
######################################################<br />
h = 6.62607e-34<br />
Endereço de h: 0x7ffd895a65e8<br />
Memória alocada: 8 bytes<br />
######################################################<br />
c = A<br />
Endereço de c: 0x7ffd895a65de<br />
Memória alocada: 1 bytes<br />
######################################################<br />
v = abcdefg<br />
Endereço de v: 0x7ffd895a6610<br />
Memória alocada: 8 bytes<br />
</syntaxhighlight><br />
<br />
Observe que cada variável possui um endereço de memória diferente (mostrado em hexadecimal). Dependendo do tipo de variável, a quantidade de memória alocada pode variar. O que determina quanta memória é necessária é o tipo da variável, não o dado que será armazenado. O compilador sabe quanta memória cada tipo de dados precisa, e por isso reserva a quantidade adequada para cada variável. Essa forma de usar memória é muito prática para o programador, que não precisa se preocupar com a alocação e liberação de memória para suas variáveis. Porém isso apresenta algumas limitações.<br />
<br />
A primeira dificuldade aparece quando não se sabe exatamente quantos dados serão armazenados. Por exemplo, desejam-se armazenar números em um vetor, mas não se sabe exatamente quantos números serão fornecidos ao programa. Se forem usadas variáveis com alocação automática, o programador precisará criar um vetor cujo tamanho deve ser estimado pela quantidade de dados que provavelmente podem ser fornecidos no pior caso. Isso implica dois problemas:<br />
# Se a estimativa estiver incorreta, mais dados do que se pensou podem ser fornecidos e não haveria lugar no vetor para todos eles.<br />
# Se na maioria das vezes a quantidade de dados for bem menor do que o estimado, o vetor terá boa parte de sua capacidade ociosa. Isso significa que o programa estará reservando mais memória do que o necessário, e isso pode ter consequências negativas (lembre que memória é um recurso finito).<br />
<br />
A segunda dificuldade é mais sutil. As variáveis existem apenas no escopo em que foram declaradas. Além de as variáveis de uma função não serem acessíveis em outra função, elas deixam de existir quando termina a função em que foram declaradas. Uma variável deixar de existir significa que a memória a ela alocada foi liberada, e pode ser usada para outros propósitos no programa. Portanto, se uma função armazena dados que devem estar disponíveis em outras funções, uma outra forma de alocar a memória deve ser usada. Esses dados devem ser armazenados em uma área de memória que não seja liberada automaticamente, quando terminar o escopo em que foi alocada. <br />
<br />
Para usar memória sem essas limitações, recorre-se à técnica de [[Introdução_C%2B%2B#Aloca.C3.A7.C3.A3o_din.C3.A2mica_de_mem.C3.B3ria%3A_operadores_new_e_delete|alocação dinâmica de memória]].<br />
<br />
=== CURIOSIDADE: como um processo usa a memória ===<br />
<br />
Um processo, que é um programa em execução, usa memória para guardar tanto seus dados (variáveis e constantes) quanto suas instruções (o programa em si). A forma com que cada processo ocupa a memória depende do sistema operacional. No caso do Linux, o diagrama abaixo mostra de forma simplificada como um processo se organiza em memória (maiores detalhes no link abaixo da figura, e na disciplina de [[SOP29005-2014-1|Sistemas Operacionais da 5a fase]] ... [[MIC-EngTel#MIC29004_-_MICROPROCESSADORES|Microprocessadores da 4a fase]] também ajuda a entender essa questão).<br />
<br />
<br />
[[imagem:Prg2-LinuxFlexibleAddressSpaceLayout.png|500px]]<br />
''<br>Anatomia de um processo em memória<br>(obtido de http://duartes.org/gustavo/blog/post/anatomy-of-a-program-in-memory/)''<br />
<br />
<br />
Segundo esse diagrama, um processo aloca regiões de memória para diferentes finalidades. Por exemplo, as instruções de programa ficam no segmento ''Text'', as variáveis dinâmicas alocadas com ''malloc'' (linguagem C) ou operador ''new'' (C++) ficam no segmento ''heap'', e as variáveis locais e argumentos de função ficam em ''stack''.<br />
<br />
=== Experimento: alocação de memória ===<br />
<br />
Compile e use os dois programas a seguir para comparar as limitações na alocação de memória na pilha e no ''heap''. Ao executá-los, informa a quantidade de memória a ser alocada (em MB). Com ambos programas, experimente valores variados, tais como 2, 4, 6, 8, 10, 50, 100, 1000.<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/mempilha.cpp Alocação na pilha]<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/memheap.cpp Alocação no heap]<br />
'''OBS''': você pode compilá-los e executá-los diretamente na linha de comando:<br />
<syntaxhighlight lang="bash"><br />
aluno@micro:~$ g++ -std=c++11 -o mempilha mempilha.cpp<br />
aluno@micro:~$ ./mempilha<br />
</syntaxhighlight></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PRG29003:_Introdu%C3%A7%C3%A3o_a_%C3%A1rvores_bin%C3%A1rias&diff=170928PRG29003: Introdução a árvores binárias2020-10-06T18:21:43Z<p>Msobral: /* Enumeração dos dados de uma árvore */</p>
<hr />
<div>[[PRG29003:_Etapa_2:_A_construção_da_prglib|Próxima aula]]<br />
<br />
__toc__<br />
<br />
* [http://desciclopedia.org/wiki/Programa%C3%A7%C3%A3o_Orientada_a_Gambiarras POG]<br />
* [http://en.wikipedia.org/wiki/Binary_tree Árvores binárias]<br />
* [https://vincent.bernat.im/en/blog/2017-ipv4-route-lookup-linux Tabela de rotas no Linux]<br />
<br />
<br />
Uma estrutura de dados que possibilita consultas rápidas se chama '''árvore'''. Tal estrutura mantém os dados organizados de forma hierárquica, o que reduz bastante a quantidade de comparações necessárias para se encontrar algum valor. Um exemplo é a '''árvore de diretórios''', que organiza os arquivos em disco em diretórios que formam um diagrama hierarquizado. Esse tipo de estrutura é largamente utilizada em bancos de dados, e também possui diversas aplicações em muitas outras áreas de conhecimento (redes de computadores, análise combinatória, mapas digitais, sistemas de decisão, linguística, diagramas em geral). <br />
<br />
<br />
{| border=0<br />
|[[imagem:Crt-decisao.png|400px]]<br>''Uma árvore de decisão''||[[imagem:prg2-Arvore-binaria-real.png|300px]]<br>''Uma árvore real ... e binária !''<br />
|}<br />
<br />
<br />
<br />
Um exemplo de árvore é mostrado na figura a seguir. A hierarquia inicia em um nodo chamado de ''raiz''. Os demais nodos são conectados de forma hierárquica, sem haver caminhos fechados. Cada nodo possui ''ramos'' que conectam os nodos um nível abaixo na árvore. A quantidade de ramos de um nodo é denominada '''grau do nodo''', e o '''grau da árvore''' é dado pelo maior grau dentre os nodos dessa árvore. Nodos com grau zero (que não possuem ramos) são chamados de ''folhas''. Uma árvore com grau dois (cujos nodos possuem no máximo dois ramos cada) é chamada de '''árvore binária''', sendo a árvore mais simples que se pode criar.<br />
<br />
[[imagem:Prg2-arvores-1.png]]<br />
<br>''Uma pequena árvore binária''<br />
<br />
<br />
= Árvore de Pesquisa Binária =<br />
<br />
* [http://en.wikipedia.org/wiki/Binary_search_tree Árvore de pesquisa binária na Wikipedia]<br />
<br />
Uma nova estrutura de dados chamada ''árvore de pesquisa binária'' proporciona uma grande eficiência no tempo de busca de um dado. Ela também tem outras propriedades interessantes, e que são úteis para resolver diversos problemas. <br />
<br />
Uma '''árvore de pesquisa binária''' é um tipo especial de árvore binária usada para armazenar valores ordenáveis. Nesse tipo de árvore a seguinte propriedade é verificada em todos os seus nodos:<br />
* valores anteriores àquele contido em um nodo ficam na árvore conectada ao ramo esquerdo.<br />
* valores sucessores àquele contido em um nodo ficam na árvore conectada ao ramo direito.<br />
<br />
<br />
Dois exemplos de árvores de pesquisa binárias são mostrados abaixo. No exemplo 1 armazenam-se ''strings'' na árvore, e no exemplo 2 armazenam-se números. Em ambos os casos a propriedade da árvore de pesquisa binária é verificada. Note que os valores à esquerda de um nodo são sempre antecessores ao valor desse nodo, e do lado direito são sempre sucessores. Com isso, a estrutura da árvore de pesquisa binária implicitamente ordena os valores armazenados, o que é útil para diversas aplicações.<br />
<br />
{| border=0<br />
!Exemplo 1<br />
!Exemplo 2<br />
|-<br />
|[[imagem:Prg2-Apb1.png]] ||[[imagem:Prg2-Apb2.png]]<br />
|}<br />
<br />
<br />
Mas por que essa estrutura de dados é eficiente para armazenar um conjunto de dados, para fins de busca ? Basicamente porque, ao hierarquizar os valores, é possível facilmente guardá-los de forma ordenada. Se a árvore estiver bem balanceada (isso é, tem a mesma quantidade de nodos a partir de ambos os ramos de cada nodo), cada comparação da busca divide a quantidade de nodos restante pela metade. Assim, a quantidade de comparações até localizar o valor procurado é limitada superiormente pela '''altura da árvore''' (a quantidade de ramos entre o nodo raiz e o nodo folha mais distante da raiz).<br />
<br />
<br />
Para fins de comparação, imagine que um programa armazene uma grande quantidade de dados em uma lista encadeada ou em uma árvore de pesquisa binária. O custo computacional para localizar um dado em uma lista é <math>O(n)</math>, pois, no pior caso, cada dado procurado pode ser comparado com todos os dados existentes na lista. Se for usada uma '''árvore de pesquisa binária''', esse custo pode ser <math>O(log_2 n)</math>, contanto que certas propriedades da árvore sejam verificadas (isso será discutido mais adiante).<br />
<br />
<br />
Esta introdução, e um resumo do restante da explicação sobre árvores, pode ser vista também neste video.<br />
<br />
<youtube>oSWTXtMglKE</youtube><br />
<br />
= Um exemplo de árvore de pesquisa binária =<br />
* [https://github.com/IFSC-Engtelecom-Prg2/Prg2_Trees Arquivo de projeto CLion com a árvore no Github]<br />
<br />
A biblioteca STL não oferece uma árvore de pesquisa binária genérica. Na verdade, existem ali algumas estruturas de dados que internamente são implementadas usando algo parecido com uma árvore de pesquisa binária, tais como [http://www.cplusplus.com/reference/map/map/ map] e [http://www.cplusplus.com/reference/set/set/ set]. Mas elas não possibilitam explorar as operações típicas desse tipo de árvore, justamente o que queremos para fins de estudo.<br />
<br />
A biblioteca prglib possui uma árvore de pesquisa binária simplificada, que foi criada para fins didáticos. Ela foi implementada como uma classe template, para que a árvore possa armazenar qualquer tipo de dado. No entanto, apenas tipos de dados ordenáveis podem ser armazenados (que possuem uma relação de precedência e implementem os operadores ''=='' e ''<''). A árvore possui operações para adicionar, procurar e remover dados, para listar os dados em profundidade (''in-order'', ''pre-order'' e ''post-order'') ou largura, para iterar os dados (apenas ''in-order''), e para balanceamento AVL. A declaração dessa árvore está a seguir.<br />
<br />
<br />
{{collapse top | A árvore de pesquisa binária da prglib}}<br />
<syntaxhighlight lang=c><br />
template <typename T> class arvore : private BasicTree{<br />
public:<br />
arvore();<br />
//arvore(const arvore<T> & outra);<br />
arvore(const T & dado);<br />
virtual ~arvore();<br />
<br />
// adiciona um dado à árvore<br />
void adiciona(const T& algo);<br />
<br />
// obtém um dado da árvore<br />
const T& obtem(const T & algo) const;<br />
<br />
// obtém o valor da raiz da árvore<br />
const T& obtem() const ;<br />
<br />
// enumera os dados in-order, pre-order, post-order e breadth-first<br />
void listeInOrder(list<T> & result);<br />
void listePreOrder(list<T> & result);<br />
void listePostOrder(list<T> & result);<br />
void listeEmLargura(list<T> & result);<br />
<br />
// retorna a quantidade de dados na árvore<br />
unsigned int tamanho() const;<br />
<br />
// retorna a subárvore esquerda<br />
arvore<T> * esquerda();<br />
<br />
// retorna a subárvore direita<br />
arvore<T> * direita();<br />
<br />
// itera a árvore<br />
void inicia();<br />
bool fim();<br />
T& proximo();<br />
<br />
// itera a árvore de forma reversa<br />
void iniciaPeloFim();<br />
bool inicio();<br />
T& anterior();<br />
<br />
// remove um dado<br />
T remove(const T & algo);<br />
<br />
// retorna o menor dado<br />
T & obtemMenor() const;<br />
<br />
// retorna o maior dado<br />
T & obtemMaior() const;<br />
<br />
// copia na lista "result" os dados menores que "algo"<br />
void obtemMenoresQue(list<T> & result, const T & algo);<br />
<br />
// copia na lista "result" os dados maiores que "algo"<br />
void obtemMaioresQue(list<T> & result, const T & algo);<br />
<br />
// obtém todos valores entre "start" e "end" (inclusive)<br />
void obtemIntervalo(list<T> & result, const T & start, const T & end);<br />
<br />
// retorna a altura da folha mais distante da raiz<br />
unsigned int altura() ;<br />
<br />
// retorna o fator de balanceamento<br />
int fatorB() ;<br />
<br />
// balanceia a árvore<br />
arvore<T> * balanceia();<br />
<br />
// balanceia a árvore repetidamente, até que a altura não mais se reduza<br />
arvore<T> * balanceia(bool otimo);<br />
};<br />
</syntaxhighlight>''arvore.h''<br />
{{collapse bottom}}<br />
<br />
<br />
Um exemplo de uso de uma pequena árvore binária é este:<br />
<br />
<syntaxhighlight lang=c><br />
#include <iostream><br />
#include <prglib.h><br />
<br />
using namespace std;<br />
<br />
using prglib::arvore;<br />
<br />
/*<br />
* <br />
*/<br />
int main(int argc, char** argv) {<br />
<br />
arvore<int> * a = new arvore<int>(10);<br />
<br />
a->adiciona(5);<br />
a->adiciona(7);<br />
a->adiciona(2);<br />
a->adiciona(13);<br />
a->adiciona(11);<br />
a->adiciona(15);<br />
<br />
// testando se dado existe na árvore<br />
int y;<br />
<br />
cout << "Digite um número: ";<br />
cin >> y;<br />
try {<br />
auto & x = a->obtem(y);<br />
cout << y << " existe !" << endl;<br />
} catch (...) {<br />
cout << y << " NÃO existe !" << endl;<br />
}<br />
<br />
// enumerando os dados ... eles devem aparecer em ordem crescente !<br />
list<int> l;<br />
a->listeInOrder(l);<br />
<br />
cout << "In-order: ";<br />
for (auto & x: l) {<br />
cout << x << ", ";<br />
}<br />
cout << endl;<br />
<br />
return 0;<br />
}<br />
</syntaxhighlight><br />
<br />
== Atividade ==<br />
<br />
Resolva estes exercícios:<br />
* [https://github.com/IFSC-Engtelecom-Prg2/Arvores_TopoSimples/blob/master/Readme.md Criação de uma árvore de pesquisa binária com topologia simples]<br />
* [https://github.com/IFSC-Engtelecom-Prg2/Arvores_ConsultarDados Consultar dados contidos em uma árvore]<br />
<br />
= Eficiência da árvore de pesquisa binária =<br />
<br />
A eficiência das árvores de pesquisa binária para armazenar dados de forma que possam ser localizados rapidamente depende de como esses dados ficam distribuídos na árvore. Se a árvore estiver desequilibrada (desbalanceada), a eficiência nas buscas será reduzida. Hoje veremos alguns fatores relacionados ao balanceamento de árvores, e como garantir que uma árvore fique bem equilibrada.<br />
<br />
== Quão eficiente ficou sua árvore ? ==<br />
<br />
Uma árvore fica mais eficiente se estiver balanceada. Isso significa que, para cada nodo da árvore, as alturas dos ramos esquerdo e direito diferem em no máximo uma unidade. Se uma árvore possuir essa propriedade, sua altura será minimizada e assim as buscas serão mais rápidas. Para entender porque, veja que uma árvore com altura ''h'' pode conter uma certa quantidade de nodos:<br />
<br />
{| border="1"<br />
!Altura<br />
!Nodos (máximo)<br />
!Exemplo<br />
|-<br />
|0|| 1|| <center>[[imagem:Prg2-H0.png|20px]]</center><br />
|-<br />
|1|| 3||<center>[[imagem:Prg2-H1.png|50px]]</center><br />
|-<br />
|2|| 7||<center>[[imagem:Prg2-H2.png|100px]]</center><br />
|-<br />
|3|| 15||[[imagem:Prg2-H3.png|150px]]<br />
|}<br />
<br />
<br />
De forma geral, a quantidade máxima de nodos que cabem em uma árvore binária com altura ''h'' é dada por esta recorrência:<br />
<br />
<math>N_h = 1 + 2 \cdot N_{h-1}</math><br />
<br />
<br />
... sendo que <math>N_0 = 1</math>. A recorrência acima pode ser escrita mais diretamente como:<br />
<br />
<math>N_h = 2^{h+1}-1</math><br />
<br />
<br />
Usando esta relação, pode-se descobrir qual a menor altura possível para uma árvore que contenha ''N'' nodos:<br />
<br />
<math>h = -1 + \lceil log_{2}(1 + N) \rceil</math><br />
<br />
<br />
Na prática, as árvores que criamos não estão otimizadas. Porém iremos comparar as alturas dessas árvores com a altura mínima possível para ter uma ideia de quão eficientes elas são.<br />
<br />
<br />
O cálculo da altura de uma árvore ''A'' pode ser feito segundo esta recorrência:<br />
<br />
<math>h(A)=\begin{cases}<br />
0, \text{if } A_{esq} = NULL \and A_{dir} = NULL \\<br />
1+max(h(A_{esq}), h(A_{dir})), \text{caso contrario} \\<br />
\end{cases}<br />
</math><br />
<br />
== Fator de balanceamento ==<br />
<br />
O fator de balanceamento é a diferença entre as alturas das árvores esquerda e direita, e pode ser calculado assim:<br />
<br />
<br />
<math>F_b = altura(esquerda) -altura(direita)</math><br />
<br />
<br />
Se para todos os nodos da árvore <math>\lVert F_b <= 1 \rVert</math>, então a árvore está balanceada e nada precisa ser feito. Porém se para algum nodo <math>\lVert F_b > 1 \rVert</math>, então existe um desequilíbrio (má distribuição de nodos), o qual pode ser corrigido.<br />
<br />
== Criação de árvores balanceadas ==<br />
<br />
Para criar uma árvore balanceada, pode-se fazer o seguinte:<br />
* '''Se a árvore for criada a partir de um conjunto de dados já disponível''': uma boa técnica é embaralhar os dados e depois criar a árvore. Isso cria uma árvore aceitavelmente balanceada, se bem que não de forma otimizada. Um ajuste pode ser feito no balanceamento usando-se um algoritmo apropriado.<br />
* '''Se os dados forem acrescentados gradualmente à árvore''': correções em seu balanceamento devem ser feitas periodicamente usando-se um algoritmo apropriado.<br />
<br />
<br />
Em ambos os casos, um algoritmo de balanceamento é útil para fazer com que a árvore fique bem equilibrada. Um desses algoritmos é apresentado a seguir.<br />
<br />
=== Atividade ===<br />
<br />
# Crie a árvore que armazena as [https://wiki.sj.ifsc.edu.br/images/1/16/Palavras.zip palavras contidas neste arquivo]. Observe que essas palavras estão '''ordenadas'''.<br />
# Investigue a altura e fator de balanceamento dessa árvore<br />
# Procure modificar a ordem em que as palavras são adicionadas à árvore, de forma que sua altura diminua.<br />
<br />
== Balanceamento ==<br />
<br />
* [http://en.wikipedia.org/wiki/AVL_tree AVL Tree]<br />
<br />
Nos experimentos feitos até agora, as '''árvores de pesquisa binária''' apresentaram um bom desempenho tanto para serem criadas quanto para pesquisarem valores. Foi estudado que isso se deve a uma importante propriedade da árvore binária, que limita à altura da árvore a quantidade de operações de comparação em uma pesquisa qualquer. Como a altura é função do logaritmo da quantidade de nodos, ela tende a crescer muito lentamente com o aumento da quantidade de nodos da árvore (ex: uma árvore com pouco mais 2.3 milhões de nodos teria altura de pelo menos 21). Porém isso depende de os nodos estarem igualmente distribuídos dos dois lados da árvore. Em outras palavras, '''a árvore deve estar balanceada'''.<br />
<br />
A árvore disponibilizada na ''prglib'' pode ser balanceada usando o algoritmo clássico [http://en.wikipedia.org/wiki/AVL_tree AVL]. Mas outras abordagens existem, tais como [https://en.wikipedia.org/wiki/Red%E2%80%93black_tree árvores vermelho-preto]. A abordagem AVL é mais simples de implementar que RBT, porém a segunda funciona melhor para árvores que são frequentemente modificadas. Uma [https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#Applications_and_related_data_structures interessante comparação entre árvores AVL e Vermelho-Preto] pode ser lida na Wikipedia:<br />
<br />
<syntaxhighlight lang=text><br />
Red–black trees offer worst-case guarantees for insertion time, deletion time, and search time. <br />
Not only does this make them valuable in time-sensitive applications such as real-time applications, <br />
but it makes them valuable building blocks in other data structures which provide worst-case <br />
guarantees; for example, many data structures used in computational geometry can be based on <br />
red–black trees, and the Completely Fair Scheduler used in current Linux kernels uses red–black <br />
trees.<br />
<br />
The AVL tree is another structure supporting O(log n) search, insertion, and removal. It is more <br />
rigidly balanced than red–black trees, leading to slower insertion and removal but faster retrieval. <br />
This makes it attractive for data structures that may be built once and loaded without <br />
reconstruction, such as language dictionaries (or program dictionaries, such as the opcodes of an <br />
assembler or interpreter).<br />
</syntaxhighlight><br />
<br />
<br />
No caso da árvore da ''prglib'', o balanceamento pode ser realizado por meio do método ''balanceia'':<br />
<br />
<syntaxhighlight lang=c><br />
// balanceia a arvore usando o algoritmo AVL. <br />
// Retorna a raiz da nova arvore ... pois o algoritmo pode modificar a raiz.<br />
arvore<T> * balanceia();<br />
<br />
// Balanceia o melhor possivel a arvore. Executa o método ''balanceia()'' repetidas<br />
// vezes, até que a altura da árvore não mais reduza.<br />
arvore<T> * balanceia(bool otimo);<br />
</syntaxhighlight><br />
<br />
<br />
Um exemplo de como utilizá-lo é mostrado a seguir:<br />
<br />
<syntaxhighlight lang=c><br />
int main() {<br />
arvore<int> * arv = new arvore<int>(5);<br />
<br />
arv->adiciona(4);<br />
arv->adiciona(3);<br />
arv->adiciona(2);<br />
arv->adiciona(1);<br />
arv->adiciona(0);<br />
<br />
// a arvore "arv" está totalmente desbalanceada, tendo todos os nodos do lado esquerdo<br />
// Mostra seu fator de balanceamento e sua altura<br />
cout << "Altura: " << arv->altura() << endl;<br />
cout << "Fator de balanceamento: " << arv->fatorB() << endl;<br />
<br />
// balanceia a arvore<br />
arv = arv->balanceia();<br />
<br />
// Mostra novamente seu fator de balanceamento e sua altura<br />
cout << "Altura: " << arv->altura() << endl;<br />
cout << "Fator de balanceamento: " << arv->fatorB() << endl;<br />
<br />
// destroi a arvore<br />
delete arv;<br />
} <br />
</syntaxhighlight><br />
<br />
== Atividade ==<br />
<br />
# Crie a árvore que armazena as [http://tele.sj.ifsc.edu.br/~msobral/prg2/portugues.zip palavras contidas neste arquivo].<br />
# Investigue a altura e fator de balanceamento dessa árvore<br />
# Balanceie sua árvore, e verifique o novo fator de balanceamento e altura. Compare-os com a menor altura possível teoricamente.<br />
# E se a árvore fosse criada aos poucos ? Como ela poderia ser mantida balanceada ?<br />
# Escreva uma função que gere um diagrama de uma árvore. Para isso, sua função deve gerar uma string que represente uma especificação de uma árvore no [https://www.graphviz.org/doc/info/lang.html formato .dot] (definido pelo software [https://www.graphviz.org/ Graphviz]). Essa string pode ser gravada em um arquivo a partir do qual, usando o programa [https://graphviz.gitlab.io/_pages/pdf/dotguide.pdf dot], pode-se gerar um arquivo de imagem contendo um desenho da árvore.<br><br>O formato ''dot'' é bem simples, ao menos para desenhar uma árvore. O exemplo a seguir mostra o diagrama de uma árvore e a especificação ''dot'' correspondente:<br />
<br />
{|border=1<br />
!Diagrama<br />
!Especificação<br />
|-<br />
| [[imagem:prg2-Tree-diagrama.png|300px]]||<syntaxhighlight lang=text><br />
strict graph {<br />
laranja -- cereja<br />
laranja -- morango<br />
cereja -- banana<br />
cereja -- figo<br />
morango -- mamao<br />
morango -- tangerina<br />
}</syntaxhighlight><br />
|}<br />
<br />
<br />
Para gerar um arquivo de imagem a partir de uma especificação ''dot'', pode-se usar este comando:<br />
<br />
<syntaxhighlight lang=bash><br />
dot -Tpng arquivo.dot > arquivo.png<br />
</syntaxhighlight><br />
<br />
<br />
A função a ser criada se chama ''gera_diagrama_arvore'':<br />
<br />
<syntaxhighlight lang=c><br />
// a função deve ser um template, pois deve funcionar com qualquer tipo de árvore<br />
template <typename T> string gera_diagrama_arvore(arvore<T> * raiz) {<br />
// corpo da função<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
Para implementá-la, será necessário usar ao menos estes métodos da árvore:<br />
<br />
<syntaxhighlight lang=c><br />
// obtém o valor da raiz da árvore<br />
const T& obtem() const ;<br />
<br />
// retorna a subárvore esquerda<br />
arvore<T> * esquerda();<br />
<br />
// retorna a subárvore direita<br />
arvore<T> * direita();<br />
</syntaxhighlight><br />
<br />
<br />
6. Use a função ''gera_diagrama_arvore'' para gerar diagramas de árvores antes e após seus balanceamentos. Visualize esses diagramas e compare-os !<br />
<br />
<br />
Feito esse aquecimento:<br />
# Crie uma árvore de pesquisa binária contendo as palavras [http://tele.sj.ifsc.edu.br/~msobral/prg2/portugues.zip deste arquivo].<br />
# Após criar uma árvore balanceada, procure cada uma das palavras contidas na árvore. Meça quanto tempo levou para encontrá-las (média, menor e maior valor)<br />
## Repita a medição, mas ao invés de guardar as palavras em uma árvore, guarde-as em uma lista.<br />
## Repita a medição, mas ao invés de guardar as palavras em uma árvore, guarde-as em uma tabela hash.<br />
## Compare os tempos gastos em cada caso ...<br />
<br />
{{collapse top | Como medir tempo decorrido}}<br />
Use a função [http://manpages.ubuntu.com/manpages/trusty/man3/clock.3.html clock], que retorna um número correspondente ao valor do relógio do computador (OBS: precisa de ''#include <time.h>'').<br />
<br />
<syntaxhighlight lang=c><br />
clock_t c1 = clock();<br />
<br />
cout << "Testando clock ..." << endl;<br />
cout.flush();<br />
<br />
clock_t c2 = clock();<br />
<br />
// calcula o tempo decorrido<br />
double dt = c2 - c1;<br />
cout << dt << "ticks = " << (float)dt/CLOCKS_PER_SEC << " s" << endl;<br />
<br />
</syntaxhighlight><br />
{{collapse bottom}}<br />
<br />
= Enumeração dos dados de uma árvore =<br />
<br />
Até o momento nos concentramos em operações básicas de árvores. Elas possibilitam criar e adicionar dados a uma árvore, e pesquisar por um dado em função de um dado específico. Porém outras formas de acessar os dados de uma árvore podem ser úteis, dentre elas o acesso sequencial de acordo com uma determinada ordem. Por exemplo, pode-se desejar acessar os dados de uma árvore de forma ordenada. Assim, devem-se conhecer as quatro ordens de visitação de nodos de uma árvore:<br />
<!--* '''In order:''' visitam-se nodos na sequência esquerda, raiz, direita. O resultado é o acesso ordenado em função das chaves.<br />
* '''Pre order:''' visitam-se nodos na sequência raiz, esquerda, direita. O resultado é uma ordem de acesso que revela a topologia da árvore.<br />
* '''Post order:''' visitam-se nodos na sequência esquerda, direita, raiz. O resultado é uma ordem de acesso das folhas em direção à raiz.<br />
* '''Level order:''' visitam-se nodos cada nível por vez, da esquerda pra direita.<br />
--><br />
<br />
{| border=1<br />
!Tipo<br />
!Descrição<br />
!Exemplo<br />
|-<br />
|'''In order'''||visitam-se nodos na sequência esquerda, raiz, direita. O resultado é o acesso ordenado em função das chaves||[[imagem:Prg2-Inorder.gif]]<br />
|-<br />
|'''Pre order''' ||visitam-se nodos na sequência raiz, esquerda, direita. O resultado é uma ordem de acesso que revela a topologia da árvore||[[imagem:Prg2-Preorder.gif]]<br />
|-<br />
|'''Post order''' ||visitam-se nodos na sequência esquerda, direita, raiz. O resultado é uma ordem de acesso das folhas em direção à raiz||[[imagem:Prg2-Postorder.gif]]<br />
|-<br />
|'''Level order'''|| visitam-se nodos cada nível por vez, da esquerda pra direita||[[imagem:Prg2-Levelorder.gif]]<br />
|}<br />
<br />
As três primeiras formas de acesso são do tipo '''busca em profundidade''', pois implicam descer até as folhas de um lado antes de visitarem o outro lado da árvore. A última forma de acesso é do tipo '''busca em largura''', pois os nodos são visitados por nível da árvore.<br />
<br />
<br />
Cada uma das formas de acesso tem sua aplicações em algoritmos. Por exemplo, ''in order'' serve para ordenar os dados, ''pre order'' pode ser usada para copiar uma árvore, e ''post order'' pode ser usado para destruir uma árvore. Alguns algoritmos já criados usam algumas dessas formas de acesso (ex: ''escrevaSe'' é do tipo ''in order''; o destrutor da árvore e ''altura'' são do tipo ''post order''). Hoje será visto como usar métodos que enumeram os dados de uma árvore segundo essas sequências de acesso.<br />
<br />
A enumeração dos dados está disponível de duas maneiras:<br />
# '''Operações que copiam os dados para uma lista''': esta forma de enumerar os dados é bem direta, bastando passar uma lista como parâmetro:<syntaxhighlight lang=c><br />
void listeInOrder(lista<T> & result);<br />
void listePreOrder(lista<T> & result);<br />
void listePostOrder(lista<T> & result);<br />
void listeEmLargura(lista<T> & result);<br />
</syntaxhighlight><br />
# '''Iteradores''': a árvore oferece iteradores do tipo ''in-order'' e ''pre-order'', ambos em suas versões diretas e reversas. Eles podem ser usados facilmente em laços: <syntaxhighlight lang=c><br />
// iteradores diretos ...<br />
preorder_iterator preorder_begin();<br />
preorder_iterator preorder_end() const;<br />
inorder_iterator inorder_begin();<br />
inorder_iterator inorder_end() const;<br />
// iteradores reversos ...<br />
preorder_riterator preorder_rbegin();<br />
preorder_riterator preorder_rend() const;<br />
inorder_riterator inorder_rbegin();<br />
inorder_riterator inorder_rend() const;<br />
</syntaxhighlight>Por exemplo, para acessar os dados em ordem crescente pode-se fazer assim (''arv'' é o ponteiro para a raiz):<syntaxhighlight lang=c><br />
for (auto it = arv->inorder_begin(); it != arv->inorder_end(); it++) {<br />
cout << "Dado: " << *it << endl;<br />
}<br />
</syntaxhighlight><br />
#* Um caso especial da iteração é usar um laço de iteração simplificado. Isso resulta em uma iteração in-order (note que é necessário referenciar o ponteiro da raiz da árvore): <syntaxhighlight lang=c><br />
for (auto & dado: *arv) {<br />
cout << "Dado: " << dado << endl;<br />
}<br />
</syntaxhighlight><br />
<br />
<br />
== Atividade ==<br />
<br />
Resolva estes exercícios:<br />
# [https://github.com/IFSC-Engtelecom-Prg2/Arvores_CompararArvores Comparador de árvores]<br />
# [https://github.com/IFSC-Engtelecom-Prg2/Arvore_GravaBalanceada Gravador de árvore balanceada]<br />
# [https://github.com/IFSC-Engtelecom-Prg2/Arvores_CopiaArvore Copiar uma árvore]<br />
<br />
= Outras operações da árvore de pesquisa binária =<br />
<br />
Outras operações estão disponíveis na árvore de pesquisa binária da prglib. Abaixo segue um resumo dos tipos de operações e respectivos métodos da classe ''arvore''.<br />
<br />
* '''Remoção de um dado:''' <syntaxhighlight lang=c><br />
// remove um dado<br />
T remove(const T & algo);<br />
</syntaxhighlight><br />
* '''Busca pelo menor ou maior valor contido na árvore:''' <syntaxhighlight lang=c><br />
// obtém uma referência ao menor dado<br />
T & obtemMenor() const;<br />
<br />
// obtém uma referência ao maior dado<br />
T & obtemMaior() const;<br />
<br />
// obtém uma lista com os dados menores ou maiores que algo<br />
void obtemMenoresQue(lista<T> & result, const T & algo);<br />
void obtemMaioresQue(lista<T> & result, const T & algo);<br />
</syntaxhighlight><br />
* '''Busca de dados dentro de um intervalo:''' <syntaxhighlight lang=c><br />
// obtém todos valores entre "start" e "end" (inclusive)<br />
void obtemIntervalo(lista<T> & result, const T & start, const T & end);<br />
</syntaxhighlight><br />
* '''Acesso ao dado da raiz:''' <syntaxhighlight lang=c><br />
// obtém uma referência ao dado contido na raiz<br />
const T& obtem() const ;<br />
</syntaxhighlight><br />
* '''Acesso às subárvores esquerda e direita:'''<syntaxhighlight lang=c><br />
// obtém a raiz da subárvore esquerda (nullptr caso não exista)<br />
arvore<T> * esquerda();<br />
<br />
// obtém a raiz da subárvore direita (nullptr caso não exista)<br />
arvore<T> * direita();<br />
</syntaxhighlight><br />
<br />
== Atividade ==<br />
<br />
Resolva estes exercícios:<br />
# [https://moodle.sj.ifsc.edu.br/mod/vpl/view.php?id=5672 Busca de uma faixa de valores (não pode usar ''obtemIntervalo'' !)]<br />
# [https://moodle.sj.ifsc.edu.br/mod/vpl/view.php?id=5676 Busca palavras por sufixo]<br />
# [https://moodle.sj.ifsc.edu.br/mod/vpl/view.php?id=5669 Refaça este exercício sem usar iteração da árvore]<br />
<br />
= Alguns outros tipos de árvores =<br />
<br />
== Árvores de expressão binária ==<br />
<br />
Árvores binárias podem ter outras aplicações além de armazenar dados de forma a possibilitar buscas eficientes. A representação de expressões aritméticas e algébricas é outro uso de árvores. Essas expressões também possuem uma hierarquia, dada pela precedência de operadores, o que as torna passíveis de serem representadas por árvores. Uma vez transformada em uma árvore binária, uma expressão pode ser facilmente avaliada, obtendo-se seu resultado. Esse tipo de árvore é chamado de [http://en.wikipedia.org/wiki/Binary_expression_tree árvore de expressão binária].<br />
<br />
<br />
[[imagem:Prg2-Bet1.jpg]]<br />
<br>''Uma árvore de expressão binária para a expressão (a+b)*c+7''<br />
<br />
Note-se que ness tipo de árvore as folhas são operandos (constantes ou variáveis), e demais nodos são operadores aritméticos. A topologia da árvore deve respeitar a precedência dos operadores, para que o resultado da expressão possa ser obtido (isso se faz ao percorrê-la segundo ''in-order'').<br />
<br />
Árvores de expressão binária são úteis para resolver expressões fornecidas em tempo de execução. Por exemplo, uma calculadora pode permitir que o usuário digite uma expressão a ser calculada, que é lida portanto como uma ''string''. Para resolvê-la, pode-se transformá-la em uma árvore binária, e então calculá-la. Assim, qualquer programa que precise resolver expressões fornecidas pelo usuário pode usar essa técnica para avaliá-las.<br />
<br />
=== Avaliando uma expressão contida em um árvore de expressão binária ===<br />
<br />
Uma árvore de expressão binária devidamente construída pode ser facilmente avaliada se for percorrida ''in-order''. O algoritmo basicamente funciona assim:<br />
<br />
<syntaxhighlight lang=text><br />
algoritmo resolveExpressao(arvore):<br />
Entrada: uma arvore de expressão binária<br />
Saída: o resultado da expressão após sua avaliação<br />
Variáveis locais: operador (tipo caractere), resultado (tipo ponto flutuante)<br />
<br />
se arvore for vazia: retorne 0<br />
<br />
se arvore for folha: retorne valor da folha<br />
<br />
operador = raiz da arvore<br />
Escolha (operador):<br />
caso '+': <br />
resultado = resolveExpressao(arvore esquerda) + resolveExpressao(arvore direita)<br />
caso '-': <br />
resultado = resolveExpressao(arvore esquerda) - resolveExpressao(arvore direita)<br />
caso '*': <br />
resultado = resolveExpressao(arvore esquerda) * resolveExpressao(arvore direita)<br />
caso '/': <br />
resultado = resolveExpressao(arvore esquerda) / resolveExpressao(arvore direita)<br />
caso '%': <br />
resultado = resolveExpressao(arvore esquerda) % resolveExpressao(arvore direita)<br />
caso '^': <br />
resultado = resolveExpressao(arvore esquerda) ^ resolveExpressao(arvore direita)<br />
fim Escolha<br />
retorne resultado<br />
fim resolveExpressao<br />
</syntaxhighlight><br />
<br />
=== Construção de uma árvore de expressão binária ===<br />
<br />
A construção automática da árvore inicia com um vetor ou lista composta por um nodo raiz para cada token da expressão. Em seguida, agrupam-se sistematicamente os nodos em árvores cujas raízes sejam operadores. Isso deve ser feito respeitando a precedência dos operadores. O funcionamento desse algoritmo pode ser visualizado pela seguinte sequência de diagramas, que mostra o agrupamento dos nodos de acordo com a precedência de operadores, até que no final haja somente uma árvore:<br />
<br />
<br />
[[imagem:Prg2-Alg-aeb.png|400px]]<br />
<br />
<br />
... e então ? Será que é fácil escrever tal algoritmo ?<br />
<br />
== Radix tree (trie) ==<br />
<br />
* [https://en.wikipedia.org/wiki/Trie Trie na Wikipedia]<br />
<br />
<br />
Um ''trie'', ou ''radix tree'', é um tipo de árvore em que as chaves não estão nos nodos e sim nas transições. A chave associada a cada nodo depende da posição do nodo em relação à raiz, tomando-se as transições necessárias para chegar a tal nodo. Valores podem estar associados a folhas e nodos de interesse. Esse tipo de árvore, que NÃO NECESSARIAMENTE É BINÁRIA, é útil para representar conjuntos de dados que podem ser pesquisados por seus prefixos. Exemplos de aplicações são [http://www.nada.kth.se/~snilsson/fast-routing/ tabelas de roteamento em roteadores] e armazenamento de palavras de dicionário (em particular quando se desejam sugerir palavras a partir de suas letras iniciais).<br />
<br />
<br />
A figura a seguir exemplifica um ''trie''.<br />
<br />
[[imagem:Prg2-Trie_example.svg.png]]<br />
<br>''Exemplo de trie (obtido na [https://en.wikipedia.org/wiki/Trie Wikipedia])''<br />
<br />
== Árvores B ==<br />
<br />
* [https://pt.wikipedia.org/wiki/%C3%81rvore_B Árvore B na Wikipedia]<br />
<br />
<br />
Árvores B têm grau arbitrário, e em seus nodos múltiplos dados podem ser armazenados. Se o grau de um nodo dessa árvore for N, a ordem desse nodo (quantidade de dados nele contidos) é N-1. Esse tipo de árvore costuma ser usada para indexar dados em mídia secundária (ex: discos), pois reduz a quantidade de acessos necessários para obter os dados. Além disso, árvores B são auto-balanceadas e possibilitam pesquisas, acesso sequencial, inserções e remoções em tempo logarítmico (ver [https://pt.wikipedia.org/wiki/%C3%81rvore_B verbete na Wikipedia]).<br />
<br />
<br />
[[imagem:prg2-B-tree-definition.png|600px]]<br />
<br>''Exemplo de árvore B ([https://commons.wikimedia.org/wiki/File:B-tree-definition.png Fonte])''<br />
<br />
== Árvores binárias no kernel Linux ==<br />
<br />
* [http://tele.sj.ifsc.edu.br/~msobral/prg2/kernel-ds.pdf Estruturas de dados disponíveis dentro do kernel Linux] ''(cap. 6 do livro [https://www.amazon.com/Linux-Kernel-Development-Robert-Love/dp/0672329468/ref=as_li_ss_tl?ie=UTF8&tag=roblov-20 Linux Kernel Development, 3rd ed., de Robert Love, 2010])''<br />
<br />
<br />
Algumas estruturas de dados estão disponíveis para uso dentro do [https://en.wikipedia.org/wiki/Linux_kernel kernel Linux]. Há filas, listas, tabelas hash e árvores binárias para ajudar no desenvolvimento tanto do kernel quanto de módulos e [https://en.wikipedia.org/wiki/Device_driver device drivers]. Elas não se destinam ao desenvolvedor de aplicações, e sim a desenvolvedores do kernel (esperem a [[SOP-EngTel_(Plano_de_Ensino)|disciplina de SOP]] para entender melhor isso). <br />
<br />
<br />
Com respeito a árvores binárias, destaca-se este parágrafo ao final do capítulo do livro:<br />
<br />
<syntaxhighlight lang=text><br />
If you need to store a large amount of data and look it up efficiently, consider a red-<br />
black tree. Red-black trees enable the searching in logarithmic time, while still providing<br />
an efficient linear time in-order traversal.Although more complicated to implement than<br />
the other data structures, their in-memory footprint isn’t significantly worse. If you are<br />
not performing many time-critical look-up operations, a red-black tree probably isn’t<br />
your best bet. In that case, favor a linked list.<br />
</syntaxhighlight></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PTC29008:_Projeto_2:_Sistema_de_aquisi%C3%A7%C3%A3o_de_dados&diff=170867PTC29008: Projeto 2: Sistema de aquisição de dados2020-10-01T21:59:58Z<p>Msobral: /* Formato das mensagens da aplicação */</p>
<hr />
<div>[[PTC29008:_Verifica%C3%A7%C3%A3o_de_Protocolos|Próxima aula]]<br />
<br />
__toc__<br />
<br />
* [http://mqtt.org/ Site oficial do MQTT]<br />
* [https://mosquitto.org/ Mosquitto: um broker MQTT]<br />
<br />
<br />
No projeto 2 será desenvolvido um protótipo de um sistema de aquisição de dados. Cada unidade de aquisição de dados, representada por um kit baseado em RaspberryPi 3, é responsável por coletar dados de monitoramento e enviá-los para um servidor de coleta. A comunicação entre as unidades e o servidor se dá por links sem-fio ponto-a-ponto, implantados com o [[PTC29008:_Projeto_1:_um_protocolo_de_comunicação|protocolo do projeto 1]]. A figura a seguir ilustra um cenário desse sistema de aquisição de dados remotos.<br />
<br />
[[imagem:PTC-Proj2-aquisicao-dados.jpg|640px]]<br />
<br>''O sistema de aquisição de dados remotos''<br />
<br />
<br />
Nesse sistema, a transmissão de mensagens de dados através dos links sem-fio faz uso do [https://mqtt.org/ protocolo MQTT]. Esse protocolo foi desenhado com um serviço do tipo publisher-subscriber voltado a dispositivos com restrições de recursos, tendo em mente aplicações da [https://en.wikipedia.org/wiki/Internet_of_things Internet das Coisas (IoT)]. Em linhas gerais, as unidades de aquisição de dados se comportam como publicadores MQTT, o servidor de coleta é um assinante.<br />
<br />
<br />
O projeto tem por objetivo geral '''implementar a unidade de aquisição de dados''', a qual monitora dados ambientais e os envia para o servidor de coleta. Os objetivos específicos são:<br />
# Especificar um protocolo de aplicação, que deve estar fundado no protocolo MQTT: esse protocolo de aplicação deve ser capaz de:<br />
## Configurar a unidade de aquisição de dados<br />
## Transmitir mensagens contendo dados monitorados<br />
# Selecionar e usar uma implementação do MQTT, com a finalidade de enviar as mensagens de aquisição de dados<br />
# Usar uma técnica de codificação de mensagens que possibilite o intercâmbio de dados entre sistemas heterogêneos<br />
<br />
= A especificação do protocolo de aplicação =<br />
<br />
A especificação deve descrever:<br />
# o serviço oferecido<br />
# as mensagens do protocolo<br />
# o formato dessas mensagens<br />
# o comportamento do protocolo<br />
<br />
== Formato das mensagens da aplicação ==<br />
<br />
As mensagens da aplicação são de dois tipos:<br />
* '''Configuração:''' trocadas no início da sessão, servem para identificar os sensores e o período de amostragem e transmissão de dados. Seu conteúdo é formado pelo seguinte:<br />
*# Placa se anuncia ao servidor: <br />
*#* mensagem de configuração é publicada em um subtópico que identifica a placa. <br />
*#* mensagem de configuração contém a lista de sensores da placa. Cada sensor possui estes atributos: status (se está ativado), tipo (ex: temperatura, pressão, ...), peeríodos de amostragem e de envio, limiares inferior e superior para alertas.<br />
*# servidor configura a placa:<br />
*#* mensagem de configuração enviada para o subtópico da placa<br />
*#* mensagem contém os atributos de cada sensor, conforme configuração definida pelo servidor<br />
* '''Dados''': contêm os valores amostrados dos sensores, e têm este formato: <br />
** Para cada sensor, há uma lista de valores lidos, companhados dos respectivos timestamps<br />
<br />
<br />
A especificação e codificação das mensagens deve ser feita usando [[PTC29008:_Projeto_2:_Codificação_de_Mensagens#Protocol_Buffers|Protocol Buffers]]:<br />
<br />
<!--<br />
<syntaxhighlight lang=text><br />
syntax = "proto2";<br />
<br />
package sensor;<br />
<br />
message Sensor {<br />
// nome do sensor<br />
required string nome = 1;<br />
<br />
// valor amostrado do sensor<br />
required int32 valor = 2; <br />
<br />
// timestamp da amostragem, em milissegundos desde 1/1/2019 0:0:0<br />
optional int32 timestamp = 3;<br />
}<br />
<br />
message Config {<br />
// periodo dado em milissegundos<br />
required int32 periodo = 1;<br />
<br />
// lista de nomes de sensores<br />
repeated string sensores = 2; <br />
}<br />
<br />
message Dados {<br />
// lista de sensores com seus valores amostrados e timestamp<br />
repeated Sensor amostras = 1;<br />
}<br />
<br />
// Mensagem genérica: encapsula uma mensagem Config OU uma mensagem Dados<br />
message Mensagem {<br />
required string placa = 1;<br />
oneof msg {<br />
Config config = 2;<br />
Dados dados = 3;<br />
}<br />
}<br />
</syntaxhighlight><br />
--><br />
<br />
As trocas de mensagens entre unidade de sensores e servidor de coleta é feita sempre por iniciativa da unidade de sensores, de acordo com uma MEF.<br />
<br />
<!--<br />
[[imagem:PTC-Proj2-proto.jpg]]<br />
<br>''O comportamento do protocolo de aquisição de dados no lado da unidade de sensores''<br />
--><br />
<br />
Como será usado MQTT, o comportamento da aplicação pode explorar o seguinte: <br />
* não são necessárias confirmações de mensagens de dados<br />
* a identificação da unidade de sensores pode ser feita por um tópico. Isso evita que mensagens da unidade de coleta sejam transmitidas para todas unidades de sensores desnecessariamente<br />
* o serviço de configuração seja identificado por um tópico específico<br />
<br />
<!--<br />
=== Servidor de coleta ===<br />
<br />
O servidor de coleta está disponível neste link:<br />
* [http://tele.sj.ifsc.edu.br/~msobral/ptc/mqtt_server.tgz Servidor de coleta (versão para MQTT)]<br />
<br />
<br />
Para usá-lo siga este procedimento:<br />
# Descompacte o arquivo ''mqtt_server.tgz''. Note que será criado o subdiretório ''mqtt_server''<br />
# Entre no subdiretório ''mqtt_server'' e execute: <syntaxhighlight lang=bash><br />
python3 sensorapp.py<br />
</syntaxhighlight><br />
# Faça requisições para o servidor: <br />
#* Publicações para tópico ''ptc/sistema'': o servidor em resposta publica no tópico ''ptc/sistema/placa' uma mensagem contendo a listagem de placas de aquisição de dados conhecidas e respectivos sensores. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado no payload da mensagem recebida.<br />
#* Publicações para tópico ''ptc/config'': o conteúdo da mensagem publicada deve ser do tipo Config, e deve ser usada para registrar a unidade de sensores no servidor. O servidor em resposta publica no tópico ''ptc/config/placa'' uma mensagem também do tipo ''Config'', a qual contém o valor de período de amostragem a ser usado pela placa. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado em sua mensagem Config.<br />
#* Publicações para tópico ''ptc/dados'': o conteúdo da mensagem publicada deve ser do tipo ''Dados''. Tais publicações são usadas para enviar os valores amostrados dos sensores. O servidor de coleta recusa mensagens ''Dados'' de placas não registradas. Valores de sensores desconhecidos são ignorados.<br />
<br />
= Entrega e apresentação do projeto =<br />
<br />
O projeto deve ser apresentado ao professor em data e horário a combinar. A entrega deve ser feita pelo Moodle até dia '''20/11''':<br />
* [https://moodle.sj.ifsc.edu.br/mod/assign/view.php?id=4620 Entrega do projeto]<br />
--></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PTC29008:_Projeto_2:_Sistema_de_aquisi%C3%A7%C3%A3o_de_dados&diff=170866PTC29008: Projeto 2: Sistema de aquisição de dados2020-10-01T21:48:22Z<p>Msobral: /* Formato das mensagens da aplicação */</p>
<hr />
<div>[[PTC29008:_Verifica%C3%A7%C3%A3o_de_Protocolos|Próxima aula]]<br />
<br />
__toc__<br />
<br />
* [http://mqtt.org/ Site oficial do MQTT]<br />
* [https://mosquitto.org/ Mosquitto: um broker MQTT]<br />
<br />
<br />
No projeto 2 será desenvolvido um protótipo de um sistema de aquisição de dados. Cada unidade de aquisição de dados, representada por um kit baseado em RaspberryPi 3, é responsável por coletar dados de monitoramento e enviá-los para um servidor de coleta. A comunicação entre as unidades e o servidor se dá por links sem-fio ponto-a-ponto, implantados com o [[PTC29008:_Projeto_1:_um_protocolo_de_comunicação|protocolo do projeto 1]]. A figura a seguir ilustra um cenário desse sistema de aquisição de dados remotos.<br />
<br />
[[imagem:PTC-Proj2-aquisicao-dados.jpg|640px]]<br />
<br>''O sistema de aquisição de dados remotos''<br />
<br />
<br />
Nesse sistema, a transmissão de mensagens de dados através dos links sem-fio faz uso do [https://mqtt.org/ protocolo MQTT]. Esse protocolo foi desenhado com um serviço do tipo publisher-subscriber voltado a dispositivos com restrições de recursos, tendo em mente aplicações da [https://en.wikipedia.org/wiki/Internet_of_things Internet das Coisas (IoT)]. Em linhas gerais, as unidades de aquisição de dados se comportam como publicadores MQTT, o servidor de coleta é um assinante.<br />
<br />
<br />
O projeto tem por objetivo geral '''implementar a unidade de aquisição de dados''', a qual monitora dados ambientais e os envia para o servidor de coleta. Os objetivos específicos são:<br />
# Especificar um protocolo de aplicação, que deve estar fundado no protocolo MQTT: esse protocolo de aplicação deve ser capaz de:<br />
## Configurar a unidade de aquisição de dados<br />
## Transmitir mensagens contendo dados monitorados<br />
# Selecionar e usar uma implementação do MQTT, com a finalidade de enviar as mensagens de aquisição de dados<br />
# Usar uma técnica de codificação de mensagens que possibilite o intercâmbio de dados entre sistemas heterogêneos<br />
<br />
= A especificação do protocolo de aplicação =<br />
<br />
A especificação deve descrever:<br />
# o serviço oferecido<br />
# as mensagens do protocolo<br />
# o formato dessas mensagens<br />
# o comportamento do protocolo<br />
<br />
== Formato das mensagens da aplicação ==<br />
<br />
As mensagens da aplicação são de dois tipos:<br />
* '''Configuração:''' trocadas no início da sessão, servem para identificar os sensores e o período de amostragem e transmissão de dados. Seu conteúdo é formado pelo seguinte:<br />
*# Placa se anuncia ao servidor: <br />
*#* mensagem de configuração é publicada em um subtópico que identifica a placa. <br />
*#* mensagem de configuração contém a lista de sensores da placa. Cada sensor possui estes atributos: status (se está ativado), tipo (ex: temperatura, pressão, ...), peeríodos de amostragem e de envio, limiares inferior e superior para alertas.<br />
*# servidor configura a placa:<br />
*#* mensagem de configuração enviada para o subtópico da placa<br />
*#* mensagem contém os atributos de cada sensor, conforme configuração definida pelo servidor<br />
* '''Dados''': contêm os valores amostrados dos sensores, e têm este formato: <br />
** Para cada sensor, há uma lista de valores lidos, companhados dos respectivos timestamps<br />
<br />
<br />
A especificação e codificação das mensagens deve ser feita usando Protocol Buffers:<br />
<br />
<!--<br />
<syntaxhighlight lang=text><br />
syntax = "proto2";<br />
<br />
package sensor;<br />
<br />
message Sensor {<br />
// nome do sensor<br />
required string nome = 1;<br />
<br />
// valor amostrado do sensor<br />
required int32 valor = 2; <br />
<br />
// timestamp da amostragem, em milissegundos desde 1/1/2019 0:0:0<br />
optional int32 timestamp = 3;<br />
}<br />
<br />
message Config {<br />
// periodo dado em milissegundos<br />
required int32 periodo = 1;<br />
<br />
// lista de nomes de sensores<br />
repeated string sensores = 2; <br />
}<br />
<br />
message Dados {<br />
// lista de sensores com seus valores amostrados e timestamp<br />
repeated Sensor amostras = 1;<br />
}<br />
<br />
// Mensagem genérica: encapsula uma mensagem Config OU uma mensagem Dados<br />
message Mensagem {<br />
required string placa = 1;<br />
oneof msg {<br />
Config config = 2;<br />
Dados dados = 3;<br />
}<br />
}<br />
</syntaxhighlight><br />
--><br />
<br />
As trocas de mensagens entre unidade de sensores e servidor de coleta é feita sempre por iniciativa da unidade de sensores, de acordo com uma MEF.<br />
<br />
<!--<br />
[[imagem:PTC-Proj2-proto.jpg]]<br />
<br>''O comportamento do protocolo de aquisição de dados no lado da unidade de sensores''<br />
--><br />
<br />
Como será usado MQTT, o comportamento da aplicação pode explorar o seguinte: <br />
* não são necessárias confirmações de mensagens de dados<br />
* a identificação da unidade de sensores pode ser feita por um tópico. Isso evita que mensagens da unidade de coleta sejam transmitidas para todas unidades de sensores desnecessariamente<br />
* o serviço de configuração seja identificado por um tópico específico<br />
<br />
<!--<br />
=== Servidor de coleta ===<br />
<br />
O servidor de coleta está disponível neste link:<br />
* [http://tele.sj.ifsc.edu.br/~msobral/ptc/mqtt_server.tgz Servidor de coleta (versão para MQTT)]<br />
<br />
<br />
Para usá-lo siga este procedimento:<br />
# Descompacte o arquivo ''mqtt_server.tgz''. Note que será criado o subdiretório ''mqtt_server''<br />
# Entre no subdiretório ''mqtt_server'' e execute: <syntaxhighlight lang=bash><br />
python3 sensorapp.py<br />
</syntaxhighlight><br />
# Faça requisições para o servidor: <br />
#* Publicações para tópico ''ptc/sistema'': o servidor em resposta publica no tópico ''ptc/sistema/placa' uma mensagem contendo a listagem de placas de aquisição de dados conhecidas e respectivos sensores. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado no payload da mensagem recebida.<br />
#* Publicações para tópico ''ptc/config'': o conteúdo da mensagem publicada deve ser do tipo Config, e deve ser usada para registrar a unidade de sensores no servidor. O servidor em resposta publica no tópico ''ptc/config/placa'' uma mensagem também do tipo ''Config'', a qual contém o valor de período de amostragem a ser usado pela placa. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado em sua mensagem Config.<br />
#* Publicações para tópico ''ptc/dados'': o conteúdo da mensagem publicada deve ser do tipo ''Dados''. Tais publicações são usadas para enviar os valores amostrados dos sensores. O servidor de coleta recusa mensagens ''Dados'' de placas não registradas. Valores de sensores desconhecidos são ignorados.<br />
<br />
= Entrega e apresentação do projeto =<br />
<br />
O projeto deve ser apresentado ao professor em data e horário a combinar. A entrega deve ser feita pelo Moodle até dia '''20/11''':<br />
* [https://moodle.sj.ifsc.edu.br/mod/assign/view.php?id=4620 Entrega do projeto]<br />
--></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PTC29008:_Projeto_2:_Sistema_de_aquisi%C3%A7%C3%A3o_de_dados&diff=170865PTC29008: Projeto 2: Sistema de aquisição de dados2020-10-01T21:46:47Z<p>Msobral: /* Formato das mensagens da aplicação */</p>
<hr />
<div>[[PTC29008:_Verifica%C3%A7%C3%A3o_de_Protocolos|Próxima aula]]<br />
<br />
__toc__<br />
<br />
* [http://mqtt.org/ Site oficial do MQTT]<br />
* [https://mosquitto.org/ Mosquitto: um broker MQTT]<br />
<br />
<br />
No projeto 2 será desenvolvido um protótipo de um sistema de aquisição de dados. Cada unidade de aquisição de dados, representada por um kit baseado em RaspberryPi 3, é responsável por coletar dados de monitoramento e enviá-los para um servidor de coleta. A comunicação entre as unidades e o servidor se dá por links sem-fio ponto-a-ponto, implantados com o [[PTC29008:_Projeto_1:_um_protocolo_de_comunicação|protocolo do projeto 1]]. A figura a seguir ilustra um cenário desse sistema de aquisição de dados remotos.<br />
<br />
[[imagem:PTC-Proj2-aquisicao-dados.jpg|640px]]<br />
<br>''O sistema de aquisição de dados remotos''<br />
<br />
<br />
Nesse sistema, a transmissão de mensagens de dados através dos links sem-fio faz uso do [https://mqtt.org/ protocolo MQTT]. Esse protocolo foi desenhado com um serviço do tipo publisher-subscriber voltado a dispositivos com restrições de recursos, tendo em mente aplicações da [https://en.wikipedia.org/wiki/Internet_of_things Internet das Coisas (IoT)]. Em linhas gerais, as unidades de aquisição de dados se comportam como publicadores MQTT, o servidor de coleta é um assinante.<br />
<br />
<br />
O projeto tem por objetivo geral '''implementar a unidade de aquisição de dados''', a qual monitora dados ambientais e os envia para o servidor de coleta. Os objetivos específicos são:<br />
# Especificar um protocolo de aplicação, que deve estar fundado no protocolo MQTT: esse protocolo de aplicação deve ser capaz de:<br />
## Configurar a unidade de aquisição de dados<br />
## Transmitir mensagens contendo dados monitorados<br />
# Selecionar e usar uma implementação do MQTT, com a finalidade de enviar as mensagens de aquisição de dados<br />
# Usar uma técnica de codificação de mensagens que possibilite o intercâmbio de dados entre sistemas heterogêneos<br />
<br />
= A especificação do protocolo de aplicação =<br />
<br />
A especificação deve descrever:<br />
# o serviço oferecido<br />
# as mensagens do protocolo<br />
# o formato dessas mensagens<br />
# o comportamento do protocolo<br />
<br />
== Formato das mensagens da aplicação ==<br />
<br />
As mensagens da aplicação são de dois tipos:<br />
* '''Configuração:''' trocadas no início da sessão, servem para identificar os sensores e o período de amostragem e transmissão de dados. Seu conteúdo é formado pelo seguinte:<br />
*# Placa se anuncia ao servidor: <br />
*#* mensagem de configuração é publicada em um subtópico que identifica a placa. <br />
*#* mensagem de configuração contém a lista de sensores da placa. Cada sensor possui estes atributos: status (se está ativado), tipo (ex: temperatura, pressão, ...), peeríodos de amostragem e de envio, limiares inferior e superior para alertas.<br />
*# servidor configura a placa:<br />
*#* mensagem de configuração enviada para o subtópico da placa<br />
*#* mensagem contém os atributos de cada sensor, conforme configuração definida pelo servidor<br />
* '''Dados''': contêm os valores amostrados dos sensores, e têm este formato: <syntaxhighlight lang=text><br />
Lista de amostras dos sensores: LISTA DE <STRING,INTEIRO,TIMESTAMP><br />
</syntaxhighlight><br />
<br />
<br />
A especificação e codificação das mensagens deve ser feita usando Protocol Buffers:<br />
<br />
<!--<br />
<syntaxhighlight lang=text><br />
syntax = "proto2";<br />
<br />
package sensor;<br />
<br />
message Sensor {<br />
// nome do sensor<br />
required string nome = 1;<br />
<br />
// valor amostrado do sensor<br />
required int32 valor = 2; <br />
<br />
// timestamp da amostragem, em milissegundos desde 1/1/2019 0:0:0<br />
optional int32 timestamp = 3;<br />
}<br />
<br />
message Config {<br />
// periodo dado em milissegundos<br />
required int32 periodo = 1;<br />
<br />
// lista de nomes de sensores<br />
repeated string sensores = 2; <br />
}<br />
<br />
message Dados {<br />
// lista de sensores com seus valores amostrados e timestamp<br />
repeated Sensor amostras = 1;<br />
}<br />
<br />
// Mensagem genérica: encapsula uma mensagem Config OU uma mensagem Dados<br />
message Mensagem {<br />
required string placa = 1;<br />
oneof msg {<br />
Config config = 2;<br />
Dados dados = 3;<br />
}<br />
}<br />
</syntaxhighlight><br />
--><br />
<br />
As trocas de mensagens entre unidade de sensores e servidor de coleta é feita sempre por iniciativa da unidade de sensores, de acordo com uma MEF.<br />
<br />
<!--<br />
[[imagem:PTC-Proj2-proto.jpg]]<br />
<br>''O comportamento do protocolo de aquisição de dados no lado da unidade de sensores''<br />
--><br />
<br />
Como será usado MQTT, o comportamento da aplicação pode explorar o seguinte: <br />
* não são necessárias confirmações de mensagens de dados<br />
* a identificação da unidade de sensores pode ser feita por um tópico. Isso evita que mensagens da unidade de coleta sejam transmitidas para todas unidades de sensores desnecessariamente<br />
* o serviço de configuração seja identificado por um tópico específico<br />
<br />
<!--<br />
=== Servidor de coleta ===<br />
<br />
O servidor de coleta está disponível neste link:<br />
* [http://tele.sj.ifsc.edu.br/~msobral/ptc/mqtt_server.tgz Servidor de coleta (versão para MQTT)]<br />
<br />
<br />
Para usá-lo siga este procedimento:<br />
# Descompacte o arquivo ''mqtt_server.tgz''. Note que será criado o subdiretório ''mqtt_server''<br />
# Entre no subdiretório ''mqtt_server'' e execute: <syntaxhighlight lang=bash><br />
python3 sensorapp.py<br />
</syntaxhighlight><br />
# Faça requisições para o servidor: <br />
#* Publicações para tópico ''ptc/sistema'': o servidor em resposta publica no tópico ''ptc/sistema/placa' uma mensagem contendo a listagem de placas de aquisição de dados conhecidas e respectivos sensores. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado no payload da mensagem recebida.<br />
#* Publicações para tópico ''ptc/config'': o conteúdo da mensagem publicada deve ser do tipo Config, e deve ser usada para registrar a unidade de sensores no servidor. O servidor em resposta publica no tópico ''ptc/config/placa'' uma mensagem também do tipo ''Config'', a qual contém o valor de período de amostragem a ser usado pela placa. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado em sua mensagem Config.<br />
#* Publicações para tópico ''ptc/dados'': o conteúdo da mensagem publicada deve ser do tipo ''Dados''. Tais publicações são usadas para enviar os valores amostrados dos sensores. O servidor de coleta recusa mensagens ''Dados'' de placas não registradas. Valores de sensores desconhecidos são ignorados.<br />
<br />
= Entrega e apresentação do projeto =<br />
<br />
O projeto deve ser apresentado ao professor em data e horário a combinar. A entrega deve ser feita pelo Moodle até dia '''20/11''':<br />
* [https://moodle.sj.ifsc.edu.br/mod/assign/view.php?id=4620 Entrega do projeto]<br />
--></div>Msobralhttps://wiki.sj.ifsc.edu.br/index.php?title=PTC29008:_Projeto_2:_Sistema_de_aquisi%C3%A7%C3%A3o_de_dados&diff=170864PTC29008: Projeto 2: Sistema de aquisição de dados2020-10-01T21:46:04Z<p>Msobral: /* Formato das mensagens da aplicação */</p>
<hr />
<div>[[PTC29008:_Verifica%C3%A7%C3%A3o_de_Protocolos|Próxima aula]]<br />
<br />
__toc__<br />
<br />
* [http://mqtt.org/ Site oficial do MQTT]<br />
* [https://mosquitto.org/ Mosquitto: um broker MQTT]<br />
<br />
<br />
No projeto 2 será desenvolvido um protótipo de um sistema de aquisição de dados. Cada unidade de aquisição de dados, representada por um kit baseado em RaspberryPi 3, é responsável por coletar dados de monitoramento e enviá-los para um servidor de coleta. A comunicação entre as unidades e o servidor se dá por links sem-fio ponto-a-ponto, implantados com o [[PTC29008:_Projeto_1:_um_protocolo_de_comunicação|protocolo do projeto 1]]. A figura a seguir ilustra um cenário desse sistema de aquisição de dados remotos.<br />
<br />
[[imagem:PTC-Proj2-aquisicao-dados.jpg|640px]]<br />
<br>''O sistema de aquisição de dados remotos''<br />
<br />
<br />
Nesse sistema, a transmissão de mensagens de dados através dos links sem-fio faz uso do [https://mqtt.org/ protocolo MQTT]. Esse protocolo foi desenhado com um serviço do tipo publisher-subscriber voltado a dispositivos com restrições de recursos, tendo em mente aplicações da [https://en.wikipedia.org/wiki/Internet_of_things Internet das Coisas (IoT)]. Em linhas gerais, as unidades de aquisição de dados se comportam como publicadores MQTT, o servidor de coleta é um assinante.<br />
<br />
<br />
O projeto tem por objetivo geral '''implementar a unidade de aquisição de dados''', a qual monitora dados ambientais e os envia para o servidor de coleta. Os objetivos específicos são:<br />
# Especificar um protocolo de aplicação, que deve estar fundado no protocolo MQTT: esse protocolo de aplicação deve ser capaz de:<br />
## Configurar a unidade de aquisição de dados<br />
## Transmitir mensagens contendo dados monitorados<br />
# Selecionar e usar uma implementação do MQTT, com a finalidade de enviar as mensagens de aquisição de dados<br />
# Usar uma técnica de codificação de mensagens que possibilite o intercâmbio de dados entre sistemas heterogêneos<br />
<br />
= A especificação do protocolo de aplicação =<br />
<br />
A especificação deve descrever:<br />
# o serviço oferecido<br />
# as mensagens do protocolo<br />
# o formato dessas mensagens<br />
# o comportamento do protocolo<br />
<br />
== Formato das mensagens da aplicação ==<br />
<br />
As mensagens da aplicação são de dois tipos:<br />
* '''Configuração:''' trocadas no início da sessão, servem para identificar os sensores e o período de amostragem e transmissão de dados. Seu conteúdo é formado pelo seguinte:<br />
*# Placa se anuncia ao servidor: <br />
*#* mensagem de configuração é publicada em um subtópico que identifica a placa. <br />
*#* mensagem de configuração contém a lista de sensores da placa. Cada sensor possui estes atributos: status (se está ativado), tipo (ex: temperatura, pressão, ...), peeríodos de amostragem e de envio, limiares inferior e superior para alertas.<br />
*# servidor configura a placa:<br />
*#* mensagem de configuração enviada para o subtópico da placa<br />
#*# mensagem contém os atributos de cada sensor, conforme configuração definida pelo servidor<br />
* '''Dados''': contêm os valores amostrados dos sensores, e têm este formato: <syntaxhighlight lang=text><br />
Lista de amostras dos sensores: LISTA DE <STRING,INTEIRO,TIMESTAMP><br />
</syntaxhighlight><br />
<br />
<br />
A especificação e codificação das mensagens deve ser feita usando Protocol Buffers:<br />
<br />
<!--<br />
<syntaxhighlight lang=text><br />
syntax = "proto2";<br />
<br />
package sensor;<br />
<br />
message Sensor {<br />
// nome do sensor<br />
required string nome = 1;<br />
<br />
// valor amostrado do sensor<br />
required int32 valor = 2; <br />
<br />
// timestamp da amostragem, em milissegundos desde 1/1/2019 0:0:0<br />
optional int32 timestamp = 3;<br />
}<br />
<br />
message Config {<br />
// periodo dado em milissegundos<br />
required int32 periodo = 1;<br />
<br />
// lista de nomes de sensores<br />
repeated string sensores = 2; <br />
}<br />
<br />
message Dados {<br />
// lista de sensores com seus valores amostrados e timestamp<br />
repeated Sensor amostras = 1;<br />
}<br />
<br />
// Mensagem genérica: encapsula uma mensagem Config OU uma mensagem Dados<br />
message Mensagem {<br />
required string placa = 1;<br />
oneof msg {<br />
Config config = 2;<br />
Dados dados = 3;<br />
}<br />
}<br />
</syntaxhighlight><br />
--><br />
<br />
As trocas de mensagens entre unidade de sensores e servidor de coleta é feita sempre por iniciativa da unidade de sensores, de acordo com uma MEF.<br />
<br />
<!--<br />
[[imagem:PTC-Proj2-proto.jpg]]<br />
<br>''O comportamento do protocolo de aquisição de dados no lado da unidade de sensores''<br />
--><br />
<br />
Como será usado MQTT, o comportamento da aplicação pode explorar o seguinte: <br />
* não são necessárias confirmações de mensagens de dados<br />
* a identificação da unidade de sensores pode ser feita por um tópico. Isso evita que mensagens da unidade de coleta sejam transmitidas para todas unidades de sensores desnecessariamente<br />
* o serviço de configuração seja identificado por um tópico específico<br />
<br />
<!--<br />
=== Servidor de coleta ===<br />
<br />
O servidor de coleta está disponível neste link:<br />
* [http://tele.sj.ifsc.edu.br/~msobral/ptc/mqtt_server.tgz Servidor de coleta (versão para MQTT)]<br />
<br />
<br />
Para usá-lo siga este procedimento:<br />
# Descompacte o arquivo ''mqtt_server.tgz''. Note que será criado o subdiretório ''mqtt_server''<br />
# Entre no subdiretório ''mqtt_server'' e execute: <syntaxhighlight lang=bash><br />
python3 sensorapp.py<br />
</syntaxhighlight><br />
# Faça requisições para o servidor: <br />
#* Publicações para tópico ''ptc/sistema'': o servidor em resposta publica no tópico ''ptc/sistema/placa' uma mensagem contendo a listagem de placas de aquisição de dados conhecidas e respectivos sensores. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado no payload da mensagem recebida.<br />
#* Publicações para tópico ''ptc/config'': o conteúdo da mensagem publicada deve ser do tipo Config, e deve ser usada para registrar a unidade de sensores no servidor. O servidor em resposta publica no tópico ''ptc/config/placa'' uma mensagem também do tipo ''Config'', a qual contém o valor de período de amostragem a ser usado pela placa. '''OBS:''' ''placa'' é o nome da unidade de sensores, informado em sua mensagem Config.<br />
#* Publicações para tópico ''ptc/dados'': o conteúdo da mensagem publicada deve ser do tipo ''Dados''. Tais publicações são usadas para enviar os valores amostrados dos sensores. O servidor de coleta recusa mensagens ''Dados'' de placas não registradas. Valores de sensores desconhecidos são ignorados.<br />
<br />
= Entrega e apresentação do projeto =<br />
<br />
O projeto deve ser apresentado ao professor em data e horário a combinar. A entrega deve ser feita pelo Moodle até dia '''20/11''':<br />
* [https://moodle.sj.ifsc.edu.br/mod/assign/view.php?id=4620 Entrega do projeto]<br />
--></div>Msobral