Ir ao conteúdo
  • Cadastre-se

C Como Ler Char? Visual Studio


Hedjander

Posts recomendados

Ola!

Estou iniciando em Programação e preciso fazer um projeto de lista encadeada simples, e apesar de muita pesquisa não consegui concluir meu trabalho devido a não conseguir indentificar o erro que não deixa mostrar testos na tela. Alguém pode me ajudar por favor? desde já grato!

#include <stdio.h>                               
#include <stdlib.h>
#include <string.h>

#define TAMANHO 30


//Questão do Trabalho:




//------------ INSERIR FUNÇÕES
int menu();
void InserirInicio(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s);
void Listar();


//----------- INSERIR STRUCT
struct Musicas {
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
    struct Musicas* prox;
} *Head;

// ---------- INSERIR VARIÁVEIS
int  main() {
    int op, pos, c, m, s;
    char Musica[TAMANHO];
    char Cantor[TAMANHO];
    Head = NULL;


    while (1) { // laço de Repetição

        op = menu();
        switch (op) {

        case 1:
            printf("Qual musica Gostaria de Adicionar? ");
            gets_s(Musica);
            while ((c = getchar()) != '\n' && c != EOF) {} //USADO PRA LIMPAR OS DADOS
																						...
//------------- inserir informações na PlayList----------------------

void InserirInicio(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s)
{
    Musicas* NovoElemento;
    NovoElemento = (struct Musicas*)malloc(sizeof(struct Musicas));
    NovoElemento->Nome, Musica;
    NovoElemento->Artista, Cantor;
    NovoElemento->min = m;
    NovoElemento->seg = s;

    if (Head == NULL)
    {
        Head = NovoElemento;
        Head->prox = NULL;
    }
    else
    {
        NovoElemento->prox = Head;
        Head = NovoElemento;
    }
}

...
  
  // FUNÇÃO LISTAR
void Listar()
{
    Musicas* ElementoVarredura;
    ElementoVarredura = (struct Musicas*)malloc(sizeof(struct Musicas));

    ElementoVarredura = Head;
    if (ElementoVarredura == NULL) {
        return;
    }
    while (ElementoVarredura != NULL) {
        printf("Nome da musica: %s\n", ElementoVarredura->Nome); // NÃO ESTA IMPRIMINDO NA TELA
        printf("Artista: %s\n", ElementoVarredura->Artista);     // NÃO ESTÁ IMPRIMINDO NA TELA
        printf("Minutos de duracao: %d\n", ElementoVarredura->min);	// ESTÁ IMPRIMINDO CORRETAMENTE
        printf("Segundos de duracao: %d\n", ElementoVarredura->seg);// ESTÁ IMPRIMINDO CORRETAMENTE
        ElementoVarredura = ElementoVarredura->prox;
    }
    printf("\n");

    system("pause");
    return;
}

 

 

tela.png

  • Amei 1
Link para o comentário
Compartilhar em outros sites

Use o botão code <> para inserir seu código num bloco e ajude o pessoal a ajudar você...

 

Seu programa não está bom.

 

Essa é a declaração de gets_s():

char *gets_s(
   char *buffer,
   size_t sizeInCharacters
);

Sobre InserirInicio()

    void InserirInicio(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s);

 

  • Não acha que deveria retornar algo, como o novo endereço da lista?
  • E Se insere apenas no início porque não chama a função de inserir() apenas?
  • E se criou a struct Musicas para poder criar uma lista de ... Musicas porque não insere Musicas?? Porque Cantor no parâmetro e Artista na struct? Algo assim
        Lista* inserir(Musica* uma_musica);


    Não declare os protótipos ANTES das variáveis: grande chance de suas funções usarem essas variáveis, certo?

 

Não use:

 

//------------ INSERIR FUNÇÕES
int menu();
void InserirInicio(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s);
void Listar();


//----------- INSERIR STRUCT
struct Musicas {
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
    struct Musicas* prox;
} *Head;

Escreva assim:

//----------- INSERIR STRUCT
struct Musicas {
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
    struct Musicas* prox;
} *Head;

//------------ INSERIR FUNÇÕES
int menu();
void InserirInicio(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s);
void Listar();

 

  • Obrigado 2
Link para o comentário
Compartilhar em outros sites

3 minutos atrás, Hedjander disse:

Eu não tinha colocado o código completo, vou postar por inteiro para que eu mesmo entenda melhor... 

 

Entendeu o que eu escrevi sobre a ordem das declarações e a função inserir e tal? Vi que não mudou nada.

adicionado 8 minutos depois

Não entendo esse tipo de construção:

    scanf_s("%d", &op);
    while ((c = getchar()) != '\n' && c != EOF){}

Se suas opções são também dígitos que são char porque usar scanf() para ler op e getchar() para descartar o resto da linha?

Não podia usar apenas getchar()?

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 minuto atrás, Hedjander disse:

Eu não entendi, na verdade estou muito confuso, eu apenas peguei um código que o professor fez em aula e tentei adaptar conforme instruído por ele. Esta tudo completamente errado?

 

Não, não está tudo errado. O programa não está bom, mas pode ser útil. Foi um professor universitário que escreveu esse código?

 

Em relação ao que você não entendeu, provavelmente seria mais produtivo você ir perguntando sobre essas coisas que não entendeu, eu acho...

Você entendeu o conceito desse troço de lista encadeada? E entende o que signifoca alocar memória e liberar?

 

adicionado 6 minutos depois

Você tem um livro texto? Qual é? Tem uma apostila ao menos? Algum site de referência?

 

É importante isso. Que compilador você usa? IDE, sistema? Essas coisas

  • Amei 1
Link para o comentário
Compartilhar em outros sites

@arfneto KK, foi, portanto pensei que era um programa top de seguir 🙄

 

Eu acredito que sim, na teoria, é a parte de alocar a memória que está com erros?

adicionado 26 minutos depois

Vou por partes para tentar entender... desde já obrigado pela paciência!

#include <stdio.h>                               
#include <stdlib.h>
#include <string.h>

#define TAMANHO 30   // Essa é a definição da quantidade máxima de caracteres das variáveis "Strings" é obrigatório?


//------------ INSERIR FUNÇÕES
int menu();																			
void Inserir(char Musica[TAMANHO], char Cantor[TAMANHO], int m, int s);
void Listar();


// ---------- INSERIR VARIÁVEIS
int  main() {
    int op, pos, c; // Variaveis do Menu do programa que já estavam lá, não sei se precisam ser declaradas aqui.
    int m, s; -- // Variáveis que eu inventei 
    char Musica[TAMANHO];
    char Cantor[TAMANHO];
    Head = NULL;

    //----------- INSERIR STRUCT
    struct Musicas {						// Quando digitar os dados, eles vão para o Head, que é o topo da lista ?
        char Nome[TAMANHO];
        char Artista[TAMANHO];
        int min, seg;
        struct Musicas* prox;
    } *Head;

 Essa Parte está certa?

adicionado 33 minutos depois

@arfneto Não tenho nada, só as explicações do professor que não explicou todas a linhas do código que ele fez, não achei nenhum apostila que ensine a fazer, só definições, mas nenhum exemplo , se puder me indicar ficaria mt grato, uso o Visual Studio 2019.

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Hedjander disse:

 KK, foi, portanto pensei que era um programa top de seguir 🙄

 

Eu acredito que sim, na teoria, é a parte de alocar a memória que está com erros?

 

oh... 🙃 Ele não trabalha pra mim, nem ensina pra mim, nem eu ensino pra ele. Mas o programa não está nada bom. Nada mesmo. Podemos discutir isso outra hora. Existe uma filosofia por trás de como fazer e como não fazer as coisas em cada linguagem. Em especial se você está ensinando ou aprendendo.

 

 

 

1 hora atrás, Hedjander disse:

Eu acredito que sim, na teoria, é a parte de alocar a memória que está com erros?

adicionado 26 minutos depois

Vou por partes para tentar entender...

 

Uma pena você não ter um livro-texto. Sábia decisão :D ir por partes. Mas não foi o que fez com o programa...

 

1 hora atrás, Hedjander disse:

Não tenho nada, só as explicações do professor que não explicou todas a linhas do código que ele fez, não achei nenhum apostila que ensine a fazer, só definições, mas nenhum exemplo , se puder me indicar ficaria mt grato, uso o Visual Studio 2019

 

Entendo. Boa decisão usar Visual Studio 2019.

 

Sobre as tais listas ligadas 

 

Uma lista encadeada é uma estrutura de dados que a gente usa como camada de abstração, uma ferramenta para representar no programa coisas concretas como uma fila ou uma playlist, como o seu caso.

O fato de ser simplesmente ou duplamente ou multiplamente encadeada é irrelevante para o princípio da coisa: É uma lista de coisas e cada coisa aponta para outra de alguma maneira. Nem precisa ter ponteiros por exemplo. Mas precisa ter algum tipo de encadeamento :)

Num mundo ideal é transparente: a implementação de uma abstração. Você usa as funções e pronto. Elas não são sequer dependentes do tipo de dados que está armazenando, ou ficariam menos úteis, certo? Quanto mais genéricas melhor.

Linguagens como C++ e java e muitas outas tem listas como parte da linguagem, e funcionam para listar qualquer coisa, claro. São chamadas containers nessas linguagens. E faz sentido não?

Veja um exemplo bem besta:
 

Em C++

#include <iostream>
#include <list>
using namespace std;
int main()
{
    printf("lista em C++\n");
    list<int> lista = { 1,2,3,4,5 };
    lista.push_front(8); // 8 no inicio
    lista.push_back(9); // 9 no fim
    for (auto n : lista)
        printf("%d\n", n);
};

mostra

lista em C++
8
1
2
3
4
5
9


Em java

import java.util.ArrayList;
import java.util.List;

public class Main {
    
    public static void main(String[] args)
    {
        List<Integer> lista = new ArrayList<Integer>();
        for( int i =1; i<6; i=i+1) lista.add(i);
        System.out.println("lista de int em java\n");
        lista.add(0);
        lista.add(9);
        lista.forEach( i -> System.out.println(i));
    }
}

Que mostra

lista de int em java

1
2
3
4
5
0
9

Veja que em java não tem pronta faunção pra inserir no início e no fim. Só no fim. E veja como é parecido ...

 

Como fazer isso em C?

 

Pensando em seu exemplo, veja essas declarações

#define TAMANHO 15

struct musica
{
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
};  // musica
typedef struct musica Musica;

Musica 		uma_musica; // exemplos
Musica		outra;
Musica*		pMusica;

Isso é o que você vai listar. Esse typedef serve só para ficar mais legível e não ter que ficar repetindo toda hora na declaração esse struct musica.

 

struct no
{
    void* musica;
    struct no* proxima;
};  // no
typedef struct no Lista;

Lista	playlist; // exemplo
Lista*	pList;

Lista* inserir(void*, Lista*);
int    listar(Lista*);

Aqui está uma possível lista. Um (void*) em C é um ponteiro "genérico". A razão de usar algo assim está no fato de que depois se pode usar essas funções para qualquer coisa, porque NUNCA SE MISTURA DADOS COM O CODIGO DA ESTRUTURA DE ABSTRAÇÃO ou ela deixa de ser abstrata afinal

 

A primeira função: listar()

 

Faz sentido porque ela tem que funcionar mesmo antes da Lista existir, ou quando ela está vazia

Então vamos usar... o Bloco de Notas do Windows e criar gabarito.txt porque a gente quer uma lista

formatada e não quer perder tempo com printf() que é uma m.

    *    1    *    2    *    3    *    4    *    5    *    6
123456789012345678901234567890123456789012345678901234567890
  #            faixa            artista    HH:MM
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    

Aí copiamos isso direto pros printf() :D 


Listar() é a única rotina da implementação que precisa entrar no mérito do que tem dentro da lista, porque precisa mostrar os elementos. Na verdade mesmo isso podia ser genérico, usando um conceito chamado de callback. Quem sabe na próxima versão.

 

Uma possível listar() usando o gabarito.txt

int listar(Lista* l)
{
    int total = 0;
    Lista* aux = l;
    printf("***** listar() *****\n\n");

    if (l == NULL)
    {
        printf("Lista nao iniciada\n");
        return -1;
    }
    if (l->musica == NULL)
    {
        printf("Lista vazia\n");
        return 0;
    }
    // nao esta vazia entao cria um ponteiro para
    // o tipo de dados que estamos usando
    printf(
        "  #            faixa            artista    HH:MM\n\n"
    );
    do
    {
        Musica* pM = (Musica*)aux->musica; // a musica
        total = total + 1;
        printf(
            "%3d: %15s    %15s    %02d:%02d\n",
            total,
            pM->Nome,
            pM->Artista,
            pM->min,
            pM->seg
            );
        aux = aux->proxima;
    } while (aux != NULL); // do-while()
    return total;
};  // listar()

E como inserir?

Como a gente só insere no início algo assim já serve:

Lista* inserir(void* m, Lista* l)
{
    printf("***** inserir() *****\n");
    // cria um elemento
    Lista* novo = (Lista*)malloc(sizeof(Lista));
    novo->musica = m;
    novo->proxima = l;
    return novo;
};  // inserir()

Note que isso funciona mesmo que a lista esteja vazia então não precisa criar aqueles clássicos métodos criar_lista().

 

Um exemplo criando uma lista com duas músicas

int  main()
{
    // cria uma musica
    Musica uma_musica;
    strcpy(uma_musica.Artista, "artista 1");
    strcpy(uma_musica.Nome, "nome 1");
    uma_musica.min = 3;
    uma_musica.seg = 35;
    // cria uma outra musica
    Musica outra_musica;
    strcpy(outra_musica.Artista, "artista 2");
    strcpy(outra_musica.Nome, "nome 2");
    outra_musica.min = 4;
    outra_musica.seg = 28;

    // poe na lista
    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)&uma_musica, playlist);
    listar(playlist); // uma musica 
    playlist = inserir((void*)&outra_musica, playlist);
    listar(playlist); // duas musicas
    return 0;
}

Apenas declara duas músicas e põe na lista

 

Lista nao iniciada
***** inserir() *****
***** listar() *****

  #            faixa            artista    HH:MM

  1:          nome 1          artista 1    03:35
***** inserir() *****
***** listar() *****

  #            faixa            artista    HH:MM

  1:          nome 2          artista 2    04:28
  2:          nome 1          artista 1    03:35

Assim já vê que listar() funciona com a lista vazia, e inserir()... insere. E o gabarito funciona.

 

Essas mensagens com ***** são só para dar mais segurança de que método está rodando.

 

Eis o programa de teste

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>                               
#include <stdlib.h>
#include <string.h>

#define TAMANHO 15

struct musica
{
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
};  // musica
typedef struct musica Musica;

struct no
{
    void* musica;
    struct no* proxima;
};  // no
typedef struct no Lista;

Lista* inserir(void*, Lista*);
int    listar(Lista*);

int  main()
{
    // cria uma musica
    Musica uma_musica;
    strcpy(uma_musica.Artista, "artista 1");
    strcpy(uma_musica.Nome, "nome 1");
    uma_musica.min = 3;
    uma_musica.seg = 35;
    // cria uma outra musica
    Musica outra_musica;
    strcpy(outra_musica.Artista, "artista 2");
    strcpy(outra_musica.Nome, "nome 2");
    outra_musica.min = 4;
    outra_musica.seg = 28;

    // poe na lista
    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)&uma_musica, playlist);
    listar(playlist); // uma musica 
    playlist = inserir((void*)&outra_musica, playlist);
    listar(playlist); // duas musicas
    return 0;
}

