Ir ao conteúdo
  • Cadastre-se

arfneto

Membro Pleno
  • Posts

    6.207
  • Cadastrado em

  • Última visita

Tópicos solucionados

  1. O post de arfneto em função externa para converte uma array foi marcado como solução   
    Note que na prática certamente seria preciso um parâmetro com o tamanho do array. Se o tamanho é sempre 5 deveria estar na declaração [5] e não [ ] 
     
    Isso é só uma prova de conceito para ver como escrever.
     
    Eis um exemplo de como escrever:
     
    saida
     
    Vetor de char original: Valores em char: '1' '2' '3' '4' '8' Vetor de 'int' convertido: Valores em decimal: 1 2 3 4 8 Vetor convertido (versão de um parametro): Valores em decimal: 1 2 3 4 8  
    Código
     
    #include <stdio.h> #include <stdlib.h> int* Converte(char[]); int converte(char origem[], int destino[]); int mostra_char(char[], const char*); int mostra_int(int[], const char*); int main(void) { char ent[5] = {'1', '2', '3', '4', '8'}; int sai[5] = {0}; mostra_char((int*) ent, "Vetor de char original:"); converte(ent, sai); mostra_int(sai, "Vetor de 'int' convertido:"); int* outro = Converte(ent); mostra_int( outro, "Vetor convertido (versão de um parametro):"); free(outro); // apaga return 0; } int* Converte(char origem[]) { int* destino = (int*)malloc(5 * sizeof(int)); if (destino == NULL) return NULL; for (int i = 0; i < 5; i += 1) *(destino + i) = origem[i] - '0'; return destino; } int converte(char origem[], int destino[]) { for (int i = 0; i < 5; i += 1) destino[i] = origem[i] - '0'; return 0; } int mostra_char(char v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em char: "); for (int i = 0; i < 5; i += 1) printf("'%c' ", v[i]); printf("\n"); return 0; } int mostra_int(int v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em decimal: "); for (int i = 0; i < 5; i += 1) printf("%d ", v[i]); printf("\n"); return 0; }  
     
    Sobre seu código
     
     
    porque só tem 4?
     
    Está muito confuso como escreveu. Não entendi. Mas não está certo.
  2. O post de arfneto em função externa para converte uma array foi marcado como solução   
    Note que na prática certamente seria preciso um parâmetro com o tamanho do array. Se o tamanho é sempre 5 deveria estar na declaração [5] e não [ ] 
     
    Isso é só uma prova de conceito para ver como escrever.
     
    Eis um exemplo de como escrever:
     
    saida
     
    Vetor de char original: Valores em char: '1' '2' '3' '4' '8' Vetor de 'int' convertido: Valores em decimal: 1 2 3 4 8 Vetor convertido (versão de um parametro): Valores em decimal: 1 2 3 4 8  
    Código
     
    #include <stdio.h> #include <stdlib.h> int* Converte(char[]); int converte(char origem[], int destino[]); int mostra_char(char[], const char*); int mostra_int(int[], const char*); int main(void) { char ent[5] = {'1', '2', '3', '4', '8'}; int sai[5] = {0}; mostra_char((int*) ent, "Vetor de char original:"); converte(ent, sai); mostra_int(sai, "Vetor de 'int' convertido:"); int* outro = Converte(ent); mostra_int( outro, "Vetor convertido (versão de um parametro):"); free(outro); // apaga return 0; } int* Converte(char origem[]) { int* destino = (int*)malloc(5 * sizeof(int)); if (destino == NULL) return NULL; for (int i = 0; i < 5; i += 1) *(destino + i) = origem[i] - '0'; return destino; } int converte(char origem[], int destino[]) { for (int i = 0; i < 5; i += 1) destino[i] = origem[i] - '0'; return 0; } int mostra_char(char v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em char: "); for (int i = 0; i < 5; i += 1) printf("'%c' ", v[i]); printf("\n"); return 0; } int mostra_int(int v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em decimal: "); for (int i = 0; i < 5; i += 1) printf("%d ", v[i]); printf("\n"); return 0; }  
     
    Sobre seu código
     
     
    porque só tem 4?
     
    Está muito confuso como escreveu. Não entendi. Mas não está certo.
  3. O post de arfneto em função externa para converte uma array foi marcado como solução   
    Note que na prática certamente seria preciso um parâmetro com o tamanho do array. Se o tamanho é sempre 5 deveria estar na declaração [5] e não [ ] 
     
    Isso é só uma prova de conceito para ver como escrever.
     
    Eis um exemplo de como escrever:
     
    saida
     
    Vetor de char original: Valores em char: '1' '2' '3' '4' '8' Vetor de 'int' convertido: Valores em decimal: 1 2 3 4 8 Vetor convertido (versão de um parametro): Valores em decimal: 1 2 3 4 8  
    Código
     
    #include <stdio.h> #include <stdlib.h> int* Converte(char[]); int converte(char origem[], int destino[]); int mostra_char(char[], const char*); int mostra_int(int[], const char*); int main(void) { char ent[5] = {'1', '2', '3', '4', '8'}; int sai[5] = {0}; mostra_char((int*) ent, "Vetor de char original:"); converte(ent, sai); mostra_int(sai, "Vetor de 'int' convertido:"); int* outro = Converte(ent); mostra_int( outro, "Vetor convertido (versão de um parametro):"); free(outro); // apaga return 0; } int* Converte(char origem[]) { int* destino = (int*)malloc(5 * sizeof(int)); if (destino == NULL) return NULL; for (int i = 0; i < 5; i += 1) *(destino + i) = origem[i] - '0'; return destino; } int converte(char origem[], int destino[]) { for (int i = 0; i < 5; i += 1) destino[i] = origem[i] - '0'; return 0; } int mostra_char(char v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em char: "); for (int i = 0; i < 5; i += 1) printf("'%c' ", v[i]); printf("\n"); return 0; } int mostra_int(int v[], const char* tit) { if (tit != NULL) printf("%s\n", tit); printf("\tValores em decimal: "); for (int i = 0; i < 5; i += 1) printf("%d ", v[i]); printf("\n"); return 0; }  
     
    Sobre seu código
     
     
    porque só tem 4?
     
    Está muito confuso como escreveu. Não entendi. Mas não está certo.
  4. O post de arfneto em Smart Poiters na lista simplesmente encadeada foi marcado como solução   
    @Prodigy085 Eu escrevi uma versão de insert usando unique_ptr e vou deixar aqui.
     
    No geral acho mesmo que o programa ficou menor e mais fácil de ler. Mas é um outro jeito de pensar, porque se por um lado dá uma paz na mente de não ter que pensar na ordem, dos destrutores, nos delete e em RAII. Por outro lado um erro na lógica e a estrutura toda some  
     
    Esse exemplo é mais completo então sugiro marcar esse como resposta até aparecer uma resposta melhor, que pode ser o seu código revisado   
     
    Veja a versão de insert()
     
    int LinkedList::insert(Item data, size_t pos) { // insere 'data' na posicao pos if (pos > (1 + m_size)) return -1; // não da Upn novo(new Node(data)); if (pos < 2) { // aceita 0 ou 1 para o inicio novo->next.swap(m_head); m_head.swap(novo); // novo inicio m_size += 1; return 0; }; // avanca 'pos'- 2 Nodes Node* p = m_head.get(); // comeca aqui for (size_t i = 0; i < pos - 2; i += 1) p = p->next.get(); // salva o sucessor desse Upn temp = std::move(p->next); novo->next.swap(temp); p->next.swap(novo); // novo vem aqui m_size += 1; return 0; }  
    que retorna -1 se a posição pedida é inválida.
     
    Essa versão aceita 0 ou 1 para inserir no início e size()+1 para inserir no fim, porque sempre tem essa ambiguidade. Então se usar insert(,4) o novo registro vai ser o quarto e parece mais intuitivo assim. De todo modo é só um exemplo e é a minha versão.
     
    Se existe insert(,n) então as outras ficam triviais...
     
    Claro que insert(,1) ou insert(,0) inserem no início e insert(,1+size()) insere no fim então dá para escrever push_front() e push_back() para inserir no início e no fim da lista como esperado, usando insert():
     
    int LinkedList::push_back(Item data) { // insere no final return insert(data, 1 + m_size); } int LinkedList::push_front(Item data) { // insere no inicio return insert(data, 1); }  
    O código
     
    node.h
     
    #ifndef NODE_H #define NODE_H #include <iostream> #include <memory> #include <string> using Item = std::string; struct Node { Item data; std::unique_ptr<Node> next; explicit Node(Item& d) : data(d) { next.release(); } ~Node() { std::cerr << "Destruindo Node \"" << data << "\"\n"; } friend std::ostream& operator<<( std::ostream& out, const Node& node) { out << "(" << node.data << ")\n"; return out; } }; #endif  
    LinkedList.h
     
    #ifndef LINKEDLIST_H #define LINKEDLIST_H #include <iostream> #include <optional> using namespace std; #include "Node.h" using Ost = std::ostream; using Upn = std::unique_ptr<Node>; class LinkedList { private: Upn m_head; size_t m_size; public: LinkedList(); ~LinkedList(); public: void clear(); bool empty(); int insert(Item data, size_t pos); [[nodiscard]] optional<Item> pop_back(); [[nodiscard]] optional<Item> pop_front(); int push_back(Item data); int push_front(Item data); int size(); // para teste int cria_uns(size_t); friend Ost& operator<<(Ost& out, const LinkedList& l); }; #endif  
    Inclui os atributos [[nodiscard]] --- C++17 --- em pop_back() e pop_front() para mostrar como a linguagem evolui e a razão das coisas.
    Ao retirar um cara da lista se não colocar em algum lugar o compilador vai avisar. Porque isso é bom? Porque vai tirar um cara da lista e ele vai desaparecer. Pode muito bem ser um erro do programa.  E erros custam tempo e dinheiro.
     
    Exemplo
     
    cout << "\nTenta retirar o ultimo duas vezes\n"; auto ultimo = list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia") << "\"\n"; ultimo = list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia!") << "\"\n";  
    Isso está certo e tira os 2 últimos caras da lista e mostra na tela. Está no exemplo e mostra algo assim
     
    0014 (F I N A L +2) 0015 (F I N A L +3) ] Tenta retirar o ultimo duas vezes Destruindo Node "F I N A L +3" Ultimo: "F I N A L +3" Destruindo Node "F I N A L +2" Ultimo: "F I N A L +2"  
    Claro que foi escrito com recortar e colar  . Mas e se por engano fosse digitado assim
     
    cout << "\nTenta retirar o ultimo duas vezes\n"; auto ultimo = list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia") << "\"\n"; list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia!") << "\"\n";  
    O programa ainda tira os dois caras, mas faltou atribuir o ítem extraido. Era pra ser ultimo = list.pop_back(); ao invés de list.pop_back(); só. E agora vai mostrar
     
    0014 (F I N A L +2) 0015 (F I N A L +3) ] Tenta retirar o ultimo duas vezes Destruindo Node "F I N A L +3" Ultimo: "F I N A L +3" Destruindo Node "F I N A L +2" Ultimo: "F I N A L +3"  
    repetindo o último valor errado... Claro que aqui fica óbvio porque o destrutor do Node é chamado automaticamente e mostra que o Node sendo apagado é outro. Mas o normal seria
     
    0014 (F I N A L +2) 0015 (F I N A L +3) ] Tenta retirar o ultimo duas vezes Ultimo: "F I N A L +3" Ultimo: "F I N A L +3"  
    E alguém vai ter que descobrir como acontece uma coisa dessas. E se fosse em outro ponto de um programa enorme podia custar horas até descobrir que na pressa alguém esqueceu de atribuir o valor extraído...
     
    Com o uso desse atributo quando compila o programa aparece C4834:
     
    mainv3.cpp(73,9): warning C4834: discarding return value of function with 'nodiscard' attribute e pelo menos avisa o programador de que algo POSSA estar errado. E aqui estava.
     
    Em C++20
     
    Em C++20 isso mudou e se pode até escrever a razão no aviso usando uma simples mensagem
     
    [[nodiscard("não usar o valor extraido pode ser uma grande bobagem. eu avisei")]] optional<Item> pop_back();  
    E ao compilar o compilador avisa
     
    mainv3.cpp(73,9): warning C4858: discarding return value: não usar o valor extraido pode ser uma grande bobagem. eu avisei  
    E não é que estava errado mesmo?  
     
    De volta ao programa exemplo
     
    Eis LinkedList.cpp 
     
    // // sem o compilador certo não da para // usar <ranges> nem <format> // //#define CPP23__ #ifndef CPP23__ #include <cstdio> #else #include <format> #include <ranges> #endif #include <iostream> #include "LinkedList.h" LinkedList::LinkedList() : m_head(nullptr), m_size(0) { std::cerr << "Lista criada\n"; } LinkedList::~LinkedList() { std::cerr << "Lista destruida." " Os Nodes não tem mais dono\n"; } void LinkedList::clear() { m_size = 0; m_head.reset(); } bool LinkedList::empty() { return m_size == 0; } optional<Item> LinkedList::pop_back() { // retorna e extrai o ultimo if (empty()) return {}; // o simples if (m_size == 1) return pop_front(); // avanca ate o ultimo node Node* p = m_head.get(); // comeca aqui for (size_t i = 0; i < m_size - 2; i += 1) p = p->next.get(); Upn ultimo = std::move(p->next); m_size = m_size - 1; // ajusta return ultimo->data; // vai ser apagado a seguir } [[nodiscard]] optional<Item> LinkedList::pop_front() { if (empty()) return {}; Item primeiro = m_head->data; m_head.swap(m_head->next); m_size = m_size - 1; return primeiro; } int LinkedList::push_back(Item data) { // insere no final return insert(data, 1 + m_size); } int LinkedList::push_front(Item data) { // insere no inicio return insert(data, 1); } int LinkedList::size() { return m_size; } int LinkedList::insert(Item data, size_t pos) { // insere 'data' na posicao pos if (pos > (1 + m_size)) return -1; // não da Upn novo(new Node(data)); if (pos < 2) { // aceita 0 ou 1 para o inicio novo->next.swap(m_head); m_head.swap(novo); // novo inicio m_size += 1; return 0; }; // avanca 'pos'- 2 Nodes Node* p = m_head.get(); // comeca aqui for (size_t i = 0; i < pos - 2; i += 1) p = p->next.get(); // salva o sucessor desse Upn temp = std::move(p->next); novo->next.swap(temp); p->next.swap(novo); // novo vem aqui m_size += 1; return 0; } // essas duas funcoes dependem de <ranges> e <format> // e se não tiver isso usa C e sprintf() #ifndef CPP23__ Ost& operator<<(Ost& out, const LinkedList& l) { out << "(" << l.m_size << " Elementos)\n"; if (l.m_size == 0) return out; out << "[\n"; Node* p = l.m_head.get(); char num[10]{}; for (size_t i = 1; i <= l.m_size; i += 1) sprintf(num, "%04d\t", i), out << "\t" << string(num) << *p, p = p->next.get(); out << "]\n"; return out; } int LinkedList::cria_uns(size_t qtd) { // cancela se a lista não estiver vazia if ((m_size != 0) || (qtd == 0)) return -1; // sem sentido char item[20]{}; for (size_t i = 1; i <= qtd; i += 1) sprintf(item, "Item %06d", i), push_back(string(item)); return 0; } #else Ost& operator<<(Ost& out, const LinkedList& l) { out << "(" << l.m_size << " Elementos)\n"; if (l.m_size == 0) return out; out << "[\n"; Node* p = l.m_head.get(); for (int i = 1; i <= l.m_size; i += 1) out << "\t" << std::format("{:0>4}\t", i) << *p, p = p->next.get(); out << "]\n"; return out; }; int LinkedList::cria_uns(size_t qtd) { // cancela se a lista não estiver vazia if ((m_size != 0) || (qtd == 0)) return -1; // sem sentido for (auto i : std::views::iota(0, (int)qtd)) push_back(std::format("Item {:0>6}", qtd - i)); return 0; } #endif  
    E o código do teste
     
    #include <iostream> #include "LinkedList.h" using namespace std; int main(void) { LinkedList list; cout << list; cout << "Tentando extrair primeiro valor = " << list.pop_back().value_or("[Lista Vazia]") << "\n"; // chama insert na lista vazia cout << "Tenta inserir terceiro elemento\n"; auto res = list.insert("Item 000000", 3); cout << "retornou " << res << "\n"; cout << list; cout << "Tenta inserir na posicao 0\n"; list.insert("Item 0", 0); cout << list; cout << "Tenta retirar o primeiro duas vezes\n"; auto primeiro = list.pop_front(); cout << "Primeiro: \"" << primeiro.value_or("Lista Vazia") << "\"\n"; primeiro = list.pop_front(); cout << "Primeiro: \"" << primeiro.value_or("Lista Vazia!") << "\"\n"; // insere 4 e lista auto t = 7; cout << "Inserindo " << t << " elementos:\n"; list.cria_uns(t); cout << list; // insere um cara no inicio cout << "\nTenta inserir no inicio\n"; list.insert("No inicio", 0); cout << list; cout << "\nTenta inserir de novo no inicio\n"; list.insert("Novo inicio", 1); cout << list; cout << "\nTenta inserir no final\n"; list.insert("F I N A L", list.size()); cout << list; cout << "\nTenta inserir +1 no final\n"; list.insert("F I N A L +1", list.size()); cout << list; cout << "\nTenta inserir depois do final\n"; list.insert("F I N A L +2", 1 + list.size()); cout << list; cout << "\nTenta inserir depois do final\n"; list.insert("F I N A L +3", 1 + list.size()); cout << list; cout << "\nTenta inserir um segundo registro\n"; list.insert("SEGUNDO REGISTRO", 2); cout << list; cout << "\nTenta inserir um quinto registro\n"; list.insert("QUINTO REGISTRO", 5); cout << list; cout << "\nTenta retirar o ultimo duas vezes\n"; auto ultimo = list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia") << "\"\n"; ultimo = list.pop_back(); cout << "Ultimo: \"" << ultimo.value_or("Lista Vazia!") << "\"\n"; // clear() // tenta apagar todo mundo no automatico cout << "\n====> testando clear()\n"; list.clear(); cout << "\n====> retornou de clear()\n"; cout << list; // vazia claro return 0; }  
    E a saída do EXEMPLO
     
    Lista criada (0 Elementos) Tentando extrair primeiro valor = [Lista Vazia] Tenta inserir terceiro elemento retornou -1 (0 Elementos) Tenta inserir na posicao 0 (1 Elementos) [ 0001 (Item 0) ] Tenta retirar o primeiro duas vezes Primeiro: "Item 0" Primeiro: "Lista Vazia!" Inserindo 7 elementos: (7 Elementos) [ 0001 (Item 000001) 0002 (Item 000002) 0003 (Item 000003) 0004 (Item 000004) 0005 (Item 000005) 0006 (Item 000006) 0007 (Item 000007) ] Tenta inserir no inicio (8 Elementos) [ 0001 (No inicio) 0002 (Item 000001) 0003 (Item 000002) 0004 (Item 000003) 0005 (Item 000004) 0006 (Item 000005) 0007 (Item 000006) 0008 (Item 000007) ] Tenta inserir de novo no inicio (9 Elementos) [ 0001 (Novo inicio) 0002 (No inicio) 0003 (Item 000001) 0004 (Item 000002) 0005 (Item 000003) 0006 (Item 000004) 0007 (Item 000005) 0008 (Item 000006) 0009 (Item 000007) ] Tenta inserir no final (10 Elementos) [ 0001 (Novo inicio) 0002 (No inicio) 0003 (Item 000001) 0004 (Item 000002) 0005 (Item 000003) 0006 (Item 000004) 0007 (Item 000005) 0008 (Item 000006) 0009 (F I N A L) 0010 (Item 000007) ] Tenta inserir +1 no final (11 Elementos) [ 0001 (Novo inicio) 0002 (No inicio) 0003 (Item 000001) 0004 (Item 000002) 0005 (Item 000003) 0006 (Item 000004) 0007 (Item 000005) 0008 (Item 000006) 0009 (F I N A L) 0010 (F I N A L +1) 0011 (Item 000007) ] Tenta inserir depois do final (12 Elementos) [ 0001 (Novo inicio) 0002 (No inicio) 0003 (Item 000001) 0004 (Item 000002) 0005 (Item 000003) 0006 (Item 000004) 0007 (Item 000005) 0008 (Item 000006) 0009 (F I N A L) 0010 (F I N A L +1) 0011 (Item 000007) 0012 (F I N A L +2) ] Tenta inserir depois do final (13 Elementos) [ 0001 (Novo inicio) 0002 (No inicio) 0003 (Item 000001) 0004 (Item 000002) 0005 (Item 000003) 0006 (Item 000004) 0007 (Item 000005) 0008 (Item 000006) 0009 (F I N A L) 0010 (F I N A L +1) 0011 (Item 000007) 0012 (F I N A L +2) 0013 (F I N A L +3) ] Tenta inserir um segundo registro (14 Elementos) [ 0001 (Novo inicio) 0002 (SEGUNDO REGISTRO) 0003 (No inicio) 0004 (Item 000001) 0005 (Item 000002) 0006 (Item 000003) 0007 (Item 000004) 0008 (Item 000005) 0009 (Item 000006) 0010 (F I N A L) 0011 (F I N A L +1) 0012 (Item 000007) 0013 (F I N A L +2) 0014 (F I N A L +3) ] Tenta inserir um quinto registro (15 Elementos) [ 0001 (Novo inicio) 0002 (SEGUNDO REGISTRO) 0003 (No inicio) 0004 (Item 000001) 0005 (QUINTO REGISTRO) 0006 (Item 000002) 0007 (Item 000003) 0008 (Item 000004) 0009 (Item 000005) 0010 (Item 000006) 0011 (F I N A L) 0012 (F I N A L +1) 0013 (Item 000007) 0014 (F I N A L +2) 0015 (F I N A L +3) ] Tenta retirar o ultimo duas vezes Destruindo Node "F I N A L +3" Ultimo: "F I N A L +3" Destruindo Node "F I N A L +2" Ultimo: "F I N A L +2" ====> testando clear() Destruindo Node "Novo inicio" Destruindo Node "SEGUNDO REGISTRO" Destruindo Node "No inicio" Destruindo Node "Item 000001" Destruindo Node "QUINTO REGISTRO" Destruindo Node "Item 000002" Destruindo Node "Item 000003" Destruindo Node "Item 000004" Destruindo Node "Item 000005" Destruindo Node "Item 000006" Destruindo Node "F I N A L" Destruindo Node "F I N A L +1" Destruindo Node "Item 000007" ====> retornou de clear() (0 Elementos) Lista destruida. Os Nodes não tem mais dono  
    Claro que é só recortar e colar muitas vezes.
     
     
  5. O post de arfneto em c++ somente um tipo como entrada foi marcado como solução   
    mas não usou nenhuma das sugestões
     
    E o programa não funciona como escreveu e marcou como solução. Você escreveu um programa em C praticamente. E se o cara digitar "123456teste"? testou isso? Acho que não. "123456"? Acho que não.
     
    Use o botão code como explicado no primeiro post do forum.
     
    Veja a diferença
     
    #include <iostream> using namespace std; int main() { char num[5]; int i, comp[5]; bool flag; do { flag = false; cout << "Digite somente numeros de ate 5 digitos: " << endl; cin >> num; for (i = 0; i < 5; i++) { comp[i] = num[i]; if (comp[i] < 48 || comp[i] > 57) { flag = true; } } } while (flag == true); cout << num << endl; return 0; }  
    Tente algo assim
     
    #include <iostream> #include <string> using namespace std; int main(void) { string linha; unsigned num = 0; cout << "Digite um numero sem sinal de ate 5 digitos\n\n"; while (true) { cout << "\tNumero: "; getline(cin, linha); if (cin.fail()) return(-1); if (cin.bad()) continue; if ((linha.size() == 0) or (linha.size() > 5)) continue; auto alguma_letra = false; for (auto i = 0; i < linha.size(); i += 1) if ((linha[i] < '0') || (linha[i] > '9')) { alguma_letra = true; break; } if (alguma_letra) continue; // le de novo num = atoi(linha.c_str()); //converte break; }; cout << "\n\tNumero: " << num << "\n"; return 0; }  
  6. O post de arfneto em linguagem c ordenacao crescente foi marcado como solução   
    Se vai ordenar a lista in-place, ordenando a própria lista e não retornando outra ordenada, talvez seja melhor simplesmente modificar insere() e já inserir na ordem. Afinal se depois de classificar usar uma de suas outras funções de inserção vai zoar a classificação de todo modo e a única maneira de garantir que vai estar em ordem é classificar toda hora...
     
    Sobre a classificação o simples é uma função de comparação entre dois nós. No seu caso o dado é um simples número.
     
    É provavelmente melhor usar um ponteiro no nó e não o dado. Assim pode ter mais listas apontando para os mesmos dados, por exemplo.
     
    Evite retornar void. Em geral é um desperdício. Muitas vezes um erro mesmo. USe parâmetros e retorne resultados. Por exemplo, criar lista deveria retornar o endereço de uma lista. 
     
    LISTA* li = (LISTA*)malloc(sizeof(LISTA)); if (li == NULL) { printf("Memory Allocation Error"); exit(-1); } else { startLISTA(li);  
    por exemplo estaria bem melhor como
     
    LISTA* li = startLISTA();  
  7. O post de arfneto em Inicializar array com elementos iguais a 0. foi marcado como solução   
    Acho que o maior erro está mesmo na linha 11 em main, fora do loop, onde deixou um 
     
    Array v(0);  
    que não faz sentido e gera comportamento indefinido --- UB.
     
     
    header em português é cabeçalho, masculino. Provavelmente estaria melhor escrevendo UM header.
     
    Imagino que tenha uma razão para reescrever array, que está presente em std usando o include apropriado, <array>.
     
    Como tem vários operadores redefinidos vou deixar umas notas sobre isso, algo que provavelmente receberia em sua empresa se ela tiver um comitê de revisão, ou de seu professor, considerando as recomendações comuns de boas práticas desde 2010 mais ou menos.
     
    Tem ainda uns erros em seu programa, que vou listar no texto.
     
    Escrevo isso "tudo" porque pode ser um exemplo para quem precisa de uma classe assim. Sugiro acompanhar o exemplo.
     
    Isso é problemático em seu programa:
     
    Array v(0);
    Porque precisa disso? Espere até ter um valor e apenas então crie `v`. Acessar esse ponteiro leva a um comportamento indefinido, o popular `UB`. E nunca é bom.
     
    Lendo um pouco mais seu código
     
    Array v(0); while (true) { getline(cin, line); cout << "$" << line << endl; stringstream ss(line); ss >> cmd; if (cmd == "end") { break; } else if (cmd == "init") { ss >> value; v = Array(value); }
     Então para que declarou `v` fora do loop se a cada iteração está destruindo `v` ao identificar `value` --- na linha 22 --- exatamente como eu disse para fazer?
     
    Apenas apague aquela linha.
     
    A classe Array
     
    Imagino que precise mesmo disso, como um exercício ou um teste, já que C++ tem a classe `array` disponível, bem similar. E vários outros containers.
     
    Sobre essa implementação
     
    private: int capacity; // capacidade total do Array int* ptr; // ponteiro para o array de inteiros  
    Isso provavelmente deveria ser implementado usando unique_ptr<int[]> desde 2010 mas não vou colocar no exemplo porque imagino que precise da construção como escreveu.
     
    public: Array(int capacity) { // inicializando this->capacity com capacity this->capacity = capacity; // criando memória dinamicamente para this->ptr com tamanho // capacity this->ptr = new (nothrow) int[capacity]; if (ptr == nullptr) { cout << "não foi possível alocar memoria" << endl; } // o vetor é inicializado com zeros for (int i = 0; i < capacity; i++) { this->ptr[i] = 0; } }  
    Implemente o construtor padrão ou invalide o mesmo --- =delete --- para deixar claro pata você e quem ler seu programa que sabe o que está acontecendo.
     
    // inicializando this->capacity com capacity this->capacity = capacity;
    Evite esse tipo de comentário. É óbvio o que está fazendo.
     
    E C++ não é java. Não precisa escrever esses this toda hora. Prefira o simples, algo como
     
    Array::Array(int capacity) : capacity(capacity) { ptr = new (nothrow) int[capacity]; if (ptr == nullptr) { cerr << "não foi possível alocar memoria" << endl; terminate(); } for (int i = 0; i < capacity; i++) ptr[i] = 0; }  
    Não escreva na tela --- cout --- em um construtor . Isso pode simplesmente impedir o uso de sua classe em outros casos. Se achar que precisa MESMO escrever use cerr e não cout. E se for algo realmente sério chame terminate() e aborte o programa e pronto.
    Pode colocar um limite interno a essa capacidade e se passar disso cancelar ou limitar a esse valor. E se não conseguir alocar um valor suposto razoável o computador deve estar numa situação tão instável que pode ser melhor cancelar mesmo.
     
    // o vetor é inicializado com zeros for (int i = 0; i < capacity; i++) { this->ptr[i] = 0; }
    Mesmo sem o comentário dá pra ler que o vetor será inicializado com zeros. E não precisa dessas chaves nem do this. Veja o exemplo acima.
     
    // como seu Array tem atritutos do tipo ponteiros, você precisa // criar um construtor de cópia e um operador de atribuição ou terá // erros do tipo double-free // O operador de atribuição será invocado quando você fizer um Array // receber outro Exemplo: Array vec(4); vec = Array(6); nesse ponto, // os atributos de this já foram inicializados, mas você precisa // alterá-los para copiar os valores de other  
    Pois é. Note o segundo exemplo:
    vec = Array(6);
     Array(6) é um r-value e vai ser copiado a toa. Por essa razão ao implementar uma classe dessa deve escrever TAMBÉM o move constructor e o move assignment porque não há razão para copiar a classe toda. E nesse caso e o compilador não vai conseguir perceber isso. No seu código basta copiar os ponteiros e invalidar a origem. Veja no exemplo ao final.
     
    // se this->ptr não for nulo, devolva a memória com delete[] if (this->ptr == nullptr) { delete[] this->ptr; }  
    Algo errado aqui... Acho que inverteu a condição.  E não precisa do this nem das chaves.
     
    Prefira algo assim
     
    ~Array() { delete this->ptr; this->ptr = nullptr; }
    Não precisa desses this. E o delete está errado: deve usar delete [].
     
    // getter int getCapacity() { return this->capacity; }  
    Todos os containers implementam size() para retornar um tamanho. Talvez não acha razão para reinventar isso. E não precisa do this e não deve retornar um int. Prefira algo sem sinal. Algo como
     
    size_t Array::size() { return capacity; }  
    Sobre esse operador
     
    // esse é o operador de igualdade sobrecarregado // essa função determina se os dois Arrays são iguais e devolve // true, caso contrário devolve false bool operator==(const Array& other) { // checa se this->capacity é diferente de other.capacity if (this->capacity != other.capacity) { return false; } // checa se this->ptr tem os mesmos elementos que other.ptr for (int i = 0; i < this->capacity; i++) { if (this->ptr[i] != other.ptr[i]) { return false; } } return true; }  
    Pois é:
     
    está claro que a implementação de == retorna bool e esse comentário não acrescenta nada. Não precisa dessas chaves todas e desses this. Prefira o simples e clássico
     
    bool Array::operator==(const Array& other) { if (capacity != other.capacity) return false; for (int i = 0; i < capacity; i++) if (ptr[i] != other.ptr[i]) return false; return true; }  
    Sobre a redefinição de <<
     
    // Esse é o toString do C++ // tudo que enviar para out, é como se estivesse enviando // para saída padrão basta entender o funcionamento friend ostream& operator<<(ostream& out, const Array& array) { out << "[ "; for (int i = 0; i < array.capacity; ++i) out << array.ptr[i] << " "; out << "]"; return out; }  
    Não, esse não é o operador toString do C++.
     
    toStream talvez? Imagino que pretendia escrever
     
    cout << Array(12);
    como um WriteLn(toString() ) de C++. Mas é bem diferente. Essa redefinição retorna uma referência a stream e não uma string.
     
    E porque não mostrar o valor de capacity?
    Vai deixar para o cara contar um por um na saída? E se forem centenas?

    Prefira
    `
    ostream& operator<<(ostream& out, const Array& array) { out << "(" << array.capacity << ") [ "; for (int i = 0; i < array.capacity; ++i) out << array.ptr[i] << " "; out << "]\n"; return out; }  
    que deve mostrar algo assim
     
    (6) [ 0 0 0 0 0 0 ]  
    para este enorme programa
     
    #include "array.h" int main(void) { std::cout << Array(6); return 0; }  
     
    UM EXEMPLO COMPLETO
     
    A saída 
     
    (6) [ 0 0 0 0 0 0 ] Array destructor cria 'v' copia para 'outro' copy constructor assignment operator mostra 'outro' (5) [ 0 0 0 0 0 ] cria 'um' 'um' agora tem 3 elementos mostra 'um' (3) [ 0 0 0 ] move algo para 'um' move assignment Array destructor 'um' agora tem 6 elementos (6) [ 0 0 0 0 0 42 ] vai encerrar: destroi todos Array destructor Array destructor Array destructor  
    Desse programa
     
    #include "array.h" int main(void) { { std::cout << Array(6); } cout << "cria 'v'\n"; Array v(5); cout << "copia para 'outro'\n"; auto outro = v; cout << "mostra 'outro'\n"; cout << outro; cout << "cria 'um'\n"; auto um = Array(3); cout << "'um' agora tem " << um.size() << " elementos\n"; cout << "mostra 'um'\n"; cout << um; cout << "move algo para 'um'\n"; um = Array(6); um[5] = 42; // testa o operador cout << "'um' agora tem " << um.size() << " elementos\n"; cout << um; cout << "vai encerrar: destroi todos\n"; return 0; }  
    E assim acho que pode acompanhar a execução dos métodos todos.
     
    A classe Array
     
    Prefira a classe assim, sem implementação porque pode ver muito melhor o que é a classe sem ter que seguir telas e telas de código para ver um conjunto simples como esse
     
    #include <iostream> using namespace std; class Array { public: Array(int capacity); Array() = delete; Array(const Array&); // copy Array(const Array&&) noexcept; // move ~Array(); public: const Array& operator=(const Array&); // copy Array& operator=(Array&&) noexcept; // move bool operator==(const Array&); bool operator!=(const Array&); int& operator[](int); size_t size(); friend ostream& operator<<(ostream& out, const Array& array); private: int capacity; int* ptr; // o array };  
    Uma implementação de Array
     
    #include "Array.h" Array::Array(int capacity) : capacity(capacity) { ptr = new (nothrow) int[capacity]; if (ptr == nullptr) { cerr << "não foi possível alocar memoria" << endl; terminate(); } for (auto i = 0; i < capacity; i++) ptr[i] = 0; } const Array& Array::operator=(const Array& other) { cerr << "assignment operator\n"; if (&other == this) return *this; capacity = other.capacity; if (ptr != nullptr) delete[] ptr; ptr = new (nothrow) int[other.capacity]; if (ptr == nullptr) { cerr << "não foi possível alocar memoria" << endl; terminate(); } for (auto i = 0; i < capacity; i++) ptr[i] = other.ptr[i]; return *this; } Array& Array::operator=(Array&& other) noexcept { cerr << "move assignment\n"; delete[] ptr; capacity = other.capacity; ptr = other.ptr; other.ptr = nullptr; return *this; } Array::Array(const Array& other) { cerr << "copy constructor\n"; *this = other; } Array::Array(const Array&& other) noexcept { cerr << "move constructor\n"; delete[] ptr; ptr = other.ptr; capacity = other.capacity; } Array::~Array() { cerr << "Array destructor\n"; delete [] ptr; ptr = nullptr; } size_t Array::size() { return capacity; } bool Array::operator==(const Array& other) { if (capacity != other.capacity) return false; for (auto i = 0; i < capacity; i++) if (ptr[i] != other.ptr[i]) return false; return true; } bool Array::operator!=(const Array& other) { return not (*this == other); } int& Array::operator[](int index) { return ptr[index]; } // fim dos metodos da classe // // esse poderia estar em outro lugar // ja que não e um metodo da classe ostream& operator<<(ostream& out, const Array& array) { out << "(" << array.capacity << ") [ "; for (auto i = 0; i < array.capacity; ++i) out << array.ptr[i] << " "; out << "]\n"; return out; }  
    Sugiro rodar isso em sua máquina e comparar. Esse é o modo comum de escrever essas coisas.
     
    Note que o uso de new e delete ou new[] e delete[] é absolutamente desencorajado em C++ há pelo menos uma década.
     
     
  8. O post de arfneto em Meu primeiro tópico em C C# e C++ foi marcado como solução   
    C
     
    #include <stdio.h> int main(void) { puts("Feliz Natal para todos!"); }  
    C#
     
    using System; namespace Natal { class Program { static void Main(string[] args) { Console.WriteLine("Feliz Natal para todos!"); } } }  
    C++
     
    #include <iostream> int main(void){ std::cout << "Feliz Natal para todos!"; }  
  9. O post de arfneto em Cadastro de informações? Sincronização e salvamento? foi marcado como solução   
    No banco de dados você vai criar.... um banco de dados para essas pessoas, com as tabelas com as informações. O banco de dados atende via um endereço IP, que pode ser o de sua própria máquina, e uma porta que depende do banco de dados e da configuração. São apenas números. Como um nome de arquivo. 
    Você --- seu programa --- em qualquer linguagem se conecta com o banco de dados e acessa as informações. Não existe esse lance de nuvem, é transparente. Como não existe internet. 
     
    Apenas um endereço. Se seu banco de dados estiver na Polonia o endereço IP dele vai resolver isso. Por exemplo o SQL Server da Microsoft é muito usado. A porta padrão para esse é 1433. Se você usar 127.0.0.1:1433 como endereço e sua máquina estiver rodando SQL Server vai funcionar. Se estiver no Google Cloud ou no Azure ou na AWS vai trocar o endereço apenas.
     
    Note que muitas vezes a plataforma faz isso por você e os endereços nem são vistos. Muito de programação hoje é apenas preencher formulários com endereços e eventos e tal.
     
     
  10. O post de arfneto em Como colocar em ordem alfabetica a listagem de produtos foi marcado como solução   
    nunca use void(void).  Isso só vai te dar muito mais trabalho.
     
    Escreveu um programa C. Não precisa se limitar ao dialeto C se está programando em C++ que é muito mais expressiva.
     
    Comente o que está fazendo e porque está fazendo. Sugiro evitar esses comentários óbvios tipo "variáveis aqui", "op" é a opção....
     
     
    Em C++ não há razão para escrever assim. Está claro que tem um cadastro de produtos. Só que no programa não tem. Apenas um vetor de struct. E sem nenhum método? Não se escreve assim em C++ porque só fica mais difícil...
    C++ tem sort. Basta escrever uma função que compara dois produtos. Pode ter uma linha só....
  11. O post de arfneto em Fila só está pegando o último que entrou foi marcado como solução   
    Talvez seu professor tenha feito assim de propósito com algum outro plano. Mas está muito ruim, como eu disse.
     
    Entre outras coisas
    typedef não é usado em C++. Não há razão. as tais funções em C++ fazem parte da struct. Este é o princípio básico de C++:  a noção de classe, objeto não use void. é um desperdício ou um erro não escreva um programa interativo . NUNCA. Apenas coloque isso ao final. depois de tudo testado não se preocupe com detalhes tipo cor, limpar a tela, fontes. Escreva o objetivo de seu programa. Implemente uma fila de alunos um cout de oito linhas é muito mais esperto que 8 cout de uma linha. E se vai apenas mostrar valores use puts(). Muito mais esperto e rápido. não use system(). Nunca.  não use gets(). NUNCA. Isso nem existe mais em alguns compiladores. escreva em torno dos dados. Um container é um container. TEM que ter isso no código. C ou C++ ou java ou ou COBOL... use os #define antes dos #include  
    EXEMPLO, em C++
     
    Essa é a saída do exemplo, um programa mínimo só pra você ter um exemplo de uma maneira comum de escrever isso nessa linguagem.
     
    Acho que vai perceber que é muito mais simples.
     
    Fila: "Unica" tem 0 alunos Fila: "Unica" tem 8 alunos Nome..., RA #1 Nome..., RA #2 Nome..., RA #3 Nome..., RA #4 Nome..., RA #5 Nome..., RA #6 Nome..., RA #7 Nome..., RA #8 Fila "Unica"Cheia Fila "Anonima" Vazia Atendeu o cara de RA #1 da fila "Unica" Atendeu o cara de RA #2 da fila "Unica" Atendeu o cara de RA #3 da fila "Unica" Atendeu o cara de RA #4 da fila "Unica" Atendeu o cara de RA #5 da fila "Unica" Atendeu o cara de RA #6 da fila "Unica" Atendeu o cara de RA #7 da fila "Unica" Atendeu o cara de RA #8 da fila "Unica" Fila: "Unica" tem 0 alunos Apagando a fila "Anonima" Apagando a fila "Unica"  
    Eis o programa
     
    int main(void) { Fila unica("Unica",8); unica.imprime(); // vazia ainda int seq = 1; while (unica.enfileira(Aluno(seq++, "Nome...")) > 0); unica.imprime(); // mostra a fila agora // fila cheia? if (unica.cheia()) cout << "Fila \"" << unica.nome << "\"Cheia\n"; else cout << "Fila \"" << unica.nome << "\" não esta cheia\n"; // fila vazia? Fila outra; if (outra.vazia()) cout << "Fila \"" << outra.nome << "\" Vazia\n"; else cout << "Fila \"" << outra.nome << "\" não esta vazia\n"; // atende todo mundo da fila 'unica' while (not unica.vazia() ) unica.atende(); unica.imprime(); // mostra a fila agora return 0; }  
    O programa cria 2 filas, uma chamada unica e outra chamada outra. Sim, foi pobre a nomenclatura
     
    Um loop enche a fila unica até dar erro. Vai dar erro, claro, quando não couber mais gente. Como cada fila tem um nome e uma capacidade nada de especial acontece. 
     
    A fila é mostrada antes e depois, e tem um teste de outras funções. No final atende todo mundo que estava na primeira fila e encerra o programa.
     
    Eis o código "todo"
     
    // https:www.clubedohardware.com.br/forums/topic/ // 1578391-fila-s%C3%B3-est%C3%A1-pegando-o- //%C3%BAltimo-que-entrou/#comment-8325416 #define LIMITE 10 #include <iostream> #include <queue> using namespace std; struct Aluno { int RA; string nome; void imprime(); Aluno(int ra, string nome) : RA(ra), nome(nome){}; Aluno() : Aluno(0, ""){}; // padrão }; struct Fila { unsigned limite; // maior tamanho aceito string nome; // para distinguir as filas queue<Aluno> fila; bool vazia() { return fila.empty(); }; bool cheia() { return fila.size() == limite; }; int enfileira(Aluno x) { if (fila.size() >= limite) return -1; fila.push(x); return (int) fila.size(); }; void desenfileira() { fila.pop(); }; void imprime(); // codigo abaixo Aluno atende(); // não tem as chaves... Fila(string n, int lim) : nome(n), limite(lim) { if (lim > LIMITE) limite = LIMITE; }; Fila() : Fila("Anonima",LIMITE){}; // fila padrão sem nome ~Fila() { cout << "Apagando a fila \"" << Fila::nome << "\"\n"; }; }; int main(void) { Fila unica("Unica",8); unica.imprime(); // vazia ainda int seq = 1; while (unica.enfileira(Aluno(seq++, "Nome...")) > 0); unica.imprime(); // mostra a fila agora // fila cheia? if (unica.cheia()) cout << "Fila \"" << unica.nome << "\"Cheia\n"; else cout << "Fila \"" << unica.nome << "\" não esta cheia\n"; // fila vazia? Fila outra; if (outra.vazia()) cout << "Fila \"" << outra.nome << "\" Vazia\n"; else cout << "Fila \"" << outra.nome << "\" não esta vazia\n"; // atende todo mundo da fila 'unica' while (not unica.vazia() ) unica.atende(); unica.imprime(); // mostra a fila agora return 0; } void Fila::imprime() { // Quantos tem? cout << "Fila: \"" << nome << "\" tem " << fila.size() << " alunos\n"; // agora os alunos for (int i = 0; i < fila.size(); i+=1) { Aluno a = fila.front(); fila.pop(); // tira da fila Fila::fila.push(a); // poe de volta no fim a.imprime(); // mostra esse } } Aluno Fila::atende() { Aluno prim = fila.front(); // salva o primeiro fila.pop(); // tira da fila cout << "Atendeu o cara de RA #" << prim.RA << " da fila " << "\"" << nome << "\"\n"; return prim; // retorna } void Aluno::imprime() { cout << nome << ", RA #" << RA << "\n"; };  
    Veja que algumas funções tem só um linha de código.
     
    Há maneiras diferentes e mais elegantes de escrever isso. Sugiro que se concentre em ver a diferença entre as duas linguagens. E entenda como em C++ as abstrações são muito mais simples.
     
     
     
     
     
     
  12. O post de arfneto em c/c++ struct string não é exibida foi marcado como solução   
    Não há razão para usar typedef em C++
     
     
    Isso está construindo um Carro. Use um construtor. É o simples. Muito mais simples.
     
     
    não use void e uma função sem argumentos. Passe parâmetros. Retorne algo.  exibe() vai exibir o que? passe o argumento com o endereço ou a referência do Carro em questão.
  13. O post de arfneto em Destruir uma struct, é possível? foi marcado como solução   
    Um livro é uma boa opção, se for um bom livro  
    Mas estranho dizer que ~não acha muita coisa~ na internet. O que está procurando? Como está procurando?
     
     
    Podia ter postado o tal exercício.  
     
     
    Está re-criando um vetor. C++ tem vetores para uso em <vector>, mas em C uma struct assim serviria bem. 
     
    Seu programa não está muito bom ainda. E tem um erro importante. E está programando praticamente em C e não em C++. E é muito mais vantagem programar em C++ essas coisas.
     
    De volta ao programa
     
    struct Vetor { int capacidade; int tam; int* data; }; Vetor* Vetor_criar(int capacidade) { Vetor* data = new Vetor[capacidade]; tam = 0; this->capacidade = capacidade; return data; }  
    Aposto que pretendia alocar algo de um certo tamanho em data... Pense nisso. Esse é o vetor que quer criar. E aí a nomenclatura fica realmente confusa.
     
    Provavelmente você quer alocar um vetor de int com uma certa capacidade e colocar dentro da struct. E não alocar um vetor da strut que tem um vetor dentro. E esse é o erro. Alocou o Vetor, mas esse não é o vetor que quer  Seu vetor é data[] dentro da struct Vetor
     
    Em C++, mas em C  
     
    Isso é o que imagino que queria fazer. É criado um vetor de 300 caras e destruído em seguida. Só coloquei um valor no último item como exemplo. Não vai usar assim porque vai usar tam para controlar o tamanho:
     
    #include <iostream> using namespace std; struct Vetor { int capacidade; int tam; int* data; }; Vetor* Vetor_criar(int capacidade) { Vetor* novo = new Vetor; novo->tam = 0; novo->capacidade = capacidade; novo->data = new int[capacidade]; return novo; } Vetor* Vetor_destroi(Vetor* vetor) { // destroi ao contrario delete[] vetor->data; delete vetor; return nullptr; } int main(void) { Vetor* um = Vetor_criar(300); um->data[299] = 42; cout << "Ultimo valor do vetor: " << um->data[299] << "\n"; um = Vetor_destroi(um); return 0; }  
    É esperto retornar nullptr de Vetor_destroi() porque assim pode invalidar o ponteiro na mesma linha e nunca vai ter um ponteiro inválido e vivo em seu programa.
     
    A saída
     
    Ultimo valor do vetor: 42  
    O normal em C++
     
    #include <iostream> using namespace std; struct Vetor { int capacidade; int tam; int* data; Vetor(int c) : tam(0), capacidade(c) { data = new int[c]; } ~Vetor() { delete[] data; } }; int main(void) { Vetor* um = new Vetor(300); um->data[299] = 42; cout << "Ultimo valor do vetor: " << um->data[299] << "\n"; return 0; }  
    Compare os dois programas. A saída é a mesma. O segundo é mais certo.
     
     
     
     
     
     
     
  14. O post de arfneto em Como funciona um wallpaper engine? foi marcado como solução   
    É uma chamada de sistema, mais uma biblioteca de mídia e um timer.
     
     
    cessar quer dizer terminar. 
     
     
  15. O post de arfneto em Entender um código pequeno c++ (recursão) foi marcado como solução   
    1. Isso é void. Apenas retorna ao chamador. É a definição.
     
    2. Você entendeu o que é esse lance da torre de Hanoi?
     
    A saída do programa você postou. Aquelas linhas são o resultado do cout, a unica saida do programa.
     
    A razão de usar assim é porque para trocar os discos de um pino para outro é a mesma coisa se já tiver uma disco a menos, desde que não coloque um maior sobre outro, e assim é mais simples de ler e implementar se simplesmente chamar a mesma função de novo especificando um disco a menos
  16. O post de arfneto em Entender um código pequeno c++ (recursão) foi marcado como solução   
    1. Isso é void. Apenas retorna ao chamador. É a definição.
     
    2. Você entendeu o que é esse lance da torre de Hanoi?
     
    A saída do programa você postou. Aquelas linhas são o resultado do cout, a unica saida do programa.
     
    A razão de usar assim é porque para trocar os discos de um pino para outro é a mesma coisa se já tiver uma disco a menos, desde que não coloque um maior sobre outro, e assim é mais simples de ler e implementar se simplesmente chamar a mesma função de novo especificando um disco a menos
  17. O post de arfneto em Entender um código pequeno c++ (recursão) foi marcado como solução   
    1. Isso é void. Apenas retorna ao chamador. É a definição.
     
    2. Você entendeu o que é esse lance da torre de Hanoi?
     
    A saída do programa você postou. Aquelas linhas são o resultado do cout, a unica saida do programa.
     
    A razão de usar assim é porque para trocar os discos de um pino para outro é a mesma coisa se já tiver uma disco a menos, desde que não coloque um maior sobre outro, e assim é mais simples de ler e implementar se simplesmente chamar a mesma função de novo especificando um disco a menos
  18. O post de arfneto em Lista em C, não estou conseguindo fazer essas listas em C. foi marcado como solução   
    Os 3 exercícios são a mesma coisa, desde que perceba isso antes e escreva em torno dos dados
     

     
    Nesse primeiro caso são 2 listas, duas vezes a mesma coisa. Os demais tem uma lista só.

    No desenho tem até as linhas em azul mostrando os tais ponteiros da lista.
     
     
    Acho que já sabe que a lista é uma coleção de coisas onde cada coisa aponta para a coisa seguinte. Se não soubesse saberia depois de ver esse desenho aí.
     
    Na hora de colocar algo na lista é claro que tem que ter um critério, e a realidade é simples: ou insere no início, ou no final ou por alguma ordem, como a ordem alfabética, a ordem de CPF, o total da compra, seja lá o que for.
     
    Nesse exemplo acima parece óbvio que é melhor inserir no final, como a noção que a gente tem de fila, porque assim fica na simples ordem de entrada e é mais fácil combinar a bebida com o acompanhamento.
     
    Escrevendo em torno dos dados
     
    Está claro que cada exercício vai ter uma lista e está claro que você deve escrever uma vez só esse lance de lista porque é para isso que serve uma lista em um programa de computador. Você escreve algo que possa usar sempre, ou não vale muito a pena escrever afinal.
     
    Uma lista tem algo dentro: nós.
     
    Veja isso
     
    typedef struct { int N; // tamanho Node* inicio; // o primeiro } Lista;  
    E já está bom. A Lista é de nós, cada um é chamado Node, o nome comum nos livros. E o total deles é N.
     
    Um node é como esses do desenho, mas só o esqueleto, sem o conteúdo. E dentro dele tem um ponteiro para o dado, ou mesmo o dado, dependendo de como preferir escrever.
     
    Uma tentativa para Node
     
    typedef struct st_no { struct st_no* prox; Dado* dado; } Node;  
    Então dado aponta para o dado, que pode ser qualquer coisa, e prox aponta para o próximo Node, igualzinho no desenho. Se prox for NULL acabou a Lista. Como no desenho.
     
    O tal st_no na declaração está lá porque tem um ponteiro dentro da estrutura para outra do mesmo tipo, e o nome Node só aparece na linha de baixo e assim não dá para escrever Node* dado antes de definir o que é Node, certo? E você não quer ficar repetido struct XXX pelo programa afora.
     
    Uma tentativa para Dado
     
    typedef struct { char item[20]; } Dado;  
    E já está bom: tem a lista de nós e cada nó aponta para um dado.
     
    Como criar uma lista? Como apagar uma lista?
     
    Para uma vida longa e tranquila, uma função pode criar a lista, outra pode apagar a lista e assim se funcionar está ok e se der m. já se sabe onde procurar. Se fizer diferente vai encher seu programa com ponteiros para início de uma e outra lista e ponteiros auxiliares e tal. Um inferno. 
     
    Claro, estamos programando estruturas de dados (listas) com tamanho dinâmico em C e tem uns ponteiros óbvios desde o enunciado... As linhas com a flecha...➡️ É muito mais simples ter ponteiros para frente e para trás na lista. Ponteiros só para um lado são um pesadelo porque... não dá para ir para o outro lado.
     
    E assim criar e apagar lista podem ser tão simples como
     
    Lista* criar(); Lista* apagar(Lista*);  
    Acho que dá pra entender não? Como criar e apagar uma lista em seguida?
     
    int main(void) { Lista* minha_lista = criar(); apagar(minha_lista); return 0; }  
     
    Mas depois de apagar a lista minha_lista se o programa continuar o ponteiro vai ficar apontando para a lista que já foi apagada e se você acha que isso é um problema pode apostar que é. Então por isso é esperto depois de apagar a lista zerar o ponteiro, antes de usar por engano e cancelar o programa.
     
    int main(void) { Lista* minha_lista = criar(); apagar(minha_lista); minha_lista = NULL; // apaga a referencia return 0; }  
    Mas isso é um porre e é mais uma coisa para lembrar então seria legal se apagar() retornasse o NULL para invalidar a referência para minha_lista na mesma linha...
     
    int main(void) { Lista* minha_lista = criar(); minha_lista = apagar(minha_lista); return 0; }  
    Aí sim. Em outras linguagens se pode até exigir que o cara use o valor que a função retorna. Em C ele pode ser ignorado e se pode escrever como na primeira versão.
     
    E como criar uma lista afinal?
     
    Lista* criar() { Lista* L = (Lista*)malloc(sizeof(Lista)); if (L == NULL) return NULL; L->inicio = NULL; L->N = 0; return L; };  
    Não é só isso? aloca uma lista com tamanho zero e apontando para NULL como no desenho...

    O simples. Dentro da lista está o tamanho da lista, dentro da lista tem o endereço de início da lista. Como eu sugeri antes seria claro melhor ter também o ponteiro para o último nó porque assim facilita muito percorrer a lista.
     
    E como seria apagar uma lista? 
     
    Não seria equivalente a apagar todos os nós e depois apagar a própria lista?  Sim. É só isso.
     
    Lista* apagar(Lista* uma) { if (uma->N == 0) { // esta vazia free(uma); return NULL; }; // a lista tem pelo menos 1 cara // entao p aponta paa o segundo Node* p = uma->inicio->next; for (int i = 0; i < uma->N; i += 1) { free(uma->inicio); uma->inicio = p; // o proximo } free(uma); // apaga a lista em si return NULL; };  
    Se a lista está vazia apaga a lista em si e retorna, porque não tem dado nenhum. Se tem algum apaga os N dados. Antes de apagar o nó salva o endereço do próximo, porque depois já era. Antes de travar a porta confirme que tem a chave...  
     
     
    Sim, é verdade, @Lucca Rodriguesmas não é muito bom assim. Node é algo interno a Lista. O que se quer é inserir um Dado na Lista. Prefira sempre
     
    int inserir(Dado* d, Lista* l)  
    Porque pode usar isso para qualquer dado. Só aqui tem 3 exercícios por exemplo.
     
    @patopaloro sugiro que escreva nessa linha. É a maneira comum de fazer isso em qualquer linguagem. E é comum por alguma razão. 
     
    Veja no caso do exercício 1: você vai em um loop inserir as bebidas chamando inserir() em uma Lista de bebidas e outra Lista de acompanhamentos. Depois é só listar os N caras das duas listas que claro vão ter o mesmo tamanho.
     
    Um "programa" até aqui, juntando o que está acima...
     
    #include <stdio.h> #include <stdlib.h> typedef struct { char item[20]; } Dado; typedef struct st_no { struct st_no* next; Dado* dado; } Node; typedef struct { int N; // tamanho Node* inicio; } Lista; Lista* criar(); Lista* apagar(Lista*); int inserir(Dado*,Lista*); int main(void) { Lista* bebidas = criar(); Lista* comidas = criar(); apagar(bebidas); apagar(comidas); return 0; } Lista* apagar(Lista* uma) { if (uma->N == 0) { // esta vazia free(uma); return NULL; }; // a lista tem pelo menos 1 cara // entao p aponta paa o segundo Node* p = uma->inicio->next; for (int i = 0; i < uma->N; i += 1) { free(uma->inicio); uma->inicio = p; // o proximo } free(uma); // apaga a lista em si return NULL; }; Lista* criar() { Lista* L = (Lista*)malloc(sizeof(Lista)); if (L == NULL) return NULL; L->inicio = NULL; L->N = 0; return L; }; int inserir(Dado* d, Lista* L) { return 0; }  
    É claro que vai usar o mesmo código nos 3 programas. Só muda a definição de dado. Por isso é importante deixar os dados separados da estrutura. No fundo se cria um arquivo .h com as funções de lista e usa um #include em todos os programas. Mas deixa a definição de Dado de fora para poder trocar em cada programa  
     
     
     
  19. O post de arfneto em Lista em C, não estou conseguindo fazer essas listas em C. foi marcado como solução   
    Os 3 exercícios são a mesma coisa, desde que perceba isso antes e escreva em torno dos dados
     

     
    Nesse primeiro caso são 2 listas, duas vezes a mesma coisa. Os demais tem uma lista só.

    No desenho tem até as linhas em azul mostrando os tais ponteiros da lista.
     
     
    Acho que já sabe que a lista é uma coleção de coisas onde cada coisa aponta para a coisa seguinte. Se não soubesse saberia depois de ver esse desenho aí.
     
    Na hora de colocar algo na lista é claro que tem que ter um critério, e a realidade é simples: ou insere no início, ou no final ou por alguma ordem, como a ordem alfabética, a ordem de CPF, o total da compra, seja lá o que for.
     
    Nesse exemplo acima parece óbvio que é melhor inserir no final, como a noção que a gente tem de fila, porque assim fica na simples ordem de entrada e é mais fácil combinar a bebida com o acompanhamento.
     
    Escrevendo em torno dos dados
     
    Está claro que cada exercício vai ter uma lista e está claro que você deve escrever uma vez só esse lance de lista porque é para isso que serve uma lista em um programa de computador. Você escreve algo que possa usar sempre, ou não vale muito a pena escrever afinal.
     
    Uma lista tem algo dentro: nós.
     
    Veja isso
     
    typedef struct { int N; // tamanho Node* inicio; // o primeiro } Lista;  
    E já está bom. A Lista é de nós, cada um é chamado Node, o nome comum nos livros. E o total deles é N.
     
    Um node é como esses do desenho, mas só o esqueleto, sem o conteúdo. E dentro dele tem um ponteiro para o dado, ou mesmo o dado, dependendo de como preferir escrever.
     
    Uma tentativa para Node
     
    typedef struct st_no { struct st_no* prox; Dado* dado; } Node;  
    Então dado aponta para o dado, que pode ser qualquer coisa, e prox aponta para o próximo Node, igualzinho no desenho. Se prox for NULL acabou a Lista. Como no desenho.
     
    O tal st_no na declaração está lá porque tem um ponteiro dentro da estrutura para outra do mesmo tipo, e o nome Node só aparece na linha de baixo e assim não dá para escrever Node* dado antes de definir o que é Node, certo? E você não quer ficar repetido struct XXX pelo programa afora.
     
    Uma tentativa para Dado
     
    typedef struct { char item[20]; } Dado;  
    E já está bom: tem a lista de nós e cada nó aponta para um dado.
     
    Como criar uma lista? Como apagar uma lista?
     
    Para uma vida longa e tranquila, uma função pode criar a lista, outra pode apagar a lista e assim se funcionar está ok e se der m. já se sabe onde procurar. Se fizer diferente vai encher seu programa com ponteiros para início de uma e outra lista e ponteiros auxiliares e tal. Um inferno. 
     
    Claro, estamos programando estruturas de dados (listas) com tamanho dinâmico em C e tem uns ponteiros óbvios desde o enunciado... As linhas com a flecha...➡️ É muito mais simples ter ponteiros para frente e para trás na lista. Ponteiros só para um lado são um pesadelo porque... não dá para ir para o outro lado.
     
    E assim criar e apagar lista podem ser tão simples como
     
    Lista* criar(); Lista* apagar(Lista*);  
    Acho que dá pra entender não? Como criar e apagar uma lista em seguida?
     
    int main(void) { Lista* minha_lista = criar(); apagar(minha_lista); return 0; }  
     
    Mas depois de apagar a lista minha_lista se o programa continuar o ponteiro vai ficar apontando para a lista que já foi apagada e se você acha que isso é um problema pode apostar que é. Então por isso é esperto depois de apagar a lista zerar o ponteiro, antes de usar por engano e cancelar o programa.
     
    int main(void) { Lista* minha_lista = criar(); apagar(minha_lista); minha_lista = NULL; // apaga a referencia return 0; }  
    Mas isso é um porre e é mais uma coisa para lembrar então seria legal se apagar() retornasse o NULL para invalidar a referência para minha_lista na mesma linha...
     
    int main(void) { Lista* minha_lista = criar(); minha_lista = apagar(minha_lista); return 0; }  
    Aí sim. Em outras linguagens se pode até exigir que o cara use o valor que a função retorna. Em C ele pode ser ignorado e se pode escrever como na primeira versão.
     
    E como criar uma lista afinal?
     
    Lista* criar() { Lista* L = (Lista*)malloc(sizeof(Lista)); if (L == NULL) return NULL; L->inicio = NULL; L->N = 0; return L; };  
    Não é só isso? aloca uma lista com tamanho zero e apontando para NULL como no desenho...

    O simples. Dentro da lista está o tamanho da lista, dentro da lista tem o endereço de início da lista. Como eu sugeri antes seria claro melhor ter também o ponteiro para o último nó porque assim facilita muito percorrer a lista.
     
    E como seria apagar uma lista? 
     
    Não seria equivalente a apagar todos os nós e depois apagar a própria lista?  Sim. É só isso.
     
    Lista* apagar(Lista* uma) { if (uma->N == 0) { // esta vazia free(uma); return NULL; }; // a lista tem pelo menos 1 cara // entao p aponta paa o segundo Node* p = uma->inicio->next; for (int i = 0; i < uma->N; i += 1) { free(uma->inicio); uma->inicio = p; // o proximo } free(uma); // apaga a lista em si return NULL; };  
    Se a lista está vazia apaga a lista em si e retorna, porque não tem dado nenhum. Se tem algum apaga os N dados. Antes de apagar o nó salva o endereço do próximo, porque depois já era. Antes de travar a porta confirme que tem a chave...  
     
     
    Sim, é verdade, @Lucca Rodriguesmas não é muito bom assim. Node é algo interno a Lista. O que se quer é inserir um Dado na Lista. Prefira sempre
     
    int inserir(Dado* d, Lista* l)  
    Porque pode usar isso para qualquer dado. Só aqui tem 3 exercícios por exemplo.
     
    @patopaloro sugiro que escreva nessa linha. É a maneira comum de fazer isso em qualquer linguagem. E é comum por alguma razão. 
     
    Veja no caso do exercício 1: você vai em um loop inserir as bebidas chamando inserir() em uma Lista de bebidas e outra Lista de acompanhamentos. Depois é só listar os N caras das duas listas que claro vão ter o mesmo tamanho.
     
    Um "programa" até aqui, juntando o que está acima...
     
    #include <stdio.h> #include <stdlib.h> typedef struct { char item[20]; } Dado; typedef struct st_no { struct st_no* next; Dado* dado; } Node; typedef struct { int N; // tamanho Node* inicio; } Lista; Lista* criar(); Lista* apagar(Lista*); int inserir(Dado*,Lista*); int main(void) { Lista* bebidas = criar(); Lista* comidas = criar(); apagar(bebidas); apagar(comidas); return 0; } Lista* apagar(Lista* uma) { if (uma->N == 0) { // esta vazia free(uma); return NULL; }; // a lista tem pelo menos 1 cara // entao p aponta paa o segundo Node* p = uma->inicio->next; for (int i = 0; i < uma->N; i += 1) { free(uma->inicio); uma->inicio = p; // o proximo } free(uma); // apaga a lista em si return NULL; }; Lista* criar() { Lista* L = (Lista*)malloc(sizeof(Lista)); if (L == NULL) return NULL; L->inicio = NULL; L->N = 0; return L; }; int inserir(Dado* d, Lista* L) { return 0; }  
    É claro que vai usar o mesmo código nos 3 programas. Só muda a definição de dado. Por isso é importante deixar os dados separados da estrutura. No fundo se cria um arquivo .h com as funções de lista e usa um #include em todos os programas. Mas deixa a definição de Dado de fora para poder trocar em cada programa  
     
     
     
  20. O post de arfneto em Função que recebe um inteiro como parâmetro foi marcado como solução   
    for(int i=0;i=N;i++){ s=s+((i*i)+1)/(i+3); }  
    Esse trecho é problemático. 
     
    Como colocou errado i=N na condição só vai sair do loop quando N for zero. Use i<=N. Em C 0 é falso. Qualquer outro valor é verdadeiro. o numerador é int e o denominador é int então antes de somar em s a divisão vai ser feita e gerar um valor inteiro. Converta um dos dois para float. Veja o exemplo abaixo. TESTE sempre o retorno de scanf(). Como está aprendendo ao menos no início dos testes mostre na tela os valores lidos. É muito melhor saber antes. E na série claro que deve mostrar os valores das parcelas. Se tivesse feito isso desde o início saberia do problema... Não precisa de chaves em comandos de uma linha só. Só fica mais difícil de ler. Se o programa só faz isso e você sabe o que, então passe N na linha de comando. Quando está testando use um loop para mostrar alguns valores. É bem melhor que ficar rodando o programa várias vezes. main() deve ser SEMPRE a primeira função de seu programa.  Exemplo
     
    #include<stdio.h> float soma(int); int main(void) { for ( int a=0; a<5; a+=1) printf("Soma = %.4f\n",soma(a)); return 0; } float soma(int N) { float s=0.f; printf("\n==> Calculando a soma para N = %d\n", N); for(int i=0;i<=N;i+=1) { float parcela = (i*i+1) / (float)(i+3); printf( " i = %d, parcela = %.4f\n", i, parcela ); s += parcela; } return s; };  
    Que mostra
     
    ==> Calculando a soma para N = 0 i = 0, parcela = 0.3333 Soma = 0.3333 ==> Calculando a soma para N = 1 i = 0, parcela = 0.3333 i = 1, parcela = 0.5000 Soma = 0.8333 ==> Calculando a soma para N = 2 i = 0, parcela = 0.3333 i = 1, parcela = 0.5000 i = 2, parcela = 1.0000 Soma = 1.8333 ==> Calculando a soma para N = 3 i = 0, parcela = 0.3333 i = 1, parcela = 0.5000 i = 2, parcela = 1.0000 i = 3, parcela = 1.6667 Soma = 3.5000 ==> Calculando a soma para N = 4 i = 0, parcela = 0.3333 i = 1, parcela = 0.5000 i = 2, parcela = 1.0000 i = 3, parcela = 1.6667 i = 4, parcela = 2.4286 Soma = 5.9286  
    E já tira umas dúvidas desde o início. Só DEPOIS você escreve algo como
     
    #include<stdio.h> float soma(int); int main(void) { int a; float total=0; printf("Digite um numero: "); if ( 1 != scanf("%d",&a) ) return -1; printf("Soma = %.4f\n",soma(a)); return 0; } float soma(int N) { float s=0.f; for(int i=0; i<=N; s+= (i*i+1) / (float)(i+3), i+=1); return s; };  
    Apagando os printf() e os testes passo a passo...
    Programação defensiva.  
  21. O post de arfneto em Usando ponteiros e alocação dinâmica, mas deu o erro "signal: segmentation... foi marcado como solução   
    Não consigo entender o que iria funcionar aqui. Não entendi o propósito do programa e não há razão para se programar assim, em C ou C++.
     
    cout << "\nFunciona !\n";  
    Isso só mostraria que o programa não cancelou ainda. E que compilou ok. Não serve como um teste.
     
    O que é ponteiro?
     
    delete[] * ponteiro;  
    Há muitos anos, desde C++11 não há razão para escrever assim em C++. E mesmo em C++98 esse delete deveria estar em um destrutor e nunca solto pelo programa.
     
    int main() { int** v; int x = Quest(); int** p; criar(p, x); cout << "\nFunciona !\n"; delete[] * ponteiro; }  
    já perguntei sobre ponteiro... e v seria o que? não foi alocado e jamais foi usado.
     
    E Quest() serve apenas para ler um número então o que muda no programa em relação a escrever
     
    int x = 42;
    e seguir com seja lá o que for que o programa faz?
     
    Ao que parece cria()
     
    void criar(int** p, int x) { *p = new int[x]; for (int i = 0; i < x; i++) { p[i] = new int[x]; } }  
    apenas cria um vetor de tamanho x, o valor que foi lido por Quest(). Só que depois aloca um vetor de x int para cada posição de *p. Só que *p é int[] e não um ponteiro. Uma confusão. 
     
    E acho que está mesmo errado.
     
    E ainda retorna void, um outro erro nesse caso.
     
    O que pretende criar com cria() ? porque retorna void? Porque está usando C++ e escrevendo C?
     
    Não está claro que cria() é um construtor????
     
    Se  cria(int**  p,  int x )  deveria criar em p um vetor de x vetores para int
     
    Escrever assim só complica as coisas. Muito. Porque void se vai criar alocando? Não retorne void nunca. Isso se eu entendi o que quer que "funcione" aqui. Vou te mostrar dois exemplos considerando isso. Se não for assim acho que não vai ter dificuldade em adaptar para seu caso. Ou perguntar de novo.
     
    Pode escrever 
     
    int** criar(int x);  
    E usar 
     
    int** p = criar(x);  
    Que é bem mais simples eu acho.
     
    Mas entenda que
     
     
    e só de ver isso não dá pra saber que *p é um ponteiro para um int ou um vetor.
     
     
    Então se quer criar um vetor de vetores para int de tamanho x precisa de fato criar isso. Imagine que  vai criar um vetor de x vetores para vetores de x int. Precisa saber se de fato criou isso. Não basta escrever "funciona". Eis um exemplo:
     
    Imagine então que os valores em cada vetor serão assim, para x = 4
    cria() vai retornar 4 vetores de ponteiros para int cada um desses vai ser um vetor de 4 int e eles vão valer para p[0] 0,1,2,3 para p[1] 10,11,12,13 para p[2] 20,21,22,23 para p[3] 30,31,32,33 Assim pode listar isso depois de chamar cria() e ver se deu certo porque já sabe os valores que tem que mostrar, certo? Espero que tenha dado para entender porque não basta escrever "funciona".
     
    E depois de criar tem que apagar todo mundo na ordem inversa ou seu programar pode cancelar no final, porque TEM que liberar tudo que alocou...
     
    Um exemplo em C++,  no modo C dos anos 80
     
    int** apagar(int**,int); int** criar(int x); int mostrar(int**,int);  
    O jeito comum de fazer em C, uma função cria o vetor, uma apaga e outra mostra. Quest() não é relevante aqui. Não há razão para escrever um programa interativo.
     
    Essa versão de cria() usa o exemplo acima e preenche todas as posições de todos os vetores com valores conhecidos assim pode conferir facilmente:
     
    int** criar(int x) { int** p = new int*[x]; for (int i = 0; i < x; i+=1) { p[i] = new int[x]; for ( int j = 0; j<x; j+=1 ) p[i][j] = 10*i + j; } return p; }  
    Essa versão de apagar() apaga tudo na ordem certa
     
    int** apagar(int** p, int x) { for (int i = 0; i < x; i+=1) delete[] p[i]; delete[] p; return nullptr; }  
    Note que usando apagar assim permite que se invalide o ponteiro no chamador, o que é um seguro contra esquecer que apagou e usar o ponteiro em outro lugar...
     
    Um exemplo completo
     
    #include <iostream> using namespace std; int** apagar(int**,int); int** criar(int x); int mostrar(int**,int); int main() { int x = 8; int** p = criar(x); cout << "\nFunciona! x = " << x << "\n"; int res = mostrar(p,x); cout << "mostrar() listou " << res << " elementos\n"; cout << "apagando tudo...\n"; p = apagar(p,x); return 0; } int** apagar(int** p, int x) { for (int i = 0; i < x; i+=1) delete[] p[i]; delete[] p; return nullptr; } int** criar(int x) { int** p = new int*[x]; for (int i = 0; i < x; i+=1) { p[i] = new int[x]; for ( int j = 0; j<x; j+=1 ) p[i][j] = 10*i + j; } return p; } int mostrar(int** v, int d) { int n = 0; for (int i = 0; i < d; i+=1) { cout << "[" << i << "] "; for ( int j = 0; j<d; j+=1 ) n+=1, cout << v[i][j] << " "; cout << "\n"; } cout << "\n"; return n; };  
    A saída
     
    Funciona! x = 8 [0] 0 1 2 3 4 5 6 7 [1] 10 11 12 13 14 15 16 17 [2] 20 21 22 23 24 25 26 27 [3] 30 31 32 33 34 35 36 37 [4] 40 41 42 43 44 45 46 47 [5] 50 51 52 53 54 55 56 57 [6] 60 61 62 63 64 65 66 67 [7] 70 71 72 73 74 75 76 77 Listados 64 elementos Apagando...  
    Claro que mostra() não precisava retornar nada, mas retornar o total de elementos dá mais uma segurança, já que deve ser claro x*x.

    Um modo comum de fazer isso, desta vez em C++ 2011
     
    v_int_int é a struct com os vetores de vetores de int. main() pode ser bem simples:
     
    int main(void) { v_int_int teste(8); cout << teste; };  
    E o código é o mesmo praticamente. Só que em C++ é mais fácil de escrever e ler. Redefinir << é algo comum para uma struct em C++ porque assim pode usar cout << struct e escrever como quiser sem ter que ficar formatando em toda parte ou escrever uma função, o que seria a mesma coisa só que mais difícil de ler
     
    criar() é simplesmente construir uma struct dessas. apagar() é o destrutor, com o til na frente. mostrar é o tal << e a vida segue.
     
    O exemplo completo
     
    #include <iostream> using namespace std; struct v_int_int { int x; int** p; v_int_int(int); ~v_int_int(); }; ostream& operator<<(ostream& out, v_int_int& c); int main(void) { v_int_int teste(8); cout << teste; }; v_int_int::~v_int_int() { cout << "\nApagando"; for (int i = 0; i < x; i+=1) delete[] p[i]; delete[] p; cout << "...\n"; } v_int_int::v_int_int(int tamanho) : x(tamanho) { cout << "\nFunciona! x = " << x << "\n"; p = new int*[x]; for (int i = 0; i < x; i+=1) { p[i] = new int[x]; for ( int j = 0; j<x; j+=1 ) p[i][j] = 10*i + j; } } ostream& operator<<(ostream& out, v_int_int& c) { int n = 0; for (int i = 0; i < c.x; i+=1) { out << "[" << i << "] "; for ( int j = 0; j<c.x; j+=1 ) n+=1, cout << c.p[i][j] << " "; out << "\n"; } out << "\nListados " << n << " elementos\n"; return out; };  
    A saída é a mesma.
     
    No geral não é mais preciso alocar e liberar memória assim em C++, mas agora não posso escrever outro exemplo
     
     
     
     
  22. O post de arfneto em Transformar essa lista simplesmente encadeada em uma simplesmente circular foi marcado como solução   
    // definição de uma lista simples typedef struct{ struct Musica *primeiro; char nome[30]; struct Musica *proxima; }Musica;  
    Sugiro que evite esse tipo de comentário. Comente o que está fazendo e porque está fazendo, como um recado para você mesmo daqui um tempo, ou para quem esteja lendo seu programa. E evite esses comentários meio que óbvios.
     
    Sobre a estrutura
     
    Evite ao máximo escrever assim.
     
    Uma lista é um container. Pode ter qualquer coisa dentro. Mas a lista é feita de nós, os tais links, um que aponta para o outro. DENTRO desses links é que estão os dados. As músicas. Só que no próximo programa serão livros, carros, int, char.
     
    Não misture as coisas. Só vai dificultar sua vida. A lista é genérica. Pode ser de qualquer coisa. 
     
    Veja esse exemplo:
     
    typedef struct st_no { char nome[30]; } Musica;  
    Esse é o dado.
     
    A lista é de nós:
     
    typedef struct st_node {     Info*           info;     struct st_node* ini;     struct st_node* fim; } Node;  
    E a lista o que é?
     
    Uma série de links. Seu modelo deve representar isso.
     
    typedef struct { Node* ini; Node* fim; unsigned size; // tamanho } Lista;  
    O que falta?
     
    typedef Musica Info;  
    Pronto: nesse programa a lista é de Musica.
     
    No geral se usa void* como o tipo da lista, para ficar genérico. Pense nisso.
     
    Em resumo, juntando tudo:
     
    typedef struct { char nome[30]; } Musica; typedef Musica Info; typedef struct st_node { Info* info; struct st_node* ini; struct st_node* fim; } Node; typedef struct { Node* ini; Node* fim; unsigned size; // tamanho } Lista;  
    É muito mais simples programar assim. E seu próximo programa de listas pode ser o mesmo: a lista é uma lista, uma série de links de um Node para outro.
     
    Sobre as funções
     
    void inicializarMusica(Musica **musica); void inserirMusica(Musica **musica,char auxMusica[30]); void exibirMusicas(Musica **musica); void removerMusicaDaLista(Musica **musica,char auxMusica[30]);  
    Aqui você tem o reflexo do problema de que falei acima. Não retorne void. Não misture lista com musicas. Não tem sentido inicializarMusica por exemplo. 
     
    Se Musica é um dado que vai estar numa lista não deveria ter referência a Musica**. Pense nisso.
     
    O normal:
     
    Lista* inicializarLista(); int inserir_na_lista(Info* info, Lista* l); int exibir_musicas(Lista* lista); int remover_da_lista(Info* info, Lista* l);  
    Compare: Não tem referência a Musica na Lista. Apenas em exibir_musicas aparece a Lista porque afinal é onde estão as músicas.
     
    E a lista circular?
     
    Lista circular não existe. Trata-se apenas de uma disciplina de inserção. Você coloca um limite na lista e ao chegar a esse limite não cria mais nós: apenas passa a escrever o novo em cima do mais antigo. Só isso.

    Algo assim:
     
    typedef struct { Node* ini; Node* fim; unsigned size; // tamanho unsigned limite; // tamanho } Lista;  
    E aí dependendo do modelo você implementa a inserção de acordo. É só isso: um critério. O que fazer ao atingir o limite. Em relação a isso uma maneira comum de implementar a lista é ter um registro fixo, que é chamado de sentinela na literatura --- sentinel record --- para facilitar a programação: a lista vazia só tem o sentinela. E assim evita que o programa se perca no tal círculo de nós.
     
     
     
     
     
     
     
     
  23. O post de arfneto em Qual o melhor compilador para c/c++? foi marcado como solução   
    Se você não tivesse o gcc não conseguiria usar essa extensão. Leu o que eu expliquei? 
     
    Uma vantagem de usar VS Code é que pode rapidamente alternar para outros compiladores e continuar usando um IDE.
     
    No Windows os compiladores mais comuns são o da Microsoft, CL, o gcc, o Clang e o compilador da Intel. Todos requerem instalação, mesmo caso do Linux e do Mac.
     
    Você marcou C# no tópico, mas está falando de C e C++...
  24. O post de arfneto em Qual o melhor compilador para c/c++? foi marcado como solução   
    Se você não tivesse o gcc não conseguiria usar essa extensão. Leu o que eu expliquei? 
     
    Uma vantagem de usar VS Code é que pode rapidamente alternar para outros compiladores e continuar usando um IDE.
     
    No Windows os compiladores mais comuns são o da Microsoft, CL, o gcc, o Clang e o compilador da Intel. Todos requerem instalação, mesmo caso do Linux e do Mac.
     
    Você marcou C# no tópico, mas está falando de C e C++...
  25. O post de arfneto em Qual o melhor compilador para c/c++? foi marcado como solução   
    Se você não tivesse o gcc não conseguiria usar essa extensão. Leu o que eu expliquei? 
     
    Uma vantagem de usar VS Code é que pode rapidamente alternar para outros compiladores e continuar usando um IDE.
     
    No Windows os compiladores mais comuns são o da Microsoft, CL, o gcc, o Clang e o compilador da Intel. Todos requerem instalação, mesmo caso do Linux e do Mac.
     
    Você marcou C# no tópico, mas está falando de C e C++...

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...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!