Copia profonda
Fa parte della sezione Programmazione orientata agli oggetti del percorso C di Coddy. Lezione 15 di 61.
Quando assegni una struct a un'altra in C, ottieni una copia superficiale: tutti i campi vengono copiati byte per byte. Funziona bene per valori semplici come gli interi, ma crea un problema con i puntatori: entrambe le struct finiscono per puntare alla stessa memoria.
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Copia superficiale!
// Sia alice.name sia copy.name puntano alla STESSA stringa
Se ne liberi uno, l'altro diventa non valido. Se modifichi la stringa tramite uno dei due, entrambi vedono la modifica. Raramente è ciò che vuoi.
Una copia profonda alloca nuova memoria per i membri puntatore e copia i dati effettivi:
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;
}
Ora ogni oggetto possiede la propria stringa. Puoi modificarne o liberarne una senza influire sull’altra. Il modello è semplice: per ogni membro puntatore, alloca nuova memoria e copia i contenuti, non solo l’indirizzo.
Sfida
FacileCostruiamo un modulo Student che illustra il modello della copia profonda. Creerai una funzione di clonazione che produce una copia completamente indipendente di un oggetto studente: modificarlo o liberare l'originale non avrà alcun effetto sul clone.
Creerai tre file:
student.h: dichiara una strutturaStudentcon due membri:char *name(una stringa allocata dinamicamente) eint grade. Dichiara tre funzioni:create_student: costruttore che riceve un nome e un voto e restituisce un puntatore a un nuovo Studentclone_student: riceve unconst Student *e restituisce un puntatore a una copia nuova e indipendentefree_student: distruttore che libera correttamente tutta la memoria allocata
STUDENT_H.student.c: implementa tutte e tre le funzioni. La funzioneclone_studentè fondamentale. Deve allocare nuova memoria sia per la struttura sia per la stringa del nome, quindi copiare i dati effettivi della stringa (non solo l'indirizzo del puntatore). In questo modo il clone possiede interamente la propria memoria, completamente separata da quella dell'originale.main.c: crea uno studente, clonalo, visualizza le informazioni di entrambi gli studenti, quindi libera correttamente entrambi gli oggetti.
Riceverai due input: il nome dello studente (una stringa) e il voto (un intero).
Nel file principale, crea uno studente con i valori forniti, quindi crea un clone di quello studente. Stampa le informazioni sia dell'originale sia del clone per verificare che contengano gli stessi dati. Infine, libera entrambi gli studenti e stampa una conferma.
Stampa l'output in questo formato:
Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freedAd esempio, con gli input Alice e 95, l'output sarebbe:
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedIl modello della copia profonda garantisce che ogni oggetto sia davvero indipendente: il clone ha una propria stringa allocata, non un puntatore condiviso alla memoria dell'originale.
Provalo tu
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
int main() {
char name[100];
int grade;
// Leggi l'input
scanf("%s", name);
scanf("%d", &grade);
// TODO: Crea uno studente con il nome e il voto forniti
// TODO: Crea un clone dello studente
// TODO: Stampa le informazioni dello studente originale
// Formato: "Original: {name}, Grade: {grade}"
// TODO: Stampa le informazioni del clone
// Formato: "Clone: {name}, Grade: {grade}"
// TODO: Libera la memoria di entrambi gli studenti
// Stampa la conferma
printf("Both freed\n");
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Basi di programmazione modulare
File di intestazioneGuardie di inclusioneFile sorgenteFunzioni staticheRipasso: calcolatrice modulare4Incapsulamento
Il concetto di puntatori opachiDefinire struct opacheGetter e setterLa convalida nei setterRiepilogo: scatola segreta2Oggetti e metodi
Le struct come oggettiIl puntatore 'Self'Correttezza constPuntatore o valoreMetodi di supportoRiepilogo: gestore di punti5Progetto: Conto bancario semplice
Configurazione del progettoImplementazione del conto8Polimorfismo
Puntatori a funzione nelle structSimulare i metodiIl concetto di interfacciaImplementare le interfacceIterazione polimorficaRiepilogo: Greeter11Pattern di progettazione in C
Pattern SingletonPattern FactoryPattern IteratorRiepilogo: Factory di Logger3Ciclo di vita degli oggetti
Pattern del costruttorePattern del distruttoreInizializzazione sullo stackCopia profondaRiepilogo: wrapper di stringhe6Ereditarietà tramite composizione
Incorporamento delle structLa regola del primo membroAccesso ai membri della classe baseUpcastingRiepilogo: gerarchia di forme9Progetto: Disegnatore di forme
Panoramica del progettoImplementazione del cerchioImplementazione del rettangoloUtilizzo polimorficoContenitore di formeEsercitati da solo: Compilatore C online