Lista* inserir(void* m, Lista* l)
{
    printf("***** inserir() *****\n");
    // cria um elemento
    Lista* novo = (Lista*)malloc(sizeof(Lista));
    novo->musica = m;
    novo->proxima = l;
    return novo;
};  // inserir()

int listar(Lista* l)
{
    int total = 0;
    Lista* aux = l;
    printf("***** listar() *****\n\n");

    if (l == NULL)
    {
        printf("Lista nao iniciada\n");
        return -1;
    }
    if (l->musica == NULL)
    {
        printf("Lista vazia\n");
        return 0;
    }
    // nao esta vazia entao cria um ponteiro para
    // o tipo de dados que estamos usando
    printf(
        "  #            faixa            artista    HH:MM\n\n"
    );
    do
    {
        Musica* pM = (Musica*)aux->musica; // a musica
        total = total + 1;
        printf(
            "%3d: %15s    %15s    %02d:%02d\n",
            total,
            pM->Nome,
            pM->Artista,
            pM->min,
            pM->seg
            );
        aux = aux->proxima;
    } while (aux != NULL); // do-while()
    return total;
};  // listar()

 

  • Amei 1
Link para o comentário
Compartilhar em outros sites

Uau, bem legal, esse teste seria caso as músicas já estivessem no programa certo? e se for iniciar o programa , pedir para o usuário adicionar músicas , ler a entrada no teclado e depois imprimir na tela, eu posso adaptar esse teste inserindo um menu?

