Ir ao conteúdo

C Lista em C, não estou conseguindo fazer essas listas em C.


Ir à solução Resolvido por arfneto,

Posts recomendados

Postado

@patopaloro Você tem uma lista simplesmente encadeada, então pode considerar algo assim:

struct node {
    char str[101]; // dado
    struct listNode* nextP; // ponteiro para o proximo no
};

typedef struct node Node; // encurtar o nome

Você só vai ter um ponteiro em cada nó, que aponta para o próximo nó.

O ponteiro para o começo da lista então seria:

Node* startP = NULL;

O protótipo da função de inserção poderia ser algo assim:

int insert(Node** startP, char* str);
  • Curtir 2
Postado
struct node {
    char str[101]; // dado
    struct node* nextP; // ponteiro para o proximo no
};

typedef struct node Node; // encurtar o nome

Só corrigindo minha bobagem aí.

Depois de 1h o fórum não deixa mais editar a postagem 🤪

Tem alguma ideia de como seguir com o programa? O ponteiro para o começo da lista você declara na main.

Consegue fazer a função de inserção? Tem alguma ideia de como fazer?

  • Curtir 1
Postado

@patopaloro Lista não é algo que se aprende no começo, então você já deve ter uma noção de estruturas, ponteiros e alocação dinâmica, isso é a base.

Aloque um ponteiro para Node do tamanho de Node mesmo, sendo o campo str a string do nó e nextP o ponteiro para o próximo nó, você pode inicializar com NULL.

Node* novoP = malloc(sizeof(Node));

Você vai precisar de um ponteiro para o nó anterior para fazer ele apontar para o novo nó, e um para o nó atual, inicialmente apontado para onde o ponteiro do início da lista aponta:

Node* anteriorP = NULL;
Node* atualP = *startP;

Assim, basta um loop percorrendo a lista a partir de atualP, verificando o critério de colocação do nó e atualizando anteriorP.

Já que anteriorP aponta para NULL inicialmente, se ele continuar apontando para NULL, você vai ter que fazer a inserção no início: o campo nextP de novoP aponta para onde o ponteiro do início da lista aponta, e o ponteiro do início da lista aponta para esse novoP.

Caso contrário,  o campo nextP de anteriorP aponta para novoP e o campo nextP de novoP aponta para atualP.

  • Curtir 2
  • Solução
Postado

Os 3 exercícios são a mesma coisa, desde que perceba isso antes e escreva em torno dos dados

 

image.png.816b37386a00cb1bdb817de534c49728.png

 

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.image.png.3e104624f15d9619b0d212d94f84e727.png

 

 

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.

 

image.png.8a14a0f6b4f9d7adf3e51658624174e0.pngUm 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...

image.png.562eba25ecc4f4fb8f0297f280634a17.png

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

 

13 horas atrás, Lucca Rodrigues disse:

O protótipo da função de inserção poderia ser algo assim:

int insert(Node** startP, char* str);

 

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 ;) 

 

 

 

  • Curtir 1
  • Obrigado 2

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

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!