int main (int argc, char ** argv) {QgsApplication…" /> int main (int argc, char ** argv) {QgsApplication…" />
Mais

Falha de exemplo do QGIS C ++ Hello World

Falha de exemplo do QGIS C ++ Hello World


Eu escrevi um aplicativo C ++ / Qt muito simples usando QGIS composto de um único arquivo "main.cpp" como abaixo:

#incluir  int main (int argc, char ** argv) {QgsApplication app (argc, argv, true); return 0; }

e meu arquivo de projeto Qt Creator é definido como:

QT + = core gui maior do que (QT_MAJOR_VERSION, 4): QT + = widgets TARGET = qgis_test TEMPLATE = app CONFIG + = c ++ 11 SOURCES + = main.cpp HEADERS + = LIBS + = -L / usr / local / lib - lqgis_core QGIS_DIR = /home/rouhollah/Programs/qgis-2.8.1 INCLUDEPATH + = $$ QGIS_DIR INCLUDEPATH + = $$ QGIS_DIR / src / core DEFINES + = CORE_EXPORT = GUI_EXPORT =

O programa é compilado e vinculado, mas é encerrado inesperadamente quando executado com a seguinte mensagem de erro:

realloc (): ponteiro inválido: 0x00007fc3d802e0e0

Mesmo executando o programa no modo de depuração, o depurador para antes de atingir o ponto de interrupção na primeira linha doa Principalfunção.

Observe que instalei as bibliotecas QGIS compilando os códigos-fonte obtidos no GitHub.


Depois de horas tentando tudo o que pude pensar, finalmente descobri que o QGIS não é compatível com o Qt 5.4. Conseqüentemente, consegui rodar um programa de amostra compilado e vinculado ao Qt 4.8.6.


Para tudo Dúvidas e observações relacionadas ao Cygwin, verifique os recursos disponíveis neste site, como o FAQ, o Guia do Usuário e os arquivos da lista de discussão. Se você esgotou esses recursos, envie um e-mail para um lista de correio apropriada. Isso inclui observações sobre páginas da web, questões de configuração, questões sobre onde encontrar as coisas, questões sobre por que as coisas são feitas de uma determinada maneira, questões sobre as preferências de cores dos desenvolvedores do Cygwin, questões sobre o significado do número 42, etc.

Por favor, envie notificação de problemas técnicos (html ruim, links quebrados) relacionados a essas páginas da web para a lista de discussão do Cygwin.

Por favor não envie um e-mail pessoal com "perguntas rápidas" para colaboradores individuais do Cygwin. As listas de discussão do Cygwin são os lugares para todas as perguntas. Sério. Quero dizer.

Cygwin de 32 bits

O espaço de endereço é um fator muito limitante para o Cygwin. Hoje em dia, uma distro Cygwin completa de 32 bits não é mais viável e provavelmente irá falhar em lugares aleatórios devido a um problema com a chamada de sistema fork (2).

Portanto, recomendamos o uso do Cygwin de 32 bits apenas em cenários limitados, com apenas um mínimo de pacotes necessários instalados e somente se não houver maneira de executar o Cygwin de 64 bits em seu lugar.

Você foi avisado. Se você ainda tem certeza de que realmente precisa de um Cygwin de 32 bits, e não há absolutamente nenhuma maneira de contornar isso, você pode executar o instalador setup-x86.exe.

A DLL e os utilitários do Cygwin são copyright e cópia dos autores do Cygwin. Outros pacotes têm outros direitos autorais.
UNIX & reg é uma marca registrada do Open Group nos Estados Unidos e em outros países.


Não sei muito sobre sockets, mas aqui estão alguns comentários gerais de programação C:

  • Você nunca libera () a memória malloc'd de recursos. E se você fizesse, o que deveria, então resource = "/" travaria o programa quando você tentasse liberar () aquela memória.

Possíveis bugs

char ipstr [INET6_ADDRSTRLEN] Declarar um array com o tamanho de um "comprimento de string" é duvidoso. Tem certeza de que aloca espaço suficiente para um caractere de terminação nulo de string?

(char *) malloc Nunca há uma razão para lançar o resultado de malloc em C. É até potencialmente prejudicial em C90. Você pode encontrar inúmeros tópicos sobre isso no Stack Overflow.

Detalhes exigentes e estilo de codificação

É sempre melhor declarar cada variável em uma linha sozinha, para tornar o código mais legível e para evitar bugs como int * ptr1, ptr2 // ptr2 não é um ponteiro como o pretendido.


Foi comentado que, ao trabalhar em C ++, você deve usar std :: string. Supondo que você queira ficar com as strings de estilo C (ou pelo menos entender como deve trabalhar com elas, caso precise), tenho as seguintes sugestões:

O tit pode ser maior do que o permitido pelo título do buffer. [1] Nesse caso, seu programa irá travar ou pior, continue executando enquanto corrompe alguma outra parte da memória. Para evitar isso, você deve sempre usar funções que permitem rastrear o tamanho do buffer de destino e detectar o estouro. Por exemplo:

Isso tem alguns traços indesejáveis, pois truncará silenciosamente a string se a entrada for maior que o destino. Se você estiver trabalhando em um sistema que tem strlcpy não padrão, isso tem algumas condições de erro mais claras:

Movendo-se ao longo do espectro (do código que trava com uma entrada grande, ao código que trunca a entrada, ao código que gera erros quando o buffer é insuficiente), você também pode querer alocar memória dinamicamente para isso.

Isso cria complicações se um objeto Book for copiado, então você precisa lidar com isso:

E precisa ser liberado quando seu objeto for destruído:

Se isso parece muito complicado, é porque, para código C ++ de nível superior, provavelmente é. std :: string cuidará de tudo isso para você. Observe, porém, que o layout da memória de seu objeto será substancialmente diferente com essas abordagens de memória dinâmica. [2]

Como regra geral, ter que fazer projeções como essa geralmente é um indicador de que você está fazendo algo errado. :-) Ao escrever código e revisar o trabalho dos outros, eu tendo a tentar evitar o máximo possível de conversões desnecessárias. Muitas vezes, esses bugs de máscara, por exemplo, lançar uma função para um tipo de ponteiro de função incorreto pode produzir travamentos, ou eliminar const pode travar quando alguém tenta modificar um buffer somente leitura. Por razões como esta, é um bom hábito observar conversões inadequadas ao ler o código e certifique-se de não apresentá-los você mesmo, código como este deveria ofender suas sensibilidades. :-) [3]