Por Favor,seria pedir muito um modelo de como ficaria para adicionar uma musica ? Aí depois eu sigo de base para fazer como acrescentar um Artista, e acrescentar a duração da música tudo pelo usuário do programa...

Link para o comentário
Compartilhar em outros sites

 

1 hora atrás, Hedjander disse:

esse teste seria caso as músicas já estivessem no programa certo?

 

Claro. Claro que não. Esse programa começa assim:
 

    Lista* playlist = NULL;

 

Então é lógico que as músicas não "estão no programa".

 

O programa que te mostrei tem tipo 6 linhas

    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)fabrica(1), playlist); // primeira
    listar(playlist); // uma musica 
    playlist = inserir((void*)fabrica(1), playlist); // outra
    listar(playlist); // duas musicas agora

E cria a lista e insere as tais duas musicas

  #            faixa            artista    HH:MM

  1:      Musica 002        Artista 002    09:29
  2:      Musica 001        Artista 001    09:33

 

1 hora atrás, Hedjander disse:

um modelo de como ficaria para adicionar uma musica ? Aí depois eu sigo de base para fazer como acrescentar um Artista, e acrescentar a duração da música tudo pelo usuário do programa...

 

Como poderia ser um modelo? O que te mostrei é um modelo. Se você preferir pode sim claro digitar os 8 campos das duas músicas e as opções do seu menu. Não faz diferença exceto o tempo que vai perder e a dificuldade em repetir um teste.

 

