Προς το περιεχόμενο

malloc & free


sonyxp

Προτεινόμενες αναρτήσεις

κανω free τον πινακα μου αλλα οταν παω να τον εκτυπωσω βλεπω οτι τα στοιχεια ειναι ακομα εκει :(

#include <stdio.h>
#include <malloc.h>

#define N 5
struct
{
	int *myInt;
}myStruct;

void main()
{
	myStruct *mys;
	mys = (myStruct *)malloc(sizeof(myStruct));
	if (!mys) exit(1);
	
	mys->myInt = (int *)malloc(sizeof(int) * (N*N));
	if (!mys->myInt) exit(1);
	
	for (int i=0; i<N; i++)
		for (int j=0; j<N; j++)
			mys->myInt[i*N+j] = rand() % 10;
			
	if (!mys) free(mys);
	if (!mys->myInt) free(mys->myInt);
	
	/* Afou ekana free thn mnhmh panw, pos ginete o katw 
	kwdikas na mou deixnei ta stoixeia tou pinaka? */
	for (int i=0; i<N; i++)
	{
		for (int j=0; j<N; j++)
		{
			printf("%d ", mys->myInt[i*N+j]);
		}
		printf("\n");
	}
	
}
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 63
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Συχνή συμμετοχή στο θέμα

μήπως κάνεις με ανάποδη σειρά τα

if (!mys) free(mys);
if (!mys->myInt) free(mys->myInt);
και επίσης μήπως κάνεις free μόνο το null? βάλε:

if (mys->myInt) free(mys->myInt);
if (mys) free(mys);
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Κατ αρχήν, οι δύο if που έχουν σαν body τη free() δεν εκτελούνται.

Κατά δεύτερον κανείς ανάποδα την αποδέσμευση. Πρώτα πρέπει να απελευθερώσεις τα "εσωτερικά" στοιχεία της struct και μετά την ίδια τη μεταβλητή τύπου struct.

(ως εδώ αυτά τα έχει πει κι ο φίλος παραπάνω).

 

Όμως, το ότι κανείς free() ένα κομμάτι μνήμης δε σημαίνει ότι τα περιεχόμενα της μνήμης σβήνουν (ή τέλος πάντων μηδενίζουν ή ακυρώνονται). Αυτό γίνεται καθαρά για λόγους ταχύτητας -αν και "θυσιάζουμε" την ασφάλεια-.

Εφ όσον αυτή τη μνήμη τη χρησιμοποίησες, μετά υποτίθεται ότι κάποιο άλλο πρόγραμμα (ή ακόμα και το ίδιο) θα την ξαναζητήσει για να γράψει σ αυτή, άρα δεν υπάρχει λόγος να σβηστεί το περιεχόμενό της.

Τέλος να σου πω ότι είναι πολύ καλή πρακτική μετά την free() να θέτουμε τον pointer ίσο με NULL -για προφανείς λόγους. Πχ τον έχεις κάνει free(), αλλά έχεις bug στον κώδικά σου και τον χρησιμοποιείς πάλι, αν είσαι τυχερός θα φας segmentation fault, αν όμως δεν είσαι θα νομίζεις ότι είναι μια χαρά ο κώδικας ώσπου να κάνει μπουμ-

  • Like 1
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

/* Afou ekana free thn mnhmh panw, pos ginete o katw

    kwdikas na mou deixnei ta stoixeia tou pinaka? */

 

Καταρχήν ο,τι κι αν κάνει ή δεν κάνει η free() εσύ κάτι θα δεις με τον κώδικα που έγραψες (μνήμη είναι, πάντα κάτι περιέχει -- δε μπορεί να είναι "άδεια").

 

Οπότε η ερώτηση είναι "γιατί βλέπω τις τιμές που υπήρχαν απο πριν σε κείνη την περιοχή της μνήμης αντί να βλέπω.... X?". Άρα, πες μας πρώτα ποιό είναι το Χ. Και μετά σκέψου γιατί να είναι Χ και να μην είναι Υ. Ή γιατί να μην είναι Ζ, όπου Ζ = "αυτά που υπήρχαν απο πριν".

 

Πέρα απ' αυτό, η ερώτηση που κάνεις έχει στη γενική περίπτωση κι ένα ακόμα πρόβλημα: αυτό που βλέπεις εσύ δεν είναι "αυτό που κάνει η free". Είναι αυτό που κάνει η free() όπως είναι υλοποιημένη στη συγκεκριμένη standard library που χρησιμοποιεί η συγκεκριμένη version του συγκεκριμένου compiler στο συγκεκριμένο λειτουργικό σύστημα. Αν κάποιο τμήμα της συμπεριφοράς της free() αφήνεται ελεύθερο στην κρίση της υλοποίησης, αυτό που θα δεις θα είναι η κρίση της υλοποίησης η οποία βέβαια δεν είναι παγκόσμια σταθερά.

 

Αφού τα σκεφτείς όλα αυτά, η απάντηση στην ερώτησή σου είναι: ορίστε η περιγραφή της free() από το κείμενο του standard της C99:

 

 

The free function causes the space pointed to by ptr to be deallocated, that is, made

available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if

the argument does not match a pointer earlier returned by the calloc, malloc, or

realloc function, or if the space has been deallocated by a call to free or realloc,

the behavior is undefined.

 

 

Άρα, τα περιεχόμενα της μνήμης πρέπει να παραμένουν απείραχτα γιατί ο ορισμός του τι πρέπει να κάνει η free δεν αναφέρει τίποτα σχετικά μ' αυτά.

 

Επίσης δες εδώ: http://stackoverflow.com/questions/1287180/why-doesnt-free-zero-out-the-memory-prior-to-releasing-it

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

[ Αν δε κάνω λάθος συμβαίνει το παρακάτω ]

 

Το ότι κάνεις free δε σημαίνει ότι θα πάει να γράψει κάτι άλλο στο χώρο που είχες. 

 

Σημαίνει ότι ο χώρος αυτός θα είναι πλέον διαθέσιμος να αποδοθεί αλλού, σε μία άλλη malloc σε κάτι άλλο γενικά. ώστε να "γραφτεί" κάτι άλλο σε αυτόν.

 

Ελευθερώνω δε σημαίνει σβήνω.

(Που επίσης σβήνω δε σημαίνει κάτι για τον υπολογιστή. Θέλω να πω εσύ λέγοντας σβήνω περιμένεις - δε ξέρω - να έχει γεμίσει με 0 ο χώρος που είχες. Όμως αυτό είναι μια δική σου σύμβαση).

 

Τώρα, μετά το free εσύ έχεις φυλάξει τη διεύθυνσή του και απλά το προσπελαύνεις ξανά.

Δεν είναι πλέον δεσμευμένος αλλά αφού δεν έχει τύχει μέχρι στιγμής να δεσμευτεί αλλού αφενός δεν τρως πόρτα και αφ εταίρου τυχαίνει να παραμένουν τα στοιχεία που έχεις πριν εκεί. Αυτό όμως δεν είναι μια σταθερή συμπεριφορά στην οποία μπορείς να επενδύσεις.

 

 

TIP: Αν για παράδειγμα έγραφες μια εφαρμογή που είχε πολύ ευαίσθητα δεδομένα στη μνήμη, θα μπορούσες πριν το free να τα "καθαρίζεις" (γράφεις κάτι άλλο σε αυτά) χειροκίνητα ώστε να αποφύγεις τυχών κακόβουλους "αναγνώστες'.

 

EDIT: Με πρόλαβαν οι παραπάνω. Με καλύπτουν απόλυτα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Περίμενα να μου εκτυπώσει τις διευθύνσεις μνήμης αντί των προηγούμενων τιμών.

 

Έκανα και αυτό με το NULL (mys = NULL) μετά το free αλλά μετά χτυπάει στο printf

 

*Ίσως φταεί που ενώ έχω αποδευσμευμέσει τον πίνακα προσπαθώ να τον περάσω σε μια συνάρτηση για να τον εκτυπώσω, αφού δεν υπάρχει πλεον!



όσον αφορά το

if (mys) {  }

νομίζω, νόμιζα ότι είναι ιδιο με

If (mys != NULL) {   }

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

...

όσον αφορά το

if (mys) {  }
νομίζω, νόμιζα ότι είναι ιδιο με

If (mys != NULL) {   }

 

Η απάντηση του nilos.gr είναι σφαιρική κι εύστοχη. Τα 2 σου if () free() δεν εκτελούνται ποτέ γιατί όταν οι συνθήκες τους είναι αληθείς έχεις κάνει ήδη exit() νωρίτερα σύμφωνα με τον κώδικα που παρέθεσες.

 

Btw, για τη νέα σου ερώτηση, το if ( !msys ) στην C ισοδυναμεί με if ( NULL == msys ).

 

@albNik: Στην C το NULL δεν είναι απαραίτητα ίσο με 0... παρόλο που στις περισσότερες υλοποιήσεις είναι (για την ακρίβεια είναι implementation defined, αν θυμάμαι καλά). Επίσης αν το θυμάμαι σωστά, στην C++ είναι όντως ίσο με 0 το NULL ... στην C++11 εισήγαγαν το nullprt

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ότι να ναι, όταν κάνω Debug φαίνεται ότι δουλεύει μια χαρά, όταν κάνω Release το project και τρέξω το exe τότε κρατάει τις παλιές τιμές...

 

 

 

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

#define N 5

struct myStruct
{
	int *Array;
};

void Create(int *myArray);
void Print(int *myArray);
void Deallocate(int *item);

void main()
{
	// Space allocation
	myStruct *mys;
	mys = (myStruct *)malloc(sizeof(myStruct));
	if (mys == NULL) 
		exit(1);

	mys->Array = (int *)malloc(sizeof(int) * (N *N));
	if (mys->Array == NULL) 
		exit(1);

	// Initial Array Values & Print
	Create(mys->Array);
	Print(mys->Array);

	// Deallocate space & Print again
	Deallocate(mys->Array);
	Print(mys->Array);

	for(int i=0; i<N; i++)
		for(int j=0; j<N; j++)
			printf("Address %d Value %d\n", &(mys->Array[i*N+j]), mys->Array[i*N+j]);
}

void Create(int *myArray)
{
	for(int i=0; i<N; i++)
		for(int j=0; j<N; j++)
			myArray[i*N+j] = 0;
}

void Print(int *myArray)
{
	for(int i=0; i<N; i++)
	{
		for(int j=0; j<N; j++) {
			printf("%d ", myArray[i*N+j]);
		}
		printf("\n");
	}
	printf("\n");
}
void Deallocate(int *item)
{
	if (item != NULL)
		free(item);
}

 



debug_release.png

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ότι να ναι, όταν κάνω Debug φαίνεται ότι δουλεύει μια χαρά, όταν κάνω Release το project και τρέξω το exe τότε κρατάει τις παλιές τιμές...

 

Συγγνώμη, δεν διάβασες απολύτως τίποτα από όσα σου γράψαμε σε όλα τα προηγούμενα μηνύματα;

 

 

 

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

#define N		5
#define M		(N) * (N)

#define DEBUG		1
#define RELEASE		!(DEBUG)

/* ------------------------------------------------- */
void print( int *array, int debug )
{
	if ( !array )
		return;

	for (int i=0; i < M; i++)
	{
		if ( i % N == 0 )
			putchar( '\n' );

		if ( debug )
			printf( "0x%x:%d ", &array[i], array[i] );
		else 
			printf( "%d ", array[i] );
	}
	putchar('\n');
}
/* ------------------------------------------------- */
void dealloc( int **array )
{
	if ( array && *array ) {
		free( *array );
		*array = NULL;
	}
}
/* ------------------------------------------------- */
int main( void )
{
	int *array = NULL;

	array = calloc( M, sizeof(int) );
	if ( NULL == array ) 
		exit(1);

	print( array, RELEASE );
	print( array, DEBUG );

	dealloc( &array );

	system( "pause" );  /* Windows only */
	exit(0);
}

// Έξοδος:

0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

0x3e2c90:0 0x3e2c94:0 0x3e2c98:0 0x3e2c9c:0 0x3e2ca0:0
0x3e2ca4:0 0x3e2ca8:0 0x3e2cac:0 0x3e2cb0:0 0x3e2cb4:0
0x3e2cb8:0 0x3e2cbc:0 0x3e2cc0:0 0x3e2cc4:0 0x3e2cc8:0
0x3e2ccc:0 0x3e2cd0:0 0x3e2cd4:0 0x3e2cd8:0 0x3e2cdc:0
0x3e2ce0:0 0x3e2ce4:0 0x3e2ce8:0 0x3e2cec:0 0x3e2cf0:0
Press any key to continue . . .

 

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Ότι να ναι, όταν κάνω Debug φαίνεται ότι δουλεύει μια χαρά, όταν κάνω Release το project και τρέξω το exe τότε κρατάει τις παλιές τιμές...

 

debug_release.png

Έχεις δει ένα μπλουζάκι που λέει "Undefined behavior is undefined" ? :)

 

