Menu
Coddy logo textTech

Cópia Profunda

Parte da seção Object Oriented Programming do Journey de C da Coddy — lição 15 de 61.

Quando você atribui uma struct a outra em C, você obtém uma cópia rasa (shallow copy)—todos os campos são copiados byte a byte. Isso funciona bem para valores simples como inteiros, mas cria um problema com ponteiros: ambas as structs acabam apontando para a mesma memória.

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // Cópia rasa!
// Tanto alice.name quanto copy.name apontam para a MESMA string

Se você liberar um, o outro se torna inválido. Se você modificar a string por meio de um, ambos verão a mudança. Isso raramente é o que você deseja.

Uma cópia profunda (deep copy) aloca nova memória para membros de ponteiro e copia os dados reais:

Person *clone_person(const Person *original) {
    Person *copy = malloc(sizeof(Person));
    copy->name = malloc(strlen(original->name) + 1);
    strcpy(copy->name, original->name);
    copy->age = original->age;
    return copy;
}

Agora cada objeto possui sua própria string. Você pode modificar ou liberar um sem afetar o outro. O padrão é simples: para cada membro ponteiro, aloque nova memória e copie o conteúdo — não apenas o endereço.

challenge icon

Desafio

Fácil

Vamos construir um módulo Student que demonstra o padrão de cópia profunda (deep copy). Você criará uma função de clonagem que produz uma cópia completamente independente de um objeto de estudante — uma em que a modificação ou a liberação do original não tenha efeito sobre o clone.

Você criará três arquivos:

  • student.h: Declare uma struct Student com dois membros: char *name (uma string alocada dinamicamente) e int grade. Declare três funções:
    • create_student — construtor que recebe um nome e uma nota, retornando um ponteiro para um novo Student
    • clone_student — recebe um const Student * e retorna um ponteiro para uma nova cópia independente
    • free_student — destrutor que libera adequadamente toda a memória alocada
    Use guards de inclusão com o símbolo STUDENT_H.
  • student.c: Implemente as três funções. Sua função clone_student é a chave — ela deve alocar memória nova tanto para a struct quanto para a string de nome, e então copiar os dados reais da string (não apenas o endereço do ponteiro). Isso garante que o clone possua sua própria memória, completamente separada do original.
  • main.c: Crie um estudante, clone-o, exiba as informações de ambos os estudantes e, em seguida, limpe adequadamente ambos os objetos.

Você receberá duas entradas: o nome do estudante (uma string) e a nota (um inteiro).

No seu arquivo principal, crie um estudante com os valores fornecidos e, em seguida, crie um clone desse estudante. Imprima as informações do original e do clone para verificar se eles contêm os mesmos dados. Por fim, libere ambos os estudantes e imprima uma confirmação.

Imprima a saída neste formato:

Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freed

Por exemplo, com as entradas Alice e 95, a saída seria:

Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freed

O padrão de cópia profunda garante que cada objeto seja verdadeiramente independente — o clone tem sua própria string alocada, não um ponteiro compartilhado para a memória do original.

Folha de consulta

Quando você atribui uma struct a outra em C, você obtém uma cópia rasa (shallow copy)—todos os campos são copiados byte a byte. Com ponteiros, ambas as structs acabam apontando para a mesma memória:

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // Cópia rasa!
// Tanto alice.name quanto copy.name apontam para a MESMA string

Uma cópia profunda (deep copy) aloca nova memória para membros de ponteiro e copia os dados reais:

Person *clone_person(const Person *original) {
    Person *copy = malloc(sizeof(Person));
    copy->name = malloc(strlen(original->name) + 1);
    strcpy(copy->name, original->name);
    copy->age = original->age;
    return copy;
}

O padrão de cópia profunda: para cada membro de ponteiro, aloque memória nova e copie o conteúdo—não apenas o endereço. Isso garante que cada objeto possua sua própria memória e possa ser modificado ou liberado de forma independente.

Experimente você mesmo

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

int main() {
    char name[100];
    int grade;
    
    // Ler entrada
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: Criar um estudante com o nome e a nota fornecidos
    
    // TODO: Criar um clone do estudante
    
    // TODO: Imprimir as informações do estudante original
    // Formato: "Original: {name}, Grade: {grade}"
    
    // TODO: Imprimir as informações do clone
    // Formato: "Clone: {name}, Grade: {grade}"
    
    // TODO: Liberar ambos os estudantes
    
    // Imprimir confirmação
    printf("Both freed\n");
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming