|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Junior Member
Iscritto dal: Sep 2008
Messaggi: 28
|
[C++]Niubbo: Stringhe e malloc
Sto provando a capire come funzionano le operazioni su stringhe in C++ e non ho le idee molto chiare, soprattutto sulla deallocazione.
Nel mio programmino ho: Codice:
#define STRINGA2 "test"
#define STRINGA1 "mio"
#define ALTRO "prova"
// funziona che concatena le stringhe
char* concatena(char* stringa1)
{
char* ret = (char*) malloc(sizeof(char)*256);
strcpy(ret,stringa1);
strcat(ret,STRINGA2);
return ret;
}
// funzione esterna che ritorna una stringa
char* faAltro(char* st1,char* st2)
{
...
}
// funzione che ne richiama un'altra e dal risultato ottenuto fa un confronto
bool miaFunz(char* ret)
{
char* out = (char*)malloc(sizeof(char)*128);
FunzioneEsterna(NULL,NULL,out);
if(strcmp(out,ret)==0)
return true;
else return false;
}
void MiaClasse::testa()
{
char* ret = (char*) malloc (sizeof(char)* 1024);
ret = faAltro(concatena(STRINGA1),ALTRO);
if(strcmp(ret,"-1")==0) || (miaFunz2(ret)==false))
{
throw miaException("Errore");
}
}
Il tutto funziona, ma: 1- non so se è il modo corretto; 2- dove deallocare la memoria allocata con "malloc"? |
|
|
|
|
|
#2 |
|
Junior Member
Iscritto dal: Sep 2009
Messaggi: 15
|
Rispondo al secondo punto. Sì, è buona norma liberare la memoria allocata dalla funzione malloc(). Questo perché lo spazio di memoria che hai riservato è persistente, cioè continuerà ad essere riservato fino alla chiusura del programma. Per liberare la memoria dovresti usare la seguente funzione:
void free(void *p); Quindi appena la memoria non ti serve più, un bel free() e sei a posto. In questo particolare caso, dato che il programma è molto breve e semplice, puoi anche non liberare la memoria (oramai ogni PC ha più di 1 Gb di RAM... più che abbondante, quindi liberare la memoria per così poco è pressocché inutile). Ricordati di includere la libreria C... #include<cstdlib> Ultima modifica di Bezelis : 18-09-2009 alle 11:17. |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
il titolo del thread dice tutto: mi pare giusto, i niubbi in C++ allocano le stringhe usando malloc
in C++ non si usano malloc e free, si usano new e delete! ![]() e l'allocazione dello spazio di memoria necessario a tenere una stringa non la si fa manualmente, la si lascia alla classe std::string. |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
riscrivo il programma in vero C++ (non l'ho testato peró).
Codice:
#include <string>
using namespace std;
const char *STRINGA2 = "test";
const char *STRINGA1 = "mio";
const char *ALTRO = "prova";
// funzione che concatena le stringhe
string concatena(const string &stringa1)
{
return stringa1 + STRINGA2;
}
// funzione esterna che ritorna una stringa
string faAltro(string &st1, string &st2)
{
...
}
// funzione che ne richiama un'altra e dal risultato ottenuto fa un confronto
bool miaFunz(const string &ret)
{
string out;
FunzioneEsterna(NULL,NULL,out);
return out == ret;
}
void MiaClasse::testa()
{
string ret = faAltro(concatena(STRINGA1),ALTRO);
if((ret == "-1") || !miaFunz2(ret))
{
throw miaException("Errore");
}
}
|
|
|
|
|
|
#5 |
|
Junior Member
Iscritto dal: Sep 2009
Messaggi: 15
|
Vero. Però potrebbe voler studiare le due funzioni C, del tutto compatibili col C++ (sempre che includa le librerie appropriate). Se decidesse, per alcuni semplici problemi, di utilizzare la programmazione procedurale piuttosto che quella orientata ad oggetti, niente da dire.
Ho semplicemente risposto alla sua domanda: Dove deallocare la memoria allocata con "malloc"? |
|
|
|
|
|
#6 | ||
|
Junior Member
Iscritto dal: Sep 2008
Messaggi: 28
|
Quote:
Codice:
void MiaClasse::testa()
{
char* ret = (char*) malloc (sizeof(char)* 1024);
ret = faAltro(concatena(STRINGA1),ALTRO);
if(strcmp(ret,"-1")==0) || (miaFunz2(ret)==false))
{
throw miaException("Errore");
}
if(ret!=NULL) )free(ret); //-->crash
}
Quote:
Però poi anche le funzioni esterne accettano char* e non std:string. Devo fare la conversione ogni volta? Però a questo punto vorrei comunque capire come usare malloc e free |
||
|
|
|
|
|
#7 | |||
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
Quote:
Quote:
Codice:
string str = "ciao"; const char *sz = str.c_str(); Quote:
|
|||
|
|
|
|
|
#8 | ||
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
Quote:
Quote:
|
||
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
mi correggo:
a parte naturalmente la sintassi diversa visto che malloc e free sono due funzioni mentre new e delete sono due operatori, in realtá c'é una differenza semantica importante tra malloc e new: in caso di risorse di sistema insufficienti malloc restituisce NULL, mentre il comportamento di new é configurabile ma di default viene lanciata un'eccezione che adesso non ricordo qual é; la conseguenza dell'eccezione é il crash del programma a meno che non la si catturi e la si gestisca. io in genere preferisco sempre mettermi l'anima in pace e lasciare andare qualunque potenziale eccezione lanciata da new: la mia politica di programmazione é che se il sistema é talmente intasato da non potermi allocare la mia memoria tanto vale che il mio programma si chiuda, cosi libero anche un po' di risorse al sistema.
|
|
|
|
|
|
#10 | |
|
Junior Member
Iscritto dal: Sep 2008
Messaggi: 28
|
Quote:
Codice:
char* faAltro(char* a,char* b)
{
char* a1 = (char*) malloc(sizeof(char)*256);
(//...codice)
int size=strlen(b);
return funcB(a1,size);
}
char* funcB(char* a, int size)
{
static char* aaa = "provaprova";
if (size <= 0)
return "";
char * ret = (char*) malloc(sizeof(char)*size+1);
for (int i = 0; i<size; i++)
{
ret[i] = 'a'; // in realtà fa altro, ma non è importante
}
ret[size]='\0';
return ret;
}
Cambia qualcosa? |
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
senti, facciamo una cosa?
![]() posta il sorgente completo e disinfestato da qualunque possibile codice di prova; dopodiché vediamo perché crasha PS: "sizeof(char)*size+1" non ha senso, primo perché sizeof restituisce la dimensione di un certo tipo espressa in char (quindi fa sempre 1) e secondo perché non ha senso calcolare lo spazio di size caratteri piu un byte, semmai dovrebbero essere (size+1) caratteri. Ultima modifica di fero86 : 18-09-2009 alle 17:02. |
|
|
|
|
|
#12 | ||
|
Registered User
Iscritto dal: May 2009
Messaggi: 300
|
Quote:
Quote:
|
||
|
|
|
|
|
#13 | |
|
Registered User
Iscritto dal: May 2009
Messaggi: 300
|
Quote:
Codice:
void *malloc(size_t size); RISULTATO un puntatore al buffer di memoria allocato. E' NULL se size è uguale a zero. E' NULL con size diverso da zero se non è stato possibile allocare size bytes. Codice:
void *calloc(size_t nmemb, size_t size); size è il numero di bytes che si tenta di allocare per ogni elemento. RISULTATO un puntatore al buffer di memoria allocato. E' NULL se size o nmemb è uguale a zero. E' NULL con size ed nmemb diversi da zero se non è stato possibile allocare nmemb*size bytes. Codice:
void free(void *ptr); ------------------------------------ Non so qual è il tuo grado di preparazione sul C, non mi sembra troppo approfondito, quindi cercherò di essere completo. void* è un "generico" puntatore: punta ad un'area di memoria la quale non si sa bene come interpretarla. Ad esempio: void* numero_intero = malloc(4); Quei 4 byte allocati il compilatore non sa che roba sono, può essere un int, ma possono essere anche 4 char messi a formare un array. Insomma il void* essendo generico va gestito con un "cast": int* intero = (int*)malloc(sizeof(int)); *intero = 100; In questo modo il risultato della malloc viene cast-ato in un int*. Adesso ho un puntatore ad un'area di memoria. Ad esempio ho un foglietto con sopra scritto "LIBRO x PAG y" riuscirò sempre a trovare l'informazione che voglio. Se però tu mi fai: int altro_intero = 5; intero = &altro_intero; Cosa hai fatto? Hai buttato il "bigliettino" e scritto un altro che adesso punta a "LIBRO x PAG z", ovvero punta ad un'altra zona di memoria. E la zona di memoria di prima che fine fa? Sta là che aspetta di essere usata ma tu non la userai mai perchè hai perso l'unico "bigliettino" che ti permetteva di raggiungerla. Ancora peggio non potrai nemmeno deallocare quell'area di memoria che resterà lì inutilizzata per tutta l'esecuzione del programma. Queste aree perdute (non più raggiungibili) sono dette "garbage". In JAVA non è un problema perchè esiste un "programma" apposito (garbage collector) che periodicamente controlla e dealloca queste aree di memoria perduta. In C/C++ è una delle cose peggiori che puoi fare... Veniamo alla free. La free la devi fare sempre. Tu considera che se hai N malloc/calloc dovrai avere anche N free. Attenzione quando passi l'argomento alla free. Se gli passi un puntatore ad un'area di memoria allocata con malloc/calloc tutto va bene. Se gli passi NULL va bene uguale perchè tanto non fa niente. Ma se fai una cosa del genere che succede? int* intero; free(puntatore); In questo caso intero non essendo inizializzato contiene un valore "casuale". Pertanto punta da qualche parte in memoria chissà dove. Ci sono varie possibilità: 1) Hai fortuna vale NULL... tutto OK; 2) Meno fortuna hai azzeccato il punto in cui tieni memorizzato il tuo lavoro di una vita e sta per essere deallocato all'istante; 3) Punta ad un'area riservata/non allocata e il programma ti crasha con il più odiato dei "segmentation faul". Adesso ti toccherà cercare il punto in cui è crashato tra le tue 200.000 righe di codice... tanti auguri! Un altro caso è: int* intero = (int*)malloc(sizeof(int)); *intero = 100; free(intero); free(intero); Alla seconda free vai a deallocare una zona già deallocata quindi ti riconduci dritto dritto al precedente punto 3!!! Ultima modifica di Ikon O'Cluster : 19-09-2009 alle 02:44. |
|
|
|
|
|
|
#14 | |||||
|
Senior Member
Iscritto dal: Oct 2006
Città: Roma
Messaggi: 1383
|
a questo ci pensa il runtime del mio compilatore. forse in Visual C++ é anche possibile implementare un hook per eccezioni non gestite che richieda al sistema di generare il crash dump cosi che l'utente lo possa inviare agli sviluppatori, dovrei documentarmi.
Quote:
1) si tratta di un'eventualitá rarissima; 2) molto prima ancora é una questione di ingegneria del software: il non dover controllare ogni singola allocazione dinamica semplifica considerevolmente il codice. Quote:
![]() Quote:
Quote:
Codice:
int main()
{
while (true)
{
new int[0x1000];
}
}
Quote:
PS: vuoi provare il vero brivido? eccotelo: in Java il fallimento di un'allocazione di memoria provoca un'eccezione come in C++, anzi no, peggio, provoca un errore: http://java.sun.com/javase/6/docs/ap...moryError.html solo che a differenza del C++ in Java la cosa non é configurabile: quando programmi in Java puoi farlo con la consapevolezza che in moltissimi punti dell'esecuzione il tuo programma potrebbe crashare per motivi al di fuori del tuo controllo e tu non sei nemmeno in grado di salvare il lavoro dell'utente (cosa che in C++ invece puoi fare benissimo all'interno di un distruttore). o meglio, in teoria potresti circondare con blocchi try-finally ogni singolo uso dell'operatore new ed ogni singola chiamata a metodi esterni al tuo codice (compresi quelli della libreria standard) visto che non sai chi di loro chiama new, ma tu lo fai? no che non lo fai, e fai bene a non farlo perché é irragionevole. allora potresti mettere un try-finally intorno all'entry point di ogni tuo thread, quindi nel metodo main e in ogni metodo run di Runnable o di Thread; e se l'errore salta mentre stai nell'EDT di Swing? o, analogamente, nel contesto di un thread creato da codice esterno? |
|||||
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 20:41.





