Eu sempre posto isso nesse forum e explico isso pra um grande número de pessoas: não misture as coisas. Não limpe a tela num programa de teste. Não crie um menu antes das funções estarem ultra-prontas. Não perca seu tempo. Isso não resolve nada.

Preste atenção: seu menu vai ler titulo, artista e duração da faixa. Só isso. Então qual o propósito de efetivamene ficar lendo isso? 

 

Veja (em seu código):

            printf("Qual musica Gostaria de Adicionar? ");
            gets_s(Musica);
            while ((c = getchar()) != '\n' && c != EOF) {} //USADO PRA LIMPAR OS DADOS


            printf("Qual o nome do Cantor/Artista dessa musica? ");
            gets_s(Cantor);
            while ((c = getchar()) != '\n' && c != EOF) {}

            printf("Quantos minutos de duracao?");
            scanf_s("%d", &m);
            while ((c = getchar()) != '\n' && c != EOF) {}

            printf("Quantos segundos de duracao?");
            scanf_s("%d", &s);
            while ((c = getchar()) != '\n' && c != EOF) {}

            InserirInicio(Musica, Cantor, m, s);

E a tal struct (em seu código):

struct Musicas {
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
    struct Musicas* prox;
} *Head;

Se leu o que eu escrevi deve ter entendido que assim não é bom. E visto o exemplo de declaração.

 

Mas o que importa é que está lendo exatamente os campos que tem na struct. E na ordem. Para que?

 

De novo em seu código:

    int m, s;
    char Musica[TAMANHO];
    char Cantor[TAMANHO];
    Head = NULL;

Essas são as variáveis que você leu. Bem óbvio: uma para cada campo da struct.

Se você tem a função que eu te mostrei

    Lista*  inserir(void* musica, Lista* playlist); // por exemplo

E leu essas coisas, então simplesmente aloca uma musica, preenche e insere. Não é o que está no programa que te mostrei? Trocando os nomes ficaria (depois de ler os valores, claro):

    // cria uma outra musica
    Musica outra_musica;
    strcpy(outra_musica.Artista, Cantor);
    strcpy(outra_musica.Nome, Musica);
    outra_musica.min = m;
    outra_musica.seg = s;

    // poe na lista
    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)&outra_musica, playlist);

É isso.

 

Pense de outro modo: se você tivesse uma rotina --- que já mostrei aqui em muitos casos --- que devolvesse um elemento prontinho você poderia seguir sua vida com seu programa sem perder tempo. Vamos imaginar uma função da hora declarada assim:

    Musica* fabrica(); // devolve uma musica, unica e preenchida

Cada vez que eu chamo esse trem vem uma struct Musica preenchida. Sempre diferente e numeradinha. Já não serve?
 

Citação

Para testar com 10 músicas apenas você já tem que entrar com ao menos 12  opções no menu e 40 campos. E para repetir o teste basta digitar tudo de novo. Não pode estar certo se acha que vai conseguir ficar desenvolvendo o programa assim. Compare com o que vou te mostrar.


Agora veja esse sofisticado main() com 5 linhas usando a tal rotina fabrica():

int  main()
{
    fabrica(0); // inicia a fabrica de musicas
    Lista* playlist = NULL;
    // cria e insere 10 musicas
    for (int i = 0; i < 10; i = i + 1) playlist = inserir((void*)fabrica(1), playlist);
    int n = listar(playlist); // 10 musicas?
    printf("listar() retornou %d\n", n);
    return 0;
};  // main()

E veja a saida

***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** inserir() *****
***** listar() *****

  #            faixa            artista    HH:MM

  1:      Musica 010        Artista 010    00:21
  2:      Musica 009        Artista 009    07:02
  3:      Musica 008        Artista 008    04:42
  4:      Musica 007        Artista 007    09:07
  5:      Musica 006        Artista 006    08:52
  6:      Musica 005        Artista 005    07:50
  7:      Musica 004        Artista 004    09:07
  8:      Musica 003        Artista 003    05:50
  9:      Musica 002        Artista 002    09:33
 10:      Musica 001        Artista 001    01:35

listar() retornou 10

Pois é: criou a lista com 10 músicas e listou com sucesso. E se você quiser reptir o teste com as mesmas músicas é só rodar o programa de novo. A matemática garante que vão ser geradas as mesmas músicas, até a mesma duração de todas as faixas.  Quer testar com 1.000 músicas? Mude o parâmetro de 10 para 1000.

 

Agora seria o caso de programar o resto das funções.

 

Entendeu o que estou tentando te mostrar? 

 

Eis o programa de teste com a tal fabrica(), uma rotina de 15 linhas:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>                               
#include <stdlib.h>
#include <string.h>

#define TAMANHO 15

struct musica
{
    char Nome[TAMANHO];
    char Artista[TAMANHO];
    int min, seg;
};  // musica
typedef struct musica Musica;

struct no
{
    void* musica;
    struct no* proxima;
};  // no
typedef struct no Lista;