Όπως σου εξήγησαν και τα άλλα παιδιά δεν πρέπει να προσπελάσεις ένα δείκτη αφού τον έχεις κάνει free (και δεν πρέπει να τον ξανακάνεις free όπως λέει το τμήμα του προτύπου που έδωσε ο defacer) οπότε μπορείς να δεις οποιαδήποτε συμπεριφορά. Όταν πέφτουμε σε αόριστη συμπεριφορά όχι μόνο διαφορά ανάμεσα σε Release και Debug μπορούμε να δούμε αλλά ο compiler είναι ελεύθερος να δίνει διαφορετικό αποτέλεσμα με κάθε compile που κάνεις.

 

Πάντα μετά το free να κάνεις τον pointer NULL.Διαφορετικά  εμφανίζονται bugs εκεί που δεν το περιμένεις

Και εγώ αυτής της άποψης είμαι (ότι δηλαδή του θέτω πάντα NULL) αλλά είναι αμφισβητήσιμο θέμα. Η άλλη πλευρά λέει ότι έτσι κρύβονται bugs και αν δεν θέσεις NULL θα βαρέσει segmentation fault οπότε θα καταλάβεις ότι ο αλγόριθμος είναι λάθος.

 

 

@albNik: Στην C το NULL δεν είναι απαραίτητα ίσο με 0... παρόλο που στις περισσότερες υλοποιήσεις είναι (για την ακρίβεια είναι implementation defined, αν θυμάμαι καλά). Επίσης αν το θυμάμαι σωστά, στην C++ είναι όντως ίσο με 0 το NULL ... στην C++11 εισήγαγαν το nullprt

 