No seu caso, o problema é que os literais de string têm o tipo const char *, então o compilador reclama que você está passando isso para algo que não tem const. Então, o que você precisa fazer aqui é:

Notas de rodapé e comentários tangenciais:
[1] Se houver pessoas que falam inglês que possam ler seu código, sugiro que você encontre um nome melhor do que tit para essa variável.
[2] No exemplo anterior, os caracteres do título existem ao lado de quaisquer outros membros da classe. Ao usar a memória dinâmica, agora há uma desreferenciação de ponteiro extra acontecendo para chegar aos personagens. Na maioria dos casos, isso não fará diferença, mas você pode pensar em casos teóricos em que o primeiro é desejado sobre o segundo.
[3] Nota lateral: Na minha experiência, uma maneira de dizer que alguém não sabe o que está fazendo em C / C ++ é o uso de elencos. Um programador desleixado escreverá código que o compilador rejeita e, para fazê-lo "funcionar" rapidamente, eles introduzirão conversões para silenciar os avisos do compilador em vez de corrigir o problema real. Se você está trabalhando em uma equipe em que as pessoas fazem isso, às vezes acho que ser cético em relação ao trabalho dessa pessoa por outros motivos é uma boa indicação.


17 Respostas 17

Acho que você deve começar com os tipos de dados que a linguagem construiu, como arrays e ponteiros, e quando seus alunos os compreenderem, vá para as aulas e OO, depois para STL.