Musica* fabrica();
Lista*  inserir(void*, Lista*);
int     listar(Lista*);

int  main()
{
    fabrica(0); // inicia a fabrica de musicas
    Lista* playlist = NULL;
    // cria e insere 10 musicas
    for (int i = 0; i < 10; i = i + 1) playlist = inserir((void*)fabrica(1), playlist);
    int n = listar(playlist); // 10 musicas?
    printf("listar() retornou %d\n", n);
    return 0;
};  // main()

Musica* fabrica(int parm)
{
    // a cada chamada retorna uma musica novinha
    static int n = 0;
    if (parm == 0)
    {
        srand(200401);
        n = 1;
        return NULL;
    }
    Musica* m = (Musica*)malloc(sizeof(Musica));
    sprintf(m->Nome, "Musica %03d", n);
    sprintf(m->Artista, "Artista %03d", n);
    m->min = rand() % 10;
    m->seg = rand() % 60;
    n = n + 1;
    return m;
};  // fabrica()

Lista* inserir(void* m, Lista* l)
{
    printf("***** inserir() *****\n");
    // cria um elemento
    Lista* novo = (Lista*)malloc(sizeof(Lista));
    novo->musica = m;
    novo->proxima = l;
    return novo;
};  // inserir()

int listar(Lista* l)
{
    int total = 0;
    Lista* aux = l;
    printf("***** listar() *****\n\n");

    if (l == NULL)
    {
        printf("Lista nao iniciada\n");
        return -1;
    }
    if (l->musica == NULL)
    {
        printf("Lista vazia\n");
        return 0;
    }
    // nao esta vazia entao cria um ponteiro para
    // o tipo de dados que estamos usando
    printf(
        "  #            faixa            artista    HH:MM\n\n"
    );
    do
    {
        Musica* pM = (Musica*)aux->musica; // a musica
        total = total + 1;
        printf(
            "%3d: %15s    %15s    %02d:%02d\n",
            total,
            pM->Nome,
            pM->Artista,
            pM->min,
            pM->seg
            );
        aux = aux->proxima;
    } while (aux != NULL); // do-while()
    printf("\n");
    return total;
};  // listar()

Veja uma parte da saída de um teste para 999 músicas mudando só o 10 para 999 em main(). E claro que esse poderia ser um parâmetro de execução e não precisaria compilar o programa de novo, certo?

 


  #            faixa            artista    HH:MM

  1:      Musica 999        Artista 999    02:53
  2:      Musica 998        Artista 998    00:38
  3:      Musica 997        Artista 997    00:01
  4:      Musica 996        Artista 996    00:47
  5:      Musica 995        Artista 995    01:47
  6:      Musica 994        Artista 994    05:07
  7:      Musica 993        Artista 993    05:47
  8:      Musica 992        Artista 992    00:05
  9:      Musica 991        Artista 991    00:19
 10:      Musica 990        Artista 990    03:06
 11:      Musica 989        Artista 989    04:48

... 

988:      Musica 012        Artista 012    01:16
989:      Musica 011        Artista 011    00:19
990:      Musica 010        Artista 010    00:21
991:      Musica 009        Artista 009    07:02
992:      Musica 008        Artista 008    04:42
993:      Musica 007        Artista 007    09:07
994:      Musica 006        Artista 006    08:52
995:      Musica 005        Artista 005    07:50
996:      Musica 004        Artista 004    09:07
997:      Musica 003        Artista 003    05:50
998:      Musica 002        Artista 002    09:33
999:      Musica 001        Artista 001    01:35

listar() retornou 999

E se testar com 999 as primeiras 10 músicas serão as mesmas de quando testou com 10... Cantor, Musica, m e s...

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

6 minutos atrás, Hedjander disse:

Obrigado pela ajuda!

Você pode pegar esse programa e colocar as outras funções. E depois colocar o menu e fica tudo pronto...

 

A função que apaga a lista --- não uma música --- é a que tem mais chance de dar erro. pode usar algo assim que funciona:

 

Lista*  apagar(Lista* l)
{   // apagar e como listar()
    printf("***** apagar() *****\n\n");

    if (l == NULL)
    {
        printf("Lista nao iniciada\n");
        return -1;
    }
    if (l->musica == NULL)
    {
        printf("Lista vazia\n");
        return NULL;
    }
    // nao esta vazia entao varre a lista e apaga 
    // os caras todos
    Lista* aux = l;
    Lista* temp = NULL;
    do
    {
        temp = aux->proxima; // salva o endereco da proxima
        free(aux->musica); // apaga essa musica
        free(aux); // apaga o no da lista
        aux = temp;
    } while (aux != NULL); // do-while()
    return NULL;
};  // apagar()

 

Entendeu o que expliquei? Entendeu o lance da tal fabrica() de musicas? 

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, Hedjander disse:

@arfneto Sim, vou fazer aqui e retorno com mais duvidas se houver.