Ασχέτως όμως με το πως υλοποιείται το NULL, η έκφραση που έδωσε ο albNik είναι σωστή. Όπως έχουμε πει και σε άλλο νήμα, η έκφραση 0 σε αυτή την περίπτωση δεν συμβολίζει τον αριθμό 0 (δηλαδή μια τιμή με όλα τα bit 0) αλλά τον "μηδενικό δείκτη". Ο compiler είναι υποχρεωμένος να παράξει τον κώδικα που χρειάζεται ώστε να γίνεται σύγκριση με τον "μηδενικό δείκτη" ανεξάρτητα πως υλοποιείται αυτός. Σε μια πλατφόρμα που έχουμε την διεύθυνση 54391 για null pointer, η έκφραση του albNik "if (tade != 0)" είναι σωστή ενώ η έκφραση "if (tade != 54391)" είναι λάθος.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

...

 

Και εγώ αυτής της άποψης είμαι (ότι δηλαδή του θέτω πάντα NULL) αλλά είναι αμφισβητήσιμο θέμα. Η άλλη πλευρά λέει ότι έτσι κρύβονται bugs και αν δεν θέσεις NULL θα βαρέσει segmentation fault οπότε θα καταλάβεις ότι ο αλγόριθμος είναι λάθος.

 

Αν τον θέσεις σε NULL θα βαρέσει σίγουρα seg-fault. Αν δεν τον θέσεις, μπορεί να βαρέσει μπορεί και όχι.

 