O motivo é que você pode ensinar as pessoas a entender matrizes sem entender muito mais além das variáveis ​​e da arquitetura do computador subjacente, mas não pode ensiná-las a entender vetores sem primeiro lhes dar aulas. Se você usar o STL desde o início, seus alunos terão que viver sem ter a menor ideia de como o vetor funciona exatamente. E então, quando você chegar a esse ponto, eles não terão uma compreensão boa o suficiente de ponteiros e matrizes e coisas que você obtém fazendo coisas como escrever sua própria classe de vetor, escrever sua própria classe de lista vinculada, etc. que serão necessários para apreciar e explorar seus recursos. Fico irritada quando os alunos dizem "o que é isso?" e os professores dizem "simplesmente ignore, você aprenderá mais tarde".

E como Demian apontado nos comentários, decifrar as mensagens relativamente crípticas que você obtém de erros de modelo é significativamente mais difícil do que entender os erros que você pode obter de arrays / construções não-modelo.

Não sinto o mesmo em relação a cout e printf. Nenhum é de nível inferior do que o outro, exceto que cout usa sobrecarga de operador.

Isso pode parecer estúpido, mas eu sou absolutamente fanático sobre fazer com que as pessoas entendam os blocos de construção básicos de tudo antes de passar para as abstrações. Você não deve usar ponteiros inteligentes até que seja proficiente com ponteiros brutos, sem vetores antes de matrizes, esse tipo de coisa.

Costumo dizer isso, mas vou repetir: é melhor ensinar aos alunos a divisão longa primeiro e depois deixá-los usar uma calculadora do que deixá-los usar uma calculadora e depois ensinar-lhes divisão longa.

Quanto aos livros para ensinar iniciantes, consulte a lista mestre de bons livros C ++.

Esta é minha própria experiência. Aceite o que for preciso.

Olhando para trás, quando comecei a programar, eu realmente gostaria de ter aprendido sobre memória primeiro. Não, não é emocionante. Isso vai fazer você ficar vidrado. Mas é um conceito ridiculamente fácil de ensinar. Apenas mostre uma tabela 1-D e faça-os passar por alguns exercícios mentais:

Lição 1:
Isso corresponde a 10 bytes de memória. Esta é a letra "a" colocada na célula 3. "a" é o valor e 3 é o endereço. OK? Este é o número 3 sendo colocado na célula 5. Seu valor é 3 e seu endereço é 5. Agora, o que o número 3 pode significar? Bem, pode ser apenas um número 3 - ou - pode ser uma referência a Morada 3. Assim como 1 pode ser um número ou um código de país. É apenas um número, tudo depende de como o tratamos.

Lição 2:
Vamos aprender a contar em binário. Vamos contar até 10 usando a contagem binária de dedos. Interessante não? Viu como isso só precisou de 4 dedos? Portanto, dizemos que apenas 4 bits são necessários (1/2 célula). Qual é o máximo com que você pode contar em uma mão (a resposta é 31). Que tal 2 mãos (a resposta é 1023). Explique como mais bits significam intervalos de números mais altos. Lembre-os de que uma célula de memória tem 8 bits. Pergunte o que acontece quando um número precisa de mais de 8 bits. Como eles colocariam um número de bytes múltiplos na memória (de maneira lógica)? Apresente-os a chars, shorts, inteiros e longos.

Lição 3:
Aqui está um programa que escrevi em C ++. Ele usa inteiros de 32 bits. E este aqui é tb um número. Mas este é um número usado para apontar. Ao usar esse pequeno asterisco, prometemos que o número será usado para apontar. E é assim que o apontamos para o primeiro número. O pequeno e comercial preenche o valor para nós. Legal hein?

etc. Depois de obter a memória básica para baixo, todo o resto é bolo. São os alunos pobres que presumem que o compilador está fazendo algo mágico (ou que eles nunca precisam pensar em gerenciamento de memória) que tendem a ter mais dificuldades. E o C ++ turva as águas porque algumas coisas são automaticamente limpas (ou seja, um vetor normal), enquanto outras não (ou seja, um vetor alocado usando "novo"). E nem me fale sobre strings (char * vs. std :: string - tente explicar isso sem conhecimento de ponteiro).

Não sei qual plataforma sua competição de robôs terá como alvo, mas se for um ambiente de memória limitada, as habilidades de gerenciamento de memória são cruciais.