Então... Esses geram uma PlayList com tudo que eu preciso, porém de forma aleatória? preenchimento automático? no caso eu precisaria de usar a leitura do teclado, uma música existente (" scanf_s e gest_s, está correto?) Eu entendi certo o funcionamento do teste?

 

Ex:      1º - tecle 1 para adicionar uma música:                                // Menu

            2º - printf("Qual musica Gostaria de Adicionar? ");              // a pessoa digita manualmente a música que deseja
          3º -  gets_s(Musica);                                                              // o Programa o que foi digitado.

          4º - printf("Nome da musica: %s\n", Varredura->Nome);     // o Programa exibe a música que acabou de ser digitada.

 

Link para o comentário
Compartilhar em outros sites

35 minutos atrás, Hedjander disse:

Esses geram uma PlayList com tudo que eu preciso, porém de forma aleatória? preenchimento automático? no caso eu precisaria de usar a leitura do teclado, uma música existente (" scanf_s e gest_s, está correto?) Eu entendi certo o funcionamento do teste?

 

Não exatamente aleatória porque vai reproduzir sempre a mesma sequência. Então é como se um usuário voltase sempre e digitasse tudo de novo até o seu programa funcionar...

 

Tudo que você precisa fazer é terminar as funções. As funções objetivas que estão faltando. Não insista nesse lance do menu que só vai te atrasar. Eu já te mostrei onde colocar isso depois quando estiver pronto.

 

Esse "teste" é o seu programa de fato. Apenas implemente as outras funções e depois coloque as chamadas de função --- já testadas --- no menu. Não faça ao contrário. Já te expliquei porque.

 

Programe as coisas importantes, como o gerenciamento da playlist. Imagino que tenha uma especificação... Coisas como

  • criar playlist
  • remover playlist
  • apagar uma musica da lista 
  • mudar a ordem as músicas

Coisas objetivas. Funções do programa.

 

Vou reproduzir aqui o seu código de inserir por exemplo, com as funções:

 

    int m, s;
    char Musica[TAMANHO];
    char Cantor[TAMANHO];
    Lista* HEAD = NULL;
    
    printf("Qual musica Gostaria de Adicionar? ");
    gets_s(Musica);
    while ((c = getchar()) != '\n' && c != EOF) {} //USADO PRA LIMPAR OS DADOS
    
    printf("Qual o nome do Cantor/Artista dessa musica? ");
    gets_s(Cantor);
    while ((c = getchar()) != '\n' && c != EOF) {}

    printf("Quantos minutos de duracao?");
    scanf_s("%d", &m);
    while ((c = getchar()) != '\n' && c != EOF) {}

    printf("Quantos segundos de duracao?");
    scanf_s("%d", &s);
    while ((c = getchar()) != '\n' && c != EOF) {}

    strcpy(outra_musica.Artista, Cantor);
    strcpy(outra_musica.Nome, Musica);
    outra_musica.min = m;
    outra_musica.seg = s;

    // poe na lista
    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)&outra_musica, playlist);

É só isso. Mas não deve usar isso agora. Entenda isso. Depois que programar o resto você põe isso em 15 minutos. E não tem o que testar... É só preencher um formulário....

 

Tem uma especificação desse programa? Um enunciado? 

 

Já te disse que a declaração de get_s está errada, certo? no primeiro parágrafo do primeiro post. E comentei sobre usar scanf() E get_s() em seguida, certo?

Link para o comentário
Compartilhar em outros sites

Então só faltam as opções de editar a playlist e, se você quiser a versão completa:

  • no início da execução ver se tem um playlist.txt no diretorio corrente e tentar ler as musicas de la
  • no final do programa gravar a playlist nesse arquivo

Pode escrever então 4 funções no programa "teste"

//
// fase "2" :)
//
Lista* apagar_da_playlist(int musica);
Lista* inserir_na_playlist(struct no* musica);
Lista* inserir_do_arquivo(char* arquivo);
Lista* gravar_no_arquivo(char* arquivo);

Já temos a rotina que insere na playlist então criar a partir do arquivo é trivial: bastar ler as músicas, montar a estrutura e chamar insere(). Não tem o que testar, porque ela já funciona.

 

Citação

O mais importante aqui é você --- o aluno --- ver que está criando algo a partir das ferramentas que escreveu tipo ontem. inserir a partir do arquivo é trivial porque você escreveu um gabarito com o formato e escreveu e testou ontem a rotina que insere --- Lista*  inserir(void* musica, Lista* lista) --- uma musica da playlist. Tanto faz se ela veio do tal menu, da tal fabrica() ou do arquivo em disco

 

E aquele arquivo "gabarito.txt" está de volta: basta digitar igualzinho no arquivo de entrada as musicas e pronto. Tem até aquelas primeiras linhas do arquivo mostrando o número das colunas para você posicionar os dados.

 

gabarito.txt copiado do outro post

    *    1    *    2    *    3    *    4    *    5    *    6
123456789012345678901234567890123456789012345678901234567890
  #            faixa            artista    HH:MM
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    
000: 123456789012345    123456789012345    MM:SS    

Editado para o que precisa agora

FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    
FFFFFFFFFFFFFFF AAAAAAAAAAAAAAA MM SS    

Podemos deixar os espaços para facilitar a visualização. O programa é nosso afinal. E podemos diminuir o tamanho para algo fácil de ler e digitar, tipo 15 colunas e não 50 ou 200 para os campos de artista e faixa ;) 

Continuando com a parada de não trabalhar a toa, eis a saída do programa, copiada do outro tópico, para 10 músicas:

  #            faixa            artista    HH:MM

  1:      Musica 010        Artista 010    00:21
  2:      Musica 009        Artista 009    07:02
  3:      Musica 008        Artista 008    04:42
  4:      Musica 007        Artista 007    09:07
  5:      Musica 006        Artista 006    08:52
  6:      Musica 005        Artista 005    07:50
  7:      Musica 004        Artista 004    09:07
  8:      Musica 003        Artista 003    05:50
  9:      Musica 002        Artista 002    09:33
 10:      Musica 001        Artista 001    01:35

Se colocar isso no arquivo "entrada.txt" e ler de volta igualzinho essa parte do seu programa estará aprovada sem stress: nada de ficar na frente do terminal inventando musicas 5 minutos para cada teste...

 

Editado para ficar como vai estar no arquivo no disco

     Musica 010        Artista 010    00:21
     Musica 009        Artista 009    07:02
     Musica 008        Artista 008    04:42
     Musica 007        Artista 007    09:07
     Musica 006        Artista 006    08:52
     Musica 005        Artista 005    07:50
     Musica 004        Artista 004    09:07
     Musica 003        Artista 003    05:50
     Musica 002        Artista 002    09:33
     Musica 001        Artista 001    01:35

Basta gravar no disco e tentar ler

 

É óbvio que não precisa usar o seu programa para testar isso, certo? O programa inteiro com aquelas funções todas.

 

