Ir ao conteúdo

arfneto

Membro Pleno
  • Posts

    6.526
  • Cadastrado em

  • Última visita

Tudo que arfneto postou

  1. Cuidado: não é bem assim. @sodcpp talvez deva ver os exemplos no post #9 logo acima onde tem uns exemplos do que significa excluir cada um ou todos esses comandos em C++ ou C. E os comentários sobre outras linguagens Definir --- declarar --- pos dentro do loop depende da lógica do programa. Entenda que uma razão para rodar um loop pode ser exatamente avaliar o valor de pos que safistaz uma condição e sair com esse valor do loop para continuar o programa Ao declarar a variável no loop o escopo --- scope --- dela em C++ é o próprio loop do for e ela deixa de existir na linha seguinte e lá se vai o resultado do cálculo... Pense nisso. Exemplo Veja a saída valor de pos antes do primeiro 'for' = 2019 valor de pos depois do primeiro 'for' = 2019 valor de pos depois do segundo 'for' = 3 Desse programa #include <iostream> using namespace std; int main() { auto pos = 2019; for (;0;); // irrelevante: nao faz nada for (;0;); // mas correto: nao faz nada int uns_int[] = { 1,2,3,4,5 }; primeiro valor > 3 está na posição 3 // usando o for para determinar pos = posicao do primeiro elemento maior que 3 cout << "valor de pos antes do primeiro 'for' = " << pos << endl; for (auto pos = 0; pos < 5; pos = pos + 1) if (uns_int[pos] > 3) break; cout << "valor de pos depois do primeiro 'for' = " << pos << endl; // o mesmo for aqui vai funcionar, sem declarar pos for (pos = 0; pos < 5; pos = pos + 1) if (uns_int[pos] > 3) break; cout << "valor de pos depois do segundo 'for' = " << pos << endl; return 0; }; // main() A redeclaração de pos no for faz com que a variável pos declarada antes desapareça. Ao final do for ela volta a vida com o valor de antes e seu resultado já era. No loop seguinte, como a variável não é redeclarada, tudo funciona e sai com pos = 3. Por outro lado, o pos pode ser eliminado bem como o incremento e a expressão pos<16: obrigatório no for é for(;;); // correto, mas nao termina nunca for(;0;); // correto, roda uma vez e sai apenas. Veja os for "mínimos" lá no programa exemplo também
  2. Tem razão. E ao juntar as variáveis sob um único nome também muitos problemas, como a passagem de parâmetros. E podendo tratar tudo por um único nome facilita muito a manutenção. Só disse que não é necessário porque acho importante ver o enunciado como um contrato de serviço: você não precisa e muitas vezes não pode fazer mais do que está escrito lá. E alocar mil estruturas ou 1002 para ao final calcular a média e outros valores sintéticos é um caso desses de ir além do necessário. adicionado 15 minutos depois @Venus Guy conseguiu terminar o exercício?
  3. @vangodp Desculpe, achei que dava para entender. Vou tentar de outro modo: um sentido é para dentro da implementação, como fazer para isso dar certo, e envolve esses conceitos em torno das tabelas. O outro sentido é para o mundo real, onde alguém usa ou não isso. Quando e porque você declara uma classe ou um único método como virtual, ou classes abstratas em geral. O autor do tópico ficou com a ideia de que isso foi criado apenas para corrigir algum tipo de erro relacionado a ambiguidades. Acho que é algo mais amplo e por isso escrevi os programas em C e C++, mudando o exemplo que está no manual no caso do último. E tentei explicar. Eu ia até escrever uma classe VFT e uma implementação em C++ mas o tempo não permitiu. Entendeu os programas e os conceitos que expliquei?
  4. Sim, mas no sentido contrário. VFT e os tais vptr são o mecanismo interno que em geral se usa para isso funcionar com classes e funções. Explica como se implementa mas não o que é uma classe ou função virtual e para que serviria. O conceito de VFT não é nada novo e sempre se usou em programação de sistemas e em C se usa muito desde os '80. Escrevi um programinha em C agora que cria e usa uma VFT e passa como parâmetro uma tabela dessas --- VFT é um dos nomes --- para outra função e essa função até chama as funções a partir dessa tabela. Deve ajudar a entender melhor os exemplos ou aquele vídeo do YouTube. Funciona em C++ também, só quero mostrar o conceito que é idêntico. Como sempre vou mostrar o resultado primeiro Chama as 3 funcoes pela ordem Ola!Esta e a funcao_1(1,2) Ola!Esta e a funcao_2(3,4) Ola!Esta e a funcao_3(5,6) Chama as 3 funcoes a partir do vertor de enderecos Ola!Esta e a funcao_1(11,22) Ola!Esta e a funcao_2(33,44) Ola!Esta e a funcao_3(55,66) Chama as 3 funcoes a partir de uma funcao seletora seletor(1) Chama funcao_1() Ola!Esta e a funcao_1(100,100) seletor(2) Chama funcao_2() Ola!Esta e a funcao_2(200,200) seletor(3) Chama funcao_3() Ola!Esta e a funcao_3(300,300) E o programa #include "stdio.h" #include <Windows.h> typedef int (*pF_int_int)(int, int); int funcao_1(int, int); int funcao_2(int, int); int funcao_3(int, int); int seletor(int, pF_int_int*); int main(int argc, char** argv) { pF_int_int VFT[4]; // nao usei f[0] so porque nao printf("\nChama as 3 funcoes pela ordem\n"); funcao_1(1, 2); funcao_2(3, 4); funcao_3(5, 6); VFT[1] = funcao_1; VFT[2] = funcao_2; VFT[3] = funcao_3; printf("\nChama as 3 funcoes a partir do vertor de enderecos\n"); VFT[1](11, 22); VFT[2](33, 44); VFT[3](55, 66); printf("\nChama as 3 funcoes a partir de uma funcao seletora\n"); for (int i = 1; i <= 3; i += 1) seletor(i, VFT); return 0; } int funcao_1(int a, int b) { printf("Ola!Esta e a funcao_1(%d,%d)\n", a, b); return 0; }; int funcao_2(int a, int b) { printf("Ola!Esta e a funcao_2(%d,%d)\n", a, b); return 0; }; int funcao_3(int a, int b) { printf("Ola!Esta e a funcao_3(%d,%d)\n", a, b); return 0; }; int seletor(int qual, pF_int_int* VFT) { if ((qual < 1) || (qual > 3)) return -1; printf("\nseletor(%d) Chama funcao_%d()\n", qual, qual); (*VFT[qual])(qual * 100, qual * 100); // chama a funcao pelo numero return 0; }; As linhas mais importantes para entender isso são essas typedef int (*pF_int_int)(int, int); pF_int_int VFT[4]; int seletor(int, pF_int_int*); (*VFT[qual])(qual * 100, qual * 100); // chama a funcao pelo numero O typedef é só para ficar mais legível: pF_int_int passa a ser um tipo e declara um ponteiro para uma função que recebe dois int e retorna outro. Então eu posso declarar VFT como um vetor de quatro dessas coisas E passar para uma função seletor() o vetor todo. De funções. E na função seletor() chamar direto pelo índice usando ( *VTF ) (a,b) Somando isso mais o que eu escrevi sobre as classes no outro post deve ajudar a entender. Estou postando o programa porque vi que é difícil achar referência dessas coisas e vendo os programas fica mais fácil
  5. Winning chances! Tem um livro texto? Uma apostila? Estudou algo sobre isso? Escreva ao menos um programa que crie uns 2 desses para começar e poste aqui as suas dúvidas. Não é complexo, mas é fácil de escrever errado e ruim de testar...
  6. Tem algum trecho de código onde ficaria aparente esse erro? A ideia disso entra nesse cenário: você tem uma classe digamos popular e deriva outras classes a partir dela e a partir dessas deriva outras classes e quer escolher se cada classe herdada traz sua cópia dessa primeira classe base ou não, e você escolheria isso declarando a classe como virtual na sequência de derivação --- herança --- e assim a classe base é propagada pela sequência: SEM duplicar a classe original enquanto estiver presente o especificador virtual Vendo assim, parece que só a lógica de cada problema vai dizer o que é o adequado. Editei um pouco o exemplo do manual para ficar mais legível --- minha opinião claro. Veja o resultado do programa abaixo (era pra ser 1 ) n em X: 2 (mas X e Y compartilham um unico B) n em Y: 2 n em Z: 2 n : 300 Y acessada a partir de Derivada: n: 2 Esse #include <iostream> using namespace std; int main() { class B { public: int n; }; class X : public virtual B {}; class Y : public virtual B {}; class Z : public B {}; class Derivada : X, Y, Z { public: int n; Derivada() { X::n = 1; Y::n = 2; Z::n = 3; n = 300; cout << "(era pra ser 1 ) n em X: " << X::n << endl; cout << "(mas X e Y compartilham um unico B) n em Y: " << X::n << endl; cout << " n em Z: " << X::n << endl; cout << " n : " << n << endl; }; }; Derivada teste; Y* testeY = (Y*)&teste; cout << "\nY acessada a partir de Derivada: n: " << testeY->n << endl; }; Talvez ajude a entender: a classe Derivada vem de X, Y e Z. Herança múltipla. No entanto todas elas derivam de B mas B foi declarada virtual em X e Y então Derivada vai receber um único B a partir dessas Z deriva de B mas nesse caso B não é declarada virtual Mas isso começa a ficar interessante e confuso no último comando do meu programa Derivada teste; Y* testeY = (Y*) &teste; cout << "\nY acessada a partir de Derivada: n: " << testeY->n << endl; que o manual não teve a gentileza de explicar: quando você começa a acessar uma classe através de um ponteiro para uma outra e aí precisa definir muito bem quando é certo ou errado declarar algo como virtual ou não... E o compilador e o runtime vão se virar para descobrir de qual instância buscar a variável n em Isso porque testeY é um ponteiro para Y e vai apontar para teste, uma instância de Derivada, que também é Y. E X. E Z. E essas 3 classes descendem de B onde está o n que vamos imprimir. E Derivada tem seu próprio n também. Uma zona. Recomendo fugir disso. Agora se o seu projeto tem algo que pode ser descrito assim, então vai gostar de estar usando uma dessas linguagens com herança múltipla. "Uma benção" diriam os evangélicos, nesse caso. Funciona de modo semelhante com as funções e nesse caso pode ser mais útil.
  7. Talvez nem seja preciso tudo isso Estamos falando de números e matemática e notação posicional como no ensino fundamental Em um número cada dígito é multiplicado pela base ao se mover para esquerda. Zero é o elemento neutro, então um zero a esquerda não muda nada. Um zero a direita multiplica pela base e essa foi a grande invenção dos então hindus e depois absorvida por todo mundo, séculos atrás. Um número entre 10 milhões Um número assim estaria entre 0 e 9.999.999, e isso é uma sequência de 1 a 7 ... ...Dígitos. Na base 10 temos dez dígitos. Então Você pode usar o seu gerador de números aleatórios e gerar 7 dígitos --- sim, entre 0 e 9 --- e colocar um depois do outro... Só isso. Zero é o elemento neutro então eventuais zeros à esquerda vão sumir mesmo, mas mantendo a probabilidade de 1 para 10 para cada um dos 7 dígitos Só isso Gostaria de ver um programa de exemplo ou entendeu a ideia? De todo modo em limits.h limits.h o header que tem as constantes com os limites e lá você pode ver que ULONG_MAX tem 10 dígitos e será suficiente --- você só precisa de 7 --- se precisar operar com esses valores, sem ter que criar uma classe só para isso, o que podia ser divertido até unsigned long int valores[]; Se não precisa operar com eles, use texto --- char --- mesmo e siga adiante Seu código sugere apenas que precisa gravar em disco 100.000 deles, sem repetição, como texto... Então já imagina o que vou dizer: tanto faz.
  8. Sim, poderia. Mas se for algo que valha nota certamente vai ser penalizado: está alocando nada menos que 1002 estruturas sendo que não precisa de nenhuma: Veja o caso dos e-mail, endereços e telefones: está alocando, salvando e descartando esses valores todos. Basta salvar o nome e salário para o maior e menor salário e manter atualizado conforme entram mais dados. E contando quantos leu e somando os salários. Quando acabar você divide o total de salários pelo total de funcionários e mostra a média e todo o resto. @AdrianoSiqueira Note que não precisa de fato de mais duas estruturas além das que já tem. Basta salvar o índice do maior e menor salário... De todo modo não é uma boa solução, como expliquei.
  9. São apenas duas coisas que precisa fazer. E as duas em torno do mesmo conceito da divisão de números inteiros em C e do número 5 ok esse último é só uma coincidência Com as variáveis abaixo: int a = 12; int b = 9; int c = 5; int ab = a/b; int ac = a/c; ab vale 1 e ac vale 2; isso porque a divisão de inteiros simplesmente trunca o resultado. arredondar o salario é trivial: você divide por 5 vai dar um certo número, que é o que você pagaria em notas de cinco. Pode faltar alguma coisa, entre um centavo e 4,99 certo? Então você dá mais cinco reais e não se fala mais nisso. É o que se chama arredondar para cima. Aí vai ter o valor a ser pago para a funcionária. Salve isso. definir as notas também é simples, uma vez que sabe que var pagar com um número mínimo de notas e usando notas de 5, 10, 20, 50 e 100. Use o mesmo conceito da divisão por inteiros e vá calculando quantas notas de cada valor vai usar e mostrando... Não é nada diferente do que faria pagando a partir da sua carteira...
  10. Mas não tem uma única linha de código no seu programa sobre esses itens a e b... Apenas declare por exemplo int posicao_maior; int maior; int posicao_menor; int menor; e vai mantendo atualizado enquanto preenche o vetor. Só isso. Ao final mostre e pronto. Essa é a parte difícil: um programa me java em C
  11. Então pelo enunciado não funciona nadinha... Entenda que o enunciado nada fala sobre um cadastro real. Nada. Você só precisa de informações sintéticas: maior, menor, média e soma. Só precisa mesmo de um "registro" e pode deixar mesmo tudo separado. Mas você se esqueceu de salvar o nome dos caras que ganham mais ou menos. Basta um loop. Você lê um cara trata os valores e continua. Se terminou calcula a média, que é trivial porque o total você já tem que ter mesmo. E o número de caras você deve ir contando um a um. O maior e o menor e os nomes você vai acompanhando conforme entram. Como os salários são todos positivos basta começar por zero.
  12. Vou ver lá. Entendeu o que expliquei os loops? Tinha uma parte fora de ordem e mudei a redação. Estou perdendo a paciência com esse editor do forum. Demora demais para escrever qualquer coisa...
  13. Sim. Não é você quem está suprimindo o incremento. Quem suprimiu o incremento foi o professor Wirth, criador da linguagem. Era uma das coisas que segundo ele levavam a escrever programas "menos legíveis" e "menos eficientes" como ele escreveu em Pascal User Manual and Report" o "livro do Pascal". Muito embora tenha derivado Pascal diretamente de Algol que tinha o parâmetro Step no loop, foi uma das muitas coisas que ele tirou. for in C O comando em C tem essas 3 partes e todas 3 são sim opcionais. É bem diferente do for em Pascal e é diferente por definição e limitado por decisão. Vou tentar explicar melhor com uns exemplos e referências. As linguagens modernas tem em geral 3 variedades de loop. Citando o Pascal: while/do, repeat/until e o for aritmético. C++ e java e outras tem um outro tipo de for, chamado range-based for loop e depois posso deixar um exemplo desses. Um loop é só tem um bloco anônimo de comandos e o comando define uma disciplina de repetição para ele. Bloco Um bloco em Pascal tem lá Begin e End como delimitadores. C usa as chaves, como outras linguagens. FORTRAN usava o número de comando, e assim vai. Mas Pascal é mais restritivo em relação a isso. Deixando o bloco no meio da execução Pascal e C e outros implementam em geral um comando break e um comando continue que podem deixar em definitivo o loop ou passar de imediato para a próxima iteração, de modo que é comum usar loops ditos *infinitos* usando um comando desses durante a lógica interna ao loop. E em geral há um comando goto para desviar de fato a execução para outro ponto. E comandos como return e exit que tem efeito similar for em Pascal Pascal deriva diretamente e claramente da Linguagem Algol e o loop em Algol tinha um parâmetro STEP, como tem em outras linguagens como Visual Basic hoje. Por decisão do prof. Wirth , o criador de Pascal, *step* foi eliminado. E muitos odiaram. Numa tradução direta do próprio "Pascal User Manual And Report" do criador da linguagem, o equivalente ao "livro branco"do C de Kernighan e Ritchie, você lê: E ele de fato usou essas aspas nesse "bom estilo de programação" Acho que ele era mesmo um pouco chato. E estava desenvolvendo o conceito do que ele chamava de programação estruturada que muitos dizem que evoluiu para a programação orientada a objetos de hoje --- que muitos escrevem OOP De volta aos loops em C e Pascal Um loop em Pascal é pobre e simplificado de propósito. Como não dá pra simplificar a lógica e a realidade, muitas vezes se vai odiar por exemplo a ausência do tal step no for . Um dos objetivos de Pascal era ser _A_ linguagem para ensinar programação. E haviam muitas linguagens na época. Algol nunca ficou popular exceto em certos nichos, como universisdades que usavam computadores da Control Data. FORTRAN e COBOL eram as linguagens de largo uso. Programas em COBOL eram e são as coisas mais legíveis nessa área segundo muitos, mas raramente os autores sabiam ou sabem algo sobre COBOL então era e é um animal a parte. E FORTRAN era a vítima dos acadêmicos e seria substituído pelo moderno e estruturado Pascal em muitas universidades nos cursos inicias de programação. Se você quer suprimir o parâmetro de incremento então está no caminho do Pascal mesmo. Mas em geral acho que não se pode omitir o begin / end de modo que se a ideia é simplificar não vai ser com Pascal, que sempre foi tida como uma linguagem "de muitas palavras". O parâmetro *step* não existe, mas o resto é bem engessado. E de propósito como explicado pelo autor. Autor da linguagem. E qual o propósito de C C derivou diretamente de uma linguagem chamada B e foi criada por cientistas em busca de uma linguagem para acelerar o desenvolvimento de sistemas. Do sistema Unix na Bell Labs em particular. E não por um professor com uma metodologia em mente. Assim os comandos tem um sentido prático sempre. No caso do for: for ( inicializacao; teste; incremento ) {bloco}; tem esse formato genérico, mas tudo é opcional se o bloco tiver um só comando pode omitir `{}` os 3 blocos são separados por duas `;` e essas e os parenteses são mandatórios o primeiro bloco tem os comandos de inicialização, e pode ser como no Pascal for( int CONT=1;;){} por exemplo. Mas você pode declarar várias variáveis, escrever expressões separadas por `,` e tal. Bem flexível. Ou deixar em branco e o sistema não faz nada. o segundo bloco é qualquer coisa que se avalie para um resultado, com 1 sendo verdadeiro e 0 sendo falso. Uma expressão. Como algo assim for ( int i = 0, j = 1; j = (i == 1) ? funcaoA(i,j): funcaoB(j); ); // sem a terceira parte Que declara duas variáveis e termina apenas se j for zero, mas redefine j chamando funcaoA() ou funcaoB() conforme o valor de i. Esse é um exemplo besta só para mostrar o objetivo da linguagem: não ficar no seu caminho e tentar te dizer que assim vai melhor para você, como é em Pascal. o incremento pode ser qualquer coisa, ou nada, nos mesmos moldes. Por exemplo, se você quiser incrementar uma variável que nada tem a ver com o loop e apenas sob certas condições e for algo que sempre é feito ao final do bloco, pode ficar mais claro colocar isso no próprio `for` para orientar o cara que for ler seu programa depois. Veja um exemplo for ( int i = 0, j = 1; j<4; j = (i == 1) ? j : j + 1 ) { printf("j = %d\n", j); i = (i + 1) % 2; }; // incrementa j sob certas condicoes apenas Isso imprime 1 1 2 2 3 3 porque o valor de i vai alternando entre 0 e 1 e o `for` só incrementa `j` se `i` for 1. E você pode omitir qualquer parte dessas ou todas. Em particular, se usar somente a segunda parte o comando é o próprio while e while(condicao) printf("verdade\n"); e for( ;condicao; ) printf("verdade\n"); são a mesma coisa O outro loop: "range-based" Em C++ ou java por exemplo #include <iostream> #include <vector> using namespace std; int main() { std::vector<string> coisas = { "verde", "azul", "amarelo" }; for (auto umaString : coisas) { cout << "uma coisa: " << umaString << endl; } // for return 0; }; // main() mostra uma coisa: verde uma coisa: azul uma coisa: amarelo E isso funciona também em classes definidas pelo usuário, o que abriu um universo de possibilidades de escrever coisas bem legíveis com dados nem tão legíveis, como classes complexas... Isso funciona porque a declaração auto faz com que o compilador procure o que pode ser a variável umaString a partir do que está depois dos ':' . Lá está coisas que foi declarado como vetor e o compilador verifica que é uma classe iterável. E é então o compilador define umaString como um iterador para std::vector e tudo funciona. Também para as classes que você escreve desde que você as torne iteráveis, o que é simples.
  14. Vi seu programa. Ainda não faz quase nada. Note que essa é a definição da estrutura que descreve um processo no Windows /***** Process walking *************************************************/ typedef struct tagPROCESSENTRY32W { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; // this process ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; // associated exe DWORD cntThreads; DWORD th32ParentProcessID; // this process's parent process LONG pcPriClassBase; // Base priority of process's threads DWORD dwFlags; WCHAR szExeFile[MAX_PATH]; // Path } PROCESSENTRY32W; então WCHAR é o tipo de szExeFile. Isso quer dizer que não pode usar strcpy() ou printf() ou strcmp() com esse vetor. Postei uma solução possível para isso num outro tópico. Como te disse, CreateToolhelp32Snapshot() devolve a lista de processos no momento da chamada. Mas aí você precisa chamar OpenProcess() para cada um e pegar as informações de que precisa sobre cada processo. Sem surpresa: elas virão numa estrutura dessas acima para cada processo. Então você precisa armazenar isso de algum modo. E quando for o caso chama as mesmas rotinas e faz a mesma coisa: salva o tal snapshot novo. Entre uma lista e outra você tem processos que se encerraram e processos novos, e precisa comparar as duas listas, que foi o que te mostrei no programa de exemplo. Se quer só os novos tanto faz: é trivial. Um programa normal não tem acesso a muitos dos processos em execução no sistema, mas pelo que escreveu acho que seu interesse está em programas abertos por usuários então estará bem. Para acessar processos do sistema tem que configurar um Handle com as permissões adequadas. Veja na documentação sobre Access Rights na Microsoft começando por aqui: https://docs.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights Assim é. Recomendo rodar o programa que te mostrei no outro tópico e entender porque funciona
  15. Cada fabricante tem um kit de desenvolvimento para criar aplicações desse tipo. E alguns pacotes para desenvolvimento de aplicações também incorporam isso no código. Se você usa C ou C++ é bem imediato e não por acaso os jogos são escritos em geral nessas linguagens. O mundo é bem pequeno no caso desses kits: a NVIDIA tem uma tecnologia, CUDA, a AMD tem outra, AOCC, a Intel outra. E você pode usar OpenGL ou DirectX que acessam a GPU também. E na prática os pacotes de desenvolvimento de jogos também, como Unity e Unreal Engine Muito disso é grátis porque há grande interesse dos fabricantes em que se use esse tipo de ferramenta Veja um exemplo simples e comentado em C++ neste blog da NVIDIA por exemplo https://devblogs.nvidia.com/even-easier-introduction-cuda/ Aqui o software da NVIDIA: https://developer.nvidia.com/cuda-toolkit E da AMD: https://developer.amd.com/tools-and-sdks/ E da Intel: https://software.intel.com/en-us/opencl-sdk E do DirectX da Microsoft: https://support.microsoft.com/pt-br/help/179113/how-to-install-the-latest-version-of-directx E do OpenGL: https://www.khronos.org/opengl/wiki/Getting_Started#Downloading_OpenGL O exemplo #2 não é o que você quer. Threads rodam na CPU.
  16. O que significa? Em windows não há razão para não funcionar E é assim que funciona. Pra fazer do modo como quer ainda falta implementar umas coisas como te expliquei Os arquivos que mostrei são de execução normal em Windows
  17. Olá Seu programa ainda está um pouco longe de funcionar. Sabe o que é uma pilha? Sabe escrever funções?
  18. Escrevi um programinha para mostrar o que eu queria dizer por montar uma estrutura para gravar os dados, seguindo as coisas que já te expliquei nesse e nos outros tópicos sobre essa lista de processos. Vou deixar o programa e uma explicação dessa maneira de escrever. Procurei não comprimir muito o código e não inventar nada, de modo que pode se adaptar para outros casos... Eis a saída do programa, fora a lista de processos que vem antes disso e é só uma lista mesmo. Duas na verdade. Apaguei uma parte das linhas porque não acrescenta nada, E estou postando imagens porque perdi a paciência com o editor do forum que toma muito tempo. Espero que dê para ler e entender algo Eis o programa principal: E uma possibilidade para a estrutura de que falei Recomendo rodar em sua máquina. Preste atenção na técnica de usar um vetor com as estruturas porque facilita muito, em especial porque você pode classificar os ponteiros ao invés de classificar os dados, e ainda pode acessar as estruturas por posição, como um vetor afinal. Muito rápido e resolve muitos problemas comuns. Outro lance é usar insertion sort já na entrada dos dados. Insertion Sort na entrada de dados Depois se eu tiver mais tempo escrevo sobre como apagar corretamente uma estrutura dessas. Você ainda precisa de um alarme para acordar a cada intervalo a rotina que cria os snapshots, e mais umas coisas como te expliquei, o timer e tal. Como eu disse, em C++ seria muito mais fácil. Se der um tempo nos próximos dias escrevo algo Eis o programa todo #pragma once #define _CRT_SECURE_NO_WARNINGS #define _ARFNETO_ CH2019 #include <windows.h> #include <tlhelp32.h> #include <tchar.h> #include "stdio.h" #include "stdlib.h" #include "time.h" struct snapshot { int total; time_t hora; PROCESSENTRY32** processo; }; typedef struct snapshot Snapshot; // novas funcoes Snapshot* build_snapshot(int); int compara_snapshots(Snapshot*, Snapshot*); int get_process_count(); int insere_processo(PROCESSENTRY32*, Snapshot*); unsigned int lista_snapshot(Snapshot*); int main(int argc, char** argv) { char asw; int c = get_process_count(); // quantos processos? printf("\nARFNeto 2019 para o Clube do Hardware - uso livre\n"); printf("\nTotal de %d processos rodando agora\n", c); Snapshot* l = build_snapshot(c); lista_snapshot(l); printf("\nTecle ENTER para ler novo snapshot: "); asw = fgetc(stdin); printf("\n"); c = get_process_count(); // quantos processos? printf("\nTotal de %d processos rodando agora\n", c); Snapshot* m = build_snapshot(c); lista_snapshot(m); printf("\nTecle ENTER para comparar os dois e sair: "); asw = fgetc(stdin); printf("\n"); compara_snapshots(l, m); return 0; }; // main() // // cria uma estrutura snapshot e devolve seu endereco // considerando uma estimativa de processos e alocando // o dobro de espaco so por segurança Snapshot* build_snapshot(int estimativa) { HANDLE hProcesso; HANDLE hSnap; PROCESSENTRY32* p; int total_processos = 0; int sem_acesso = 0; int ss = 0; estimativa = (estimativa < 128) ? 128 : estimativa; // assume minimo de 128 hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnap == INVALID_HANDLE_VALUE) { printf("CreateToolhelp32Snapshot error\n"); return(NULL); }; // if // cria a estrutura com o dobro da estimativa de processos Snapshot* lista = (Snapshot*)malloc(sizeof(Snapshot)); lista->total = 0; lista->hora = time(NULL); lista->processo = (PROCESSENTRY32**)malloc(sizeof(PROCESSENTRY32*) * 2 * estimativa); int n = sizeof(PROCESSENTRY32*) * 2 * estimativa; // cria um registro de processo p = (PROCESSENTRY32*)malloc(sizeof(PROCESSENTRY32)); p->dwSize = sizeof(PROCESSENTRY32); p->th32ProcessID = 3889; if (!Process32First(hSnap, p)) { // primeiro processo em p printf("Erro ao ler primeiro processo\n"); perror("Process32First()"); free(p); free(lista); CloseHandle(hSnap); return(NULL); }; // if // agora salva na lista e le o proximo ate o final do { // entra com um processo em p total_processos += 1; // pode ser que nao tenhamos acesso hProcesso = OpenProcess(PROCESS_ALL_ACCESS, FALSE, p->th32ProcessID); if (hProcesso != NULL) { // ok esse deu pra ler (*(snap->processo + i))->th32ProcessID, insere_processo(p, lista); CloseHandle(hProcesso); // libera o handle // prepara o proximo p = (PROCESSENTRY32*)malloc(sizeof(PROCESSENTRY32)); p->dwSize = sizeof(PROCESSENTRY32); } else { sem_acesso = sem_acesso + 1; } } while (Process32Next(hSnap, p)); free(p); // alocou uma mais no loop CloseHandle(hSnap); return lista; }; // build_snapshot() // // usa o campo dwFlags para marcar em uma lista o que nao // esta na outra. Assim temos os processos novos e os encerrados // int compara_snapshots(Snapshot* A, Snapshot* B) { int i, j, n; char a_hora[40]; char* quando = a_hora; quando = ctime(&A->hora); n = strlen(quando) - 1; quando[n] = 0; // era um \n printf("\ncompara_snapshots()\n\n"); printf("Snapshot A(%s): %d processos\n", quando, A->total); quando = ctime(&B->hora); n = strlen(quando) - 1; quando[n] = 0; // era um \n printf("Snapshot B(%s): %d processos\n", quando, B->total); for (i = 0; i < A->total; i += 1) { DWORD pa = (*(A->processo + i))->th32ProcessID; for (j = 0; j < B->total; j += 1) { DWORD pb = (*(B->processo + j))->th32ProcessID; if (pb > pa) { // sumiu pa (*(A->processo + i))->dwFlags = 1; break; }; // if if (pb == pa) break; // esse permanece }; // for } // for // agora ao contrario for (i = 0; i < B->total; i += 1) { DWORD pb = (*(B->processo + i))->th32ProcessID; for (j = 0; j < A->total; j += 1) { DWORD pa = (*(A->processo + j))->th32ProcessID; if (pa > pb) { // sumiu pb (*(B->processo + i))->dwFlags = 1; break; }; // if if (pb == pa) break; // esse permanece }; // for } // for // lista os que se foram printf("\nProcessos encerrados:\n\n"); int enc = 0; for (i = 0; i < A->total; i += 1) { if ((*(A->processo + i))->dwFlags == 1) { enc += 1; printf("%03d: pID=%8d exe [%ls]\n", enc, (*(A->processo + i))->th32ProcessID, (*(A->processo + i))->szExeFile ); }; // if }; // for // lista os que foram iniciados depois printf("\nProcessos criados:\n\n"); int criados = 0; for (i = 0; i < B->total; i += 1) { if ((*(B->processo + i))->dwFlags == 1) { criados += 1; printf("%03d: pID=%8d exe [%ls]\n", criados, (*(B->processo + i))->th32ProcessID, (*(B->processo + i))->szExeFile ); }; // if }; // for printf("\nIntervalo entre as consultas: %gs\n\n", difftime(B->hora, A->hora)); return 0; }; // compara_snapshots() // // return the number of processes running, to aid in dimensioning the // arrays used to compare snapshots // conta quantos processos estão rodando. Eu ia escrever tudo em inglês // mas parei :) int get_process_count() { HANDLE hProcessSnap; PROCESSENTRY32 pe32; pe32.dwSize = sizeof(PROCESSENTRY32); int total_processes = 0; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { return(-1); } if (!Process32First(hProcessSnap, &pe32)) { CloseHandle(hProcessSnap); return(-2); } do total_processes += 1; while (Process32Next(hProcessSnap, &pe32)); CloseHandle(hProcessSnap); return(total_processes); }; // get_process_count() // // faz o obvio: insere o processo p na estrutura de snapshot lista int insere_processo(PROCESSENTRY32* processo, Snapshot* lista) { int pos = lista->total; while (pos > 0) { // insertion sort DWORD atual = (*(lista->processo + pos - 1))->th32ProcessID; // printf("processo atual: %d\n", atual); if (atual > processo->th32ProcessID) { // abre aqui para inserir o cara (*(lista->processo + pos)) = (*(lista->processo + pos - 1)); pos = pos - 1; } else { break; }; // if }; // while // vai inserir o novo sempre em pos processo->dwFlags = 0; // para usar no controle de processos (*(lista->processo + pos)) = processo; lista->total += 1; return 0; }; // insere_processo() // apenas lista dois campos do snapshot unsigned int lista_snapshot(Snapshot* snap) { char a_hora[40]; char* quando = a_hora; quando = ctime(&snap->hora); int n = strlen(quando) - 1; quando[n] = 0; // era um \n printf("\nlista_snapshot(em %s):\n\n%d processos [com acesso permitido]\n\n", quando, snap->total); for (int i = 0; i < snap->total; i += 1) { printf("%03d: pID=%8d exe [%ls]\n", i, (*(snap->processo + i))->th32ProcessID, (*(snap->processo + i))->szExeFile ); } return snap->total; }; // lista_snapshot()
  19. Está bem. Vou dar uma olhada. Você leu de fato o que eu escrevi aqui sobre como fazer isso? Para comparar você precisa de dois. E uma estrutura de dados para salvar os dois. E um intervalo para o refresh, que pode ser só um ENTER enquanto estiver testando. Fazer em C é mais difícil como te expliquei. Mas também é mais divertido Vou pensar em algo e te mostro. adicionado 4 minutos depois Esse modelo que está usando é praticamente o programa que te mostrei. Você precisa acrescentar a sua necessidade. Esse programa é só um exemplo da microsoft
  20. Use as funções do sistema e crie uma função que roda em um thread separado para "consumir" os dados enquanto seu programa prossegue em main()... Veja um exemplo naquele lugar https://docs.microsoft.com/pt-br/cpp/parallel/multithreading-with-c-and-win32?view=vs-2019 que tem tudo sobre Windows. Tem um programa de exemplo. Em C.
  21. O que vai ser o novo tópico? Poste o programa todo em C pra gente ver. Aí rodo em minha máquina
  22. Acho que não me expliquei bem. Em C++ é mais fácil, não mais difícil. Em C as convenções de chamada são as mesmas, as estruturas de loop são as mesmas, mas é só isso. Em C++ é mais fácil. Vou ver depois esse trecho que postou.
  23. Tipo um sleep até receber o alarme. Mas acho que no Windows isso é arriscado. Veja essa função BOOL CreateTimerQueueTimer( PHANDLE phNewTimer, HANDLE TimerQueue, WAITORTIMERCALLBACK Callback, PVOID DueTime, DWORD Period, DWORD Flags, ULONG Parameter ); Descrita Lá onde tem tudo sobre Windows é uma que pode ajudar. No fundo você quer parar por um tempo e quando der a hora você executa uma função que pega um snapshot e compara com o anterior. Um desenvolvedor excepcional chamado Mark Russinovich escreveu um desses programas anos atrás e você pode ver em https://docs.microsoft.com/pt-br/sysinternals/downloads/ e baixar uma cópia. Ele usou as mesmas estruturas que você vai usar. E é muito muito muito bom. Veja o Process Explorer e o Process Monitor. São dos anos 90 Outro programa para ver claro é o TaskMGR.exe que você pode rodar em sua máquina: Win+R TaskMgr.exe Process Monitor Process Explorer Task Manager
  24. Acho que eu postei algo sobre isso aqui esses dias, inclusive o link para a documentação e um programa exemplo da Microsoft https://docs.microsoft.com/pt-br/windows/win32/toolhelp/taking-a-snapshot-and-viewing-processes Acho que você está indo no caminho certo, mas achei um pouco complicado. O que esse programa originalmente fazia era usar essas chamadas a Process32First() e depois ir chamando Process32Next() enquanto ela retornar algo, e montar um retrato --- snapshot -- de momento dos processos rodando no sistema, tudo em torno dessa estrutura aí abaixo typedef struct tagPROCESSENTRY32 { DWORD dwSize; DWORD cntUsage; DWORD th32ProcessID; ULONG_PTR th32DefaultHeapID; DWORD th32ModuleID; DWORD cntThreads; DWORD th32ParentProcessID; LONG pcPriClassBase; DWORD dwFlags; CHAR szExeFile[MAX_PATH]; } PROCESSENTRY32; Estamos usando C++. Então tudo sugere o simples, como o sistema faz: crie uma classe Snapshot com essa lista de processos, programe um alarme para daí a um certo intervalo. E aí cria outro snapshot. Cria uma função na classe SnapShot que compara duas variáveis desse tipo e retorna a diferença, elá deve estar a lista de programas que foram abertos entre um snapshot e o próximo. BOOL QueryFullProcessImageNameA( HANDLE hProcess, DWORD dwFlags, LPSTR lpExeName, PDWORD lpdwSize ); Essa função aí acima retorna o caminho para o executável, e você pode filtrar aí por exemplo, excluindo determinados programas porque a lista pode ter centenas deles. Não precisa usar sort() e fornecer compare(). Basta usar uma classe que já ofereça ordem, tipo Map ou Set ou uma simples lista ou vetor em que você insere os caras já na ordem. Pense bem: você lê um por um e espera para chamar sort no fim? Porque já não insere na ordem ou usa uma estrutura que já faça isso? E se tivesse esse tal SnapShot poderia declarar SnapShot* A, B; A = new SnapShot; // programa um alarme para o intervalo que quer B = new SnapShot; e escrever uma função SnapShot dif(SnapShot* antes, SnapShot* agora); por exemplo que faria a diferença entre os dois e retornaria um terceiro SnapShot só com a diferença. Ou mesmo redefinir o operador ´-´ e poder escrever SnapShot novos = B - A; postei um código aqui que mostra como fazer isso, algo com ´sobrecarga de operadores´ no título. E na criação de cada SnapShot você enfia essa lógica de montar uma lista dos processos que tem um nome de um executável no disco... Na criação quer dizer o construtor da classe e não precisa de mais de um construtor porque o processo só tem um jeito mesmo.
  25. Não sei se entendi. Você quer que mostre ao iniciar o nome do programa que foi aberto? Ou identificar os dados do processo, do seu processo, no windows? Se quer o nome do programa, pode usar argv[0] que é exatamente isso.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!