Ασχέτως όμως με το πως υλοποιείται το NULL, η έκφραση που έδωσε ο albNik είναι σωστή. Όπως έχουμε πει και σε άλλο νήμα, η έκφραση 0 σε αυτή την περίπτωση δεν συμβολίζει τον αριθμό 0 (δηλαδή μια τιμή με όλα τα bit 0) αλλά τον "μηδενικό δείκτη". Ο compiler είναι υποχρεωμένος να παράξει τον κώδικα που χρειάζεται ώστε να γίνεται σύγκριση με τον "μηδενικό δείκτη" ανεξάρτητα πως υλοποιείται αυτός. Σε μια πλατφόρμα που έχουμε την διεύθυνση 54391 για null pointer, η έκφραση του albNik "if (tade != 0)" είναι σωστή ενώ η έκφραση "if (tade != 54391)" είναι λάθος.

Δεν είμαι σίγουρος πως ισχύει το παραπάνω που γράφεις, ότι δηλαδή είναι σωστό σε όλους τους compilers το if (tade != 0) με το τάδε να είναι δείκτης (αλλά βαριέμαι τώρα να το ψάξω). Το if (tade != NULL) όμως είμαι σίγουρος 100% πως είναι σωστό.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Undefined Behaviour (UB) <=> Expect the Unexpected.

 