Assim é que se trabalha na prática com essas coisas: apenas copie o que precisa em termos de declarações para o novo programa. O que? Só aquela struct mesmo :). Para isso existe o conceito de header, o tal arquivo .h. E lá você escreve as funções que leem do arquivo e gravam no arquivo a playlist. Depois você põe as duas funções novas testadas no arquivo. Sabendo que vão funcionar...

 

 

Como testar isso?

Pois é: apenas leia e grave um arquivo desses com suas funções. O arquivo de saída tem que ser igualzinho o de entrada. Como compara? Pode usar ser tão fácil como escrever


fc.png.240a19f655aa4e8810ca2d34f2cb17eb.png

 

Certo?

fc.png

Link para o comentário
Compartilhar em outros sites

20 minutos atrás, Hedjander disse:

Eu entendi que assim é o correto e mais eficiente, mas, ainda que não valha a pena, insistindo no modelo que o professor passou, esse código compila. Usando exatamente essa estrutura que está aí, você sabe me dizer como eu faria para acrescentar mais dados?

 

Compilar não quer dizer nada. Basta apertar o botãozinho que roda o programa e pode ver isso em muitos, muitos casos. E passar dias fazendo um programa trivial que já podia estar pronto, apenas por misturar as coisas e ir pelo caminho errado é claro possível. Trata-se do livre arbítrio afinal.

 

O que eu te expliquei não vai mudar o seu programa. Nào sei mais como explicar isso. Apenas ele fica pronto num instante. E depois você insere as funções no seu precioso menu. Não existe nada de especial em um menu. Não vai criar nada. Só vai perder seu tempo.
 

Devido ao contexto atual de epidemia estou meio sem trabalho. E resolvi digamos estender meu trabalho voluntário nos foruns. E nesse tempo já te expliquei mais de uma vez que não é uma mudança de modelo. É só mais esperto. Você faz seu programa primeiro. Depois vê essas coisas de menu e telinha. Não importa se seu professor diz o contrário. Ou seu instinto. As funções que te mostrei e talvez as que você escreveu funcionam com ou sem o menu.

 

Parece que não leu os exemplos também.

 

Em relação à sua pergunta: "como acrescentar mais dados" acho que já respondi duas vezes. E mostrei o código. Você não está lendo. Acha o texto muito longo?

 

De novo, copiado do outro post, dentro do seu próprio programa:

    int m, s;
    char Musica[TAMANHO];
    char Cantor[TAMANHO];
    Lista* HEAD = NULL;
    
    printf("Qual musica Gostaria de Adicionar? ");
    gets_s(Musica);
    while ((c = getchar()) != '\n' && c != EOF) {} //USADO PRA LIMPAR OS DADOS
    
    printf("Qual o nome do Cantor/Artista dessa musica? ");
    gets_s(Cantor);
    while ((c = getchar()) != '\n' && c != EOF) {}

    printf("Quantos minutos de duracao?");
    scanf_s("%d", &m);
    while ((c = getchar()) != '\n' && c != EOF) {}

    printf("Quantos segundos de duracao?");
    scanf_s("%d", &s);
    while ((c = getchar()) != '\n' && c != EOF) {}

    strcpy(outra_musica.Artista, Cantor);
    strcpy(outra_musica.Nome, Musica);
    outra_musica.min = m;
    outra_musica.seg = s;

    // poe na lista
    Lista* playlist = NULL;
    int n = listar(playlist); // vazia
    playlist = inserir((void*)&outra_musica, playlist);
Citação

Depois de você ler os dados que você mesmo ficou lá parado digitando, apenas chama a rotina que insere. Veja de novo o código acima