Depois de ter ensinado a eles os fundamentos, sim, eu digo que vá em C ++ até o fim. Tecnicamente, eles são apenas bibliotecas diferentes, mas sim, não há por que confundi-los com mais de um paradigma. Forneça a eles ferramentas C ++ (que incluem ponteiros e matrizes).

Devo começar a usar STL desde o primeiro dia, esp. vetor ou apenas ficar com matrizes padrão? Os arrays são mais fáceis de introduzir, mas os erros de ponteiro podem ser mais difíceis de detectar.

definitivamente vá direto para o uso de tipos de biblioteca padrão. uma std :: string ou std :: vector é o que eles deveriam usar frequentemente e (a grande maioria das implementações de) esses tipos oferecem alguma forma de detecção e tratamento de erros, enquanto abstraem muitas das complexidades dos alunos.

você pode passar uma boa parte do tempo ensinando aos alunos como a memória é estruturada e como gerenciar a memória (estilo C), ou pode ir direto ao trabalho usando os tipos idiomáticos da linguagem e explicar os detalhes de implementação, se necessário (e quando eles têm um melhor compreensão do que é um array e onde são usados).

a sintaxe de std :: vector (criar / ler / escrever) não é muito mais complicada do que uma matriz C. em comparação, o gerenciamento manual de memória e todos os erros comuns que novos alunos cometem com matrizes C são muito mais difíceis de aprender, ensinar e usar.

Para I / O, devo me limitar a cout etc. ou você acha que printf seria mais fácil de aprender?

cout. pessoalmente, acho que cout é mais fácil de aprender. talvez mais importante, você deve escolher cout porque é mais seguro, versátil e permite definir como um objeto é impresso, o que significa que você já possui funcionalidades e segurança de tipo incorporadas usando alguns tipos de biblioteca padrão. finalmente, você acabará com programas mistos quando perceber que eles também precisam aprender cout além de printf.

na verdade, acho que você deveria ler Accelerated C ++, de Koenig e Moo, e possivelmente usá-lo para instrução (respondendo a pergunta 3 indiretamente). no livro, eles introduzem std :: cout logo antes de retornar (página 3) e salvam ponteiros e matrizes até o capítulo 10. Se eu pudesse copiar e colar o prefácio desse livro como uma resposta à sua pergunta, eu o faria. (nota: eu recomendo que você leia para a perspectiva de ensinar c ++).

Há algum recurso online para C ++ adequado para uso por esses jovens alunos?

se você não quiser usar o C ++ acelerado (que assume algum conhecimento de programação em geral), então talvez você queira o Thinking in C ++ de Eckel. Eu não li, mas é um texto introdutório C ++ distribuído gratuitamente.

Uma coisa a se considerar é que no código FIRST típico, as estruturas de dados de qualquer forma (estruturas, classes, matrizes, vetores, listas) desempenham um papel muito pequeno. Normalmente, você lida com uma quantidade muito pequena de dados do sensor e os usa para decidir uma quantidade muito pequena de movimentos do atuador.

Mas o que faz desempenham um papel importante e podem ser muito difíceis de entender são todas as diferentes formas de ao controle isso continua.

Então, eu colocaria muita ênfase no controle. Comece com o básico: se, por enquanto. Faça-os praticar muito. Faça-os conhecê-los bem.

. mas então fica mais difícil. Qualquer código de robô de tamanho moderado eventualmente atinge alguns padrões de controle mais complicados:

Grande loop "principal", que chama tudo

Máquinas de estado (aparecem muito)

Salvando valores anteriores / contador em execução (como para PID)

Isso é difícil para iniciantes entender. Pensar em como um programa se move através do código é confuso, você pode não perceber agora, mas é. Isso vai dar aos seus alunos muito mais problemas do que o próprio idioma.

Além disso, boa sorte! Espero que a temporada corra bem.

  • Devo começar a usar STL desde o primeiro dia, esp. vetor ou apenas ficar com matrizes padrão? Os arrays são mais fáceis de introduzir, mas os erros de ponteiro podem ser mais difíceis de detectar.