Eνα λεπτο ρε παιδιά το if( something ) για παράδειγμα δεν εξετάζει αν το something έχει μη μηδενική τιμή ωστε να εκτελέσει το σώμα του if? Σας έχασα λιγο....

 
if ( something ) <=> if ( something!= 0 )
if ( !something ) <=> if ( something == 0 )
Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αν τον θέσεις σε NULL θα βαρέσει σίγουρα seg-fault. Αν δεν τον θέσεις, μπορεί να βαρέσει μπορεί και όχι.

Ναι αν προσπελάσεις τον δείκτη και είναι NULL θα βαρέσει. Δεν το εξήγησα καλά. Εννοούσα την περίπτωση που στον κώδικα κάνεις από λάθος ξανά free το οποίο θα επιτύχει σε NULL (χωρίς φυσικά να κάνει τίποτα) ενώ θα βαρέσει double free σε άλλη περίπτωση.

 

Δεν είμαι σίγουρος πως ισχύει το παραπάνω που γράφεις, ότι δηλαδή είναι σωστό σε όλους τους compilers το if (tade != 0) με το τάδε να είναι δείκτης (αλλά βαριέμαι τώρα να το ψάξω). Το if (tade != NULL) όμως είμαι σίγουρος 100% πως είναι σωστό.

Αν ο εν λόγω compiler υλοποιεί την C τότε είναι σωστό μια και το λέει το πρότυπο :P (επίσης μην ξεχνάς ότι το NULL είναι macro οπότε ο compiler θα δει έτσι και αλλιώς το μηδέν).

An integer constant expression with the value 0, or such an expression cast to type

void *, is called a null pointer constant. If a null pointer constant is converted to a

pointer type, the resulting pointer, called a null pointer, .......

Η χρήση του 0 είναι απολύτως σωστή και ακριβώς το ίδιο με τη χρήση NULL. Το NULL έχει μόνο ένα πλεονέκτημα έναντι του 0 (που μου έρχεται τώρα στο μυαλό τουλάχιστον) και αυτό μόνο σε C compilers. Όταν έχουμε μια συνάρτηση με μεταβλητό αριθμό παραμέτρων που τελειώνουν με NULL, τότε αν χρησιμοποιήσουμε 0 μπορεί να το μπερδέψει με μια ακέραια μεταβλητή και να μη καταλάβει ότι εκεί τελειώνουν οι παράμετροι ενώ με το (void *)0 δεν υπάρχει τέτοιο πρόβλημα. Ως (void *)0 όμως ορίζεται το NULL μόνο σε C και όχι σε C++.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...