Fácil C

Inserir no final

Enunciado

Escreva uma função inserir_fim que adiciona um novo nó com um valor inteiro no final da lista encadeada. A função deve retornar o ponteiro para o início da lista (que pode ser NULL se a lista estiver vazia).

Requisitos

  • A função deve alocar memória para o novo nó.
  • Se a lista estiver vazia, o novo nó se torna a cabeça.
  • Caso contrário, percorra até o último nó e ajuste o ponteiro prox.

Código inicial

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

typedef struct No {
    int valor;
    struct No *prox;
} No;

No* inserir_fim(No *head, int valor) {
    // TODO: implemente
}

void imprimir(No *head) {
    for (No *p = head; p; p = p->prox)
        printf("%d -> ", p->valor);
    printf("NULL\n");
}

int main(void) {
    No *lista = NULL;
    lista = inserir_fim(lista, 10);
    lista = inserir_fim(lista, 20);
    lista = inserir_fim(lista, 30);
    imprimir(lista);
    // liberar memória...
    return 0;
}

Saída esperada

10 -> 20 -> 30 -> NULL
Ver dica

Crie um novo nó, se a lista estiver vazia retorne o novo nó. Senão, use um ponteiro auxiliar para chegar ao último nó e faça ultimo->prox = novo.

Mostrar solução
#include <stdio.h>
#include <stdlib.h>

typedef struct No {
    int valor;
    struct No *prox;
} No;

No* inserir_fim(No *head, int valor) {
    No *novo = malloc(sizeof(No));
    if (!novo) { perror("malloc"); exit(1); }
    novo->valor = valor;
    novo->prox = NULL;

    if (head == NULL) {
        return novo; // lista vazia: novo é a cabeça
    }

    No *atual = head;
    while (atual->prox != NULL) {
        atual = atual->prox;
    }
    atual->prox = novo; // liga o último ao novo
    return head;
}

void imprimir(No *head) {
    for (No *p = head; p; p = p->prox)
        printf("%d -> ", p->valor);
    printf("NULL\n");
}

void liberar(No *head) {
    while (head) {
        No *prox = head->prox;
        free(head);
        head = prox;
    }
}

int main(void) {
    No *lista = NULL;
    lista = inserir_fim(lista, 10);
    lista = inserir_fim(lista, 20);
    lista = inserir_fim(lista, 30);
    imprimir(lista);
    liberar(lista);
    return 0;
}

Passo a passo

  1. Alocamos um novo nó com malloc e definimos seu valor e prox = NULL.
  2. Se a lista está vazia (head == NULL), retornamos o novo nó como nova cabeça.
  3. Caso contrário, usamos atual para percorrer a lista até o último nó (quando atual->prox == NULL).
  4. Ligamos o último nó ao novo: atual->prox = novo.
  5. Retornamos head (a cabeça não mudou).
  6. No main, chamamos inserir_fim três vezes e imprimimos.
  7. Por fim, liberamos a memória com liberar.

Por que funciona

A função percorre a lista até o final e conecta o novo nó ao último, mantendo a cabeça inalterada. Isso garante que a lista permaneça encadeada corretamente. A alocação dinâmica permite que a lista cresça em tempo de execução.

Erros comuns

  • Esquecer de inicializar novo->prox = NULL: se não fizer, o último nó pode apontar para lixo, causando comportamento indefinido na impressão.
  • Não tratar lista vazia: se head for NULL e você tentar atual->prox, ocorre erro de segmentação.
  • Não retornar a cabeça: em listas vazias, a nova cabeça é o novo nó; esquecer de retornar novo faz a lista se perder.
  • Vazamento de memória: não liberar os nós ao final do programa.

Outra forma de resolver

Usar um ponteiro para ponteiro (No **head) para modificar a cabeça diretamente, evitando retorno. Exemplo:

void inserir_fim(No **head, int valor) {
    No *novo = malloc(sizeof(No));
    novo->valor = valor;
    novo->prox = NULL;
    No **pp = head;
    while (*pp) pp = &(*pp)->prox;
    *pp = novo;
}

Essa abordagem é preferível quando se deseja modificar a lista sem retornar o novo ponteiro.

Saída esperada

10 -> 20 -> 30 -> NULL