Pela terceira vez vou te mostrar o protótipo de gets_s(0 direto da documentação oficial

char *gets_s(
   char *buffer,
   size_t sizeInCharacters
);
wchar_t *_getws_s(
   wchar_t *buffer,
   size_t sizeInCharacters
);

Você continua usando com um único parâmetro como era na extinta (em 2011) gets()

 

Quando as funções estão funcionando você insere no seu precioso menu. Não antes. Não durante. É bobagem. E te mostrei. O esperto é algo como fabrica() devolver uma música prontinha, preenchida e única a cada chamada. Pena você não entender isso. Não sei mais como te explicar. Mostrar eu já mostrei. O programa que te mostrei é talvez 80% do que precisa. E o resto já até te mostrei os protótipos... E pode usar o programa abaixo que lê e grava no disco uma playlist.

 

Por falar em protótipos, veja como pode ser simples ler as musicas do disco:

NNN: MMMMMMMMMMMMMMM    AAAAAAAAAAAAAAA    MM:SS

  1:      Musica 010        Artista 010    00:21
  2:      Musica 009        Artista 009    07:02
  3:      Musica 008        Artista 008    04:42
  4:      Musica 007        Artista 007    09:07
  5:      Musica 006        Artista 006    08:52
  6:      Musica 005        Artista 005    07:50
  7:      Musica 004        Artista 004    09:07
  8:      Musica 003        Artista 003    05:50
  9:      Musica 002        Artista 002    09:33
 10:      Musica 001        Artista 001    01:35

E gravar de volta no disco.

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>                               
#include <stdlib.h>
#include <string.h>

int  main()
{
    const char* mascara = "%15c%*1c%15c%*1c%2d%*1c%2d%*1c";
    const char* arq_entrada = "gabarito.txt";
    const char* arq_saida = "saida.txt";
    int n = 0;
    FILE* entrada;
    FILE* saida;
    // o que vai ler de cada linha
    char musica[16];
    char artista[16];
    int min = 0;
    int seg = 0;
    // zera os campos de musica e artista
    memset(musica, 0, 16);
    memset(artista, 0, 16);
    entrada = fopen(arq_entrada, "r");
    if (entrada == NULL)
    {   printf("Erro tentando abrir '%s'\n", arq_entrada);
        return -1;
    };  // if()

    saida = fopen(arq_saida, "w");
    if (saida == NULL)
    {
        printf("Erro tentando criar '%s'\n", arq_saida);
        return -1;
    };  // if()

    printf("NNN: MMMMMMMMMMMMMMM    AAAAAAAAAAAAAAA    MM:SS\n\n");
    int pos = 1;
    while (!feof(entrada))
    {
        n = fscanf(entrada, mascara, musica, artista, &min, &seg);
        if (n != 4) return -1;
        printf( "%3d: %15s    %15s    %02d:%02d\n", pos, musica, artista, min, seg );
        pos = pos + 1;
        // grava no arquivo de saida no mesmo exato formato
        fprintf(saida, "%15s %15s %02d %02d\n", musica, artista, min, seg);
    }   // while()
    fclose(entrada);
    fclose(saida);
    return 0;
};  // main()

Esse programa faz isso em um único loop. Certinho. Foi testado com os dados do próprio programa. Gerados pela tal fabrica() de músicas.  Como já temos a rotina que insere e esse programa lê os 4 campos da playlist, é bem óbvio que já temos como ir lá no --- único --- loop do programa acima e chamar a rotina que insere. Isso seria claro carregar uma playlist a partir de um arquivo, como está no enunciado....

 

Como já temos a função que mostra a playlist na tela, basta copiar essa função e alterar onde ela mostra na tela para gravar no disco, como está no programa aqui que já funciona.

 

E em 15 minutos seu programa tem as funções que leem e gravam a playlist no disco. E aí você põe no menu. É assim que a coisa anda.

 

Pense nisso. 

 

Quanto à sua pergunta, como inserir, está acima, de novo.

Link para o comentário
Compartilhar em outros sites

Olá

 

Imagino que tenha feito progresso com seu programa.

 

Voltei a escrever só pra te mostrar o outro lado, o lado final disso, já que eu não tinha escrito nada sobre isso e acho que você não entendeu o sentido do que eu estava tentando explicar.

 

Supondo por um momento que seguimos o caminho de que falei, acreditando que uns 80% do programa estão já escritos por meio daquelas funções cujo código te mostrei...

 

Restariam poucas dúvidas. Temos até as funções que leêm do disco e gravam no disco uma playlist. Então podemos copiar disso também.

 

Mas e o importante menu? Pois é: um programa de menu nada precisa saber sobre a playlist. Quem diria? Eu tentei dizer.

 

Veja o programa abaixo:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h> 

int show();

// as funcoes do menu
void m_apagar();
void m_excluir();
void m_incluir();
void m_mostrar();
void m_salvar();
void m_somar();
void m_trocar();

int main(int argc, char** argv)
{
    char c = 0;
    do
    {
        c = show();
        switch (c)
        {
        case '0':
            return 0;
        case '1':
            m_incluir();
        case '2':
            m_excluir();
            break;
        case '3':
            m_mostrar();
            break;
        case '4':
            m_apagar();
            break;
        case '5':
            m_salvar();
            break;
        case '6':
            m_somar();
            break;
        case '7':
            m_trocar();
            break;
        default:
            break;
        };  // switch()
    } while (c != 'q'); // while()
    return 0;
};  // main()


int show()
{
    // temos pressa entao o menu vem de menu.txt e vai para tela
    const char* arq_entrada = "menu.txt";
    char linha[71];
    char* lido = NULL;
    char opt = 0;
    FILE* entrada;
    entrada = fopen(arq_entrada, "r");
    if (entrada == NULL)
    {
        printf("Erro tentando abrir menu '%s'\n", arq_entrada);
        return 'q';
    };  // if()
    // agora le os caras e poe na tela
    do
    {
        lido = fgets(linha, 70, entrada);
        if (lido != NULL)printf("%s", linha);
    } while (lido != NULL);
    fclose(entrada);
    printf("Sua Opcao:_");
    opt = getc(stdin);
    return opt;
};  // show()

void m_apagar() {};
void m_excluir() {};
void m_incluir() {};
void m_mostrar() {};
void m_salvar() {};
void m_somar() {};
void m_trocar() {};

Nada especial. Considere um arquivo assim:


1 - Incluir faixa
2 - Excluir faixa
3 - Mostrar PlayList
4 - Apagar PlayList
5 - Salvar PlayList em arquivo
6 - Acrescentar Musicas a partir do arquivo (+)
7 - Substituir playlist pelo conteudo do arquivo
x - inventa +10 musicas

0 - Encerrar

Então se chamar esse arquivo de "menu.txt" e colocar no diretório onde está rodando seu programa ele vai mostrar o tal menu.

 

Claro que esse programa foi copiado da função que lê uma playlist do disco.

 

E você pode ir terminando o programa inserindo chamadas às funções já testadas. É claro que vai funcionar. É por isso que a gente usa computadores afinal. Quando inserir todas as funções o programa vai estar claro pronto.

 

Exemplo: como seria mostrar uma playlist na tela?

 

Trivial: o cara vai teclar 3 e o menu vai chamar a opção m_mostrar() e tudo isso foi escrito em minutos usando recortar e colar. Essas rotinas nem precisariam estar no mesmo arquivo, como já expliquei. Então não precisaria sequer editar o programa principal. Basta ir onde está m_mostrar() e trocar por algo assim:

int     m_mostrar(Lista* playlist)
{
    int n = 0;
    cls();
    n = listar(playlist);
    if (n > 0) printf("[%d musica (s)]\n\n", n);
    pause();
    return n;
};  // m_mostrar()

Como listar(playlist) já foi escrita e testada --- você tem um código --- dias atrás é claro que vai funcionar. Como ela já devolve o número de músicas é claro que eu posso mostrar na tela. 

 

Notou que não precisa nem compilar o programa para alterar o menu? Basta editar o arquivo. 

 

Quer fazer igualzinho seu professor disse? Quando estiver satisfeito com o menu apenas recorte e cole o texto do arquivo em vários printf() em outra função e troque o código... Claro que não seria esperto. Como te disse e tentei mostrar, aquele código nem está bom.

 

 

Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

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!