O problema com arrays é que qualquer coisa, exceto exemplos simples de livros, exigirá arrays de tamanho dinâmico e, no momento em que você precisar de arrays de tamanho dinâmico, std :: vector é muito mais fácil. Além disso, a única maneira de lidar com arrays de tamanho dinâmico com segurança é envolvê-los em sua própria classe, o que seria um pobre std :: vector rip-off.
Ao contrário da crença inexplicavelmente popular, os alunos podem usar recursos que requerem mecânicas complexas para serem implementados sem saber como implemento essas próprias feras. Como eu disse em um comentário: Você nem pensaria em não considerar o ensino de strings em outras línguas, só porque sua implementação é complexa, não é?

Por que um conjunto de convenções de string de formato arcaico que fazem seu programa explodir no momento em que você errar (o que acontece no momento em que você altera um typedef em algum cabeçalho aparentemente não relacionado) seria preferível ao tipo de segurança de std :: cout ?

A maioria dos recursos C ++, online ou não, são ruins. E não estou falando sobre o uso de fontes ou linguagem difíceis de ler. Estou falando de erros factuais flagrantemente óbvios. Existem poucos recursos C ++ bons, principalmente uma ou duas dezenas de livros. O único que conheço online é o de Bruce Eckel Pensando em C ++.

Por uma década, ensinei C ++ para alunos com experiências muito diferentes usando Koenig / Moo's C ++ acelerado como base. Meu curso mudou muito naquela década, agora não está nem perto do livro, exceto pelo princípio subjacente: Use expressões modernas, corretas e seguras desde o início. Não ensine seus alunos a manipular manualmente a memória, apenas para que mais tarde desaprendam isso em favor de idiomas mais seguros. Como você pode ver em algumas das respostas fornecidas aqui, isso não funciona: Aqueles que aprenderam os métodos manuais primeiro raramente compreenderão a vantagem de usar idiomas modernos e seguros.

Se você quiser ensinar C ++, eu começaria diretamente com construções C ++ como vetor e cout, em vez do subconjunto C como printf.

Devo começar a usar STL desde o primeiro dia.

sim. Usar matrizes nativas em C ++ está sujeito a erros e simplesmente é uma prática ruim 99% das vezes.

Para I / O, devo me limitar a cout etc.?

Há algum recurso online para C ++ adequado para uso por esses jovens alunos?

Eles não são tão jovens. Aprender a programar não requer sabedoria, apenas motivação e mente aberta. Não consigo pensar em nada ensinado nos últimos dois anos do ensino médio que prepararia melhor um aluno para aprender a programar. Você já olhou para Bruce Eckel's Pensando em C ++? Está disponível para download gratuito e muito bem revisado. Por favor, evite o popular, mas horrível C ++: como programar e todo o Sam's Teach Yourself C ++. livros.

Aprendi C ++ no colégio como primeira linguagem de programação, embora estava mais parecido com "C +", agora que você mencionou, usamos cout para escrever texto no console e arquivos, mas também algumas funções C (getch () era a minha favorita).

Acho que a maneira mais eficaz (e possivelmente divertida) de ensinar o básico é usar um currículo orientado a objetivos: comece mostrando como produzir coisas, a seguir a entrada do teclado, a seguir E / S de arquivo simples, etc. Progrida para um texto simples- jogo baseado em (ou o equivalente em robótica). Então, quando eles perguntam: "Como faço X?", Você pode dividir X em termos de exemplos que eles já viram, por exemplo, "Primeiro você precisará obter a entrada do usuário como fizemos em Z, então." (Obviamente não é tão fácil na prática, já que X provavelmente será algo que eles precisam de conhecimento adicional para fazer, por exemplo " Gráficos 3D ", mas você ainda poderia explicar como gostaria trabalho de alto nível).

Os exemplos que você mostra a eles começarão como uma caixa preta de magia copiada e colada, cujos mistérios são desvendados à medida que as peças do quebra-cabeça da programação são lentamente descobertas. Por exemplo, seus alunos aprenderão o básico de if s rapidamente, mas provavelmente não perceberão que uma expressão booleana não é exclusivamente limitada para uso dentro de uma condição if (levando à clássica if (blah) return true else return código falso).

As sutilezas de escolher uma matriz ou vetor como contêiner parecerão irrelevantes para os alunos a princípio. Um vetor / matriz será simplesmente uma maneira de ter muitas variáveis ​​como uma variável, acessível por meio de um índice. Atenha-se a um onde você puder. Os ponteiros também não serão compreendidos mais tarde. Isso não quer dizer que você não deva explicar as coisas apenas que não pode explicar tudo de uma vez, e as coisas que você explica não serão completamente absorvidas. Os humanos aprendem organicamente, não linearmente. Eu estava usando cout para um casal anos antes de entender o que era sobrecarga de operador!

Ah, e não tenha medo da repetição. "É como o programa Hello World que fizemos - lembra como escrevemos texto no console?" (não.) "Vamos repassar tudo para ter certeza." . E faça perguntas! Mantenha os alunos envolvidos com exemplos divertidos e muita interação.

C ++ é uma linguagem complexa e, não importa o que você faça, uma parte significativa dessa complexidade (e da arte da programação em geral) será perdida para seus alunos. Tudo que você mostrar a eles será novo para eles, a maioria não penetrará em um nível profundo de compreensão (pelo menos, não imediatamente). Como a memória funciona, como os componentes de um PC interagem, quais são a pilha e o heap, ponteiros, classes, até mesmo loops e cadeias if-else não será devidamente compreendido pela maioria. Isso está certo! Eles não precisam ser entendidos para serem usados ​​- uma quantidade incrível de programas legais podem ser escritos com funções super-feias de 1000 linhas com redundância quíntupla aninhada se s e 43 variáveis ​​nomeadas coisas como x_2r. O importante é que os alunos sejam constantemente aprendendo e melhorando. Caixas pretas funcionam, desde que se tornem transparentes (ou pelo menos cinza translúcido) no longo prazo. Ao final do curso, eles podem não saber o que são padrões de design, mas devem ser capazes de rever os programas que escreveram nas primeiras semanas e desgosto em seu código. Eles devem compreender em um nível significativo de detalhes como o primeiro programa que escreveram realmente funciona (ao passo que, quando o escreveram, eles não tinham ideia). Mas eles não saberão tudo - ainda.


Obtendo um ambiente de desenvolvimento mais elaborado

Vamos & # 8217s fazer algumas alterações no programa Hello.c, mas vamos & # 8217s fazê-las em um ambiente de desenvolvimento mais decente & # 8211 queremos um assim chamado IDE (apoia Ambiente de desenvolvimento integrado) & # 8211 muitos desenvolvedores hard-core agora vão dizer que isso é um absurdo, mas ei, eu sei que você pode cozinhar seu bife no fogo, mas quando você tiver um bom churrasco, você usará o churrasco & # 8230

Para o nosso propósito, um IDE chamado Geany fará o truque & # 8211, mas precisa ser instalado no Raspberry.

e pronto. A instalação será iniciada, mas será necessária uma confirmação. A instalação será bem-sucedida, mas quando você tentar executar o programa a partir da linha de comando, receberá um erro: o IDE foi escrito para o XServer Desktop que, por sua vez, exige que mudemos de nossa linha de comando PuTTY para uma conexão RDP. Você encontrará Geany no menu. Eu já carreguei nosso ola.c programa & # 8230

Em primeiro lugar, teremos certeza de colocar o cursor em uma nova linha quando o programa for executado desta vez & # 8211 isso é feito simplesmente adicionando um n à saída, um caractere de controle que adicionará a nova linha. Também precisamos que o programa forneça um código de retorno (caso contrário, o compilador reclamará & # 8230), portanto, outra linha é adicionada: retornar 0

Agora você pode pressionar a tecla F9 para iniciar a compilação & # 8230

Agora poderíamos voltar para nossa sessão PuTTY e revisar o diretório de fontes usando o comando ls. Novamente, encontraremos o código-fonte e o arquivo compilado & # 8211 executá-lo novamente fará com que a saída pareça diferente.