Newsgroup: it.comp.lang.c
Titolo: allocazione dinamica della memoria

Salve a tutti. Sto cercando di capire bene come funziona la famiglia delle
funzioni malloc, specificatamente con le stringhe. Il fine è quello di
riuscire a creare un array dinamico di stringhe di lunghezza diversa non
prestabilita.
Il seguente codice:
   char *msg;
   msg = (char *) malloc(10 * sizeof(char));
   strcpy(msg, "1234567980");
   printf("%s %dn", msg, strlen(msg));
   msg = (char *) realloc(msg, 16 * sizeof(char));
   strcpy(msg, "ABCDEFGHILMNOPQR");
   printf("%s %dn", msg, strlen(msg));
da il risultato che mi aspettavo:
1234567980 10
ABCDEFGHILMNOPQR 16
Quello che non capisco è perché il seguente codice da gli stessi risultati:
   char *msg;
   msg = (char *) malloc(10 * sizeof(char));
   strcpy(msg, "1234567980");
   printf("%s %dn", msg, strlen(msg));
   strcpy(msg, "ABCDEFGHILMNOPQR");
   printf("%s %dn", msg, strlen(msg));
Mi sarei aspettato un "Segmentation fault" volendo assegnare 16 char ad un
array di 10 char .
Qualcuno sa spiegarmi l'arcano?
Inoltre sapreste indicarmi qualche documento che chiarisca bene l'uso di
array dinamici di stringhe?
Grazie mille
Mario
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

Mario Sartori ha scritto:

presumo perché lo heap ha comunque una certa grandezza quando il
programma parte, inoltre quello che fai è semplicemente sovrascrivere
uno spazio su cui non hai il look ma in assenza di altri dati in memoria
 il programma "sembra" funzionare, comunque sia per una stringa del tipo
"1234567890" non basterebbe allocare 10 *sizeof(char) ma 11 perché devi
tenere di conto anche del terminatore di riga, stesso discorso per
strcpy etc...
inoltre visto gli ultimi standard è più elegante scrivere:
char *msg = malloc(10 * sizeof *msg);
spero dal ng arrivi una spiegazione migliore... :)

 array di 10 char .
Se vai a scrivere su una locazione di memoria non allocata, a priori può 
succedere di tutto. Anche niente.
E.
E.

 Qualcuno sa spiegarmi l'arcano?
A parte i commenti che hai gia'  ricevuto. Forse e' meglio chiarire il 
significato di "Segmentation fault". Da quello che scrivi,  mi sembra 
che tu lo interpreti come un errore causato dall'  aver superato i 
limiti di un array o comunque di una regione di memoria allocata in modo 
contiguo.
Questo comportamento non esiste come comportamento degli eseguibili 
provenienti dalla compilazione di un programma C.
In genere i  compilatori possono mettere a disposizione delle opzioni di 
check dei bounds in modo da evidenziare, innescando uno status di 
errore, l'  accesso, a  run time,  di componenti di array non allocate. 
Ma non si tratta di un segmentation fault.
Il segmentation fault  e'  una  condizione di errore del processo 
innescata dal tentativo di accesso a regioni di memoria illegali per il 
processo in questione.  Puoi vederla cosi':  ogni processo ha  a 
disposizione uno  spazio in memoria in cui tenere istruzioni, dati, 
condizione di stato ... tutto. Finche' le istruzioni del processo fanno 
rifermento a locazioni di memoria interne a questo spazio, va tutto 
bene.  Anche se, per errore si sovrascrivono dati o  si fuoriesce dallo 
spazio riservato a certe strutture dati.  Solo se il riferimento va 
oltre i  confini della memoria legalmente accessibile qal processo come 
un tutto, scatta la condizione di segmentation fault.
Per maggiori informazioni prova a  dare un occhiata a wikipedia:
http://it.wikipedia.org/wiki/Errore_di_segmentazione
Giorgio

 comportamento indefinito.
Curiosita' mia: quanto spazio alloca _veramente_ una malloc? Cioe', se 
chiedo 10 byte (come sopra), alloca davvero esattamente 10 byte? O magari ne 
alloca di piu', per ottimizzare l'accesso?
Pleg 

Pleg ha scritto:

Ogni allocatore puo' decidere quanta memoria allocare, l'unica cosa che 
è certa è che avrai "almeno" 10 bytes (se sono diponibili).
In genere  ne alloca di piu', non fosse altro che per gestire la free 
list quando poi rilascerai il blocco di memoria con free(). Credo che 8 
o 16 byte di overhead per blocco siano la situazione piu' comune.
R.D.

Intanto ringrazio tutti per le utili e chiare risposte.
Mi chiedevo se il seguente codice, che fa largo uso di allocazione
dinamica di memoria, è concettualmente corretto (funziona ma vorrei essere
sicuro di aver utilizzato l'approccio giusto per ciò che voglio ottenere):
  typedef struct _insieme {
     char * parola;
     int gruppo;       
  } insieme;  
 
  insieme *elenco;
 
  elenco = malloc(sizeof(insieme));
  elenco[0].parola = malloc(5 * sizeof(char));
  strcpy(elenco[0].parola, "casa");
  elenco[0].gruppo = 12;
  elenco = realloc(elenco, 2*sizeof(insieme));
  elenco[1].parola = malloc(8 * sizeof(char));
  strcpy(elenco[1].parola, "portale");
  elenco[1].gruppo = 5;
  elenco = realloc(elenco, 3*sizeof(insieme));
  elenco[2].parola = malloc(6 * sizeof(char));
  strcpy(elenco[2].parola, "torta");
  elenco[2].gruppo = 22;
  int i;
  for (i=0; i<3; i++)
   printf("parola: %s gruppo: %dn", elenco[i].parola, elenco[i].gruppo);
Grazie,


Pleg ha scritto:

Dipende da come viene implementato l'allocatore. Una soluzione sensata 
sarebbe quella di allocare sempre potenze di 2. Dunque quando chiedi 10 
in realtà ne riserva 16.
E.

 sicuro di aver utilizzato l'approccio giusto per ciò che voglio ottenere):
Mi pare corretto. L'unico dettaglio è che non controlli che i puntatori 
restituiti da malloc e realloc siano diversi da 0. Questo significa che 
se si finisce la memoria il tuo programma andrà probabilmente in 
crash... Ma in effetti molti non fanno il controllo e preferiscono 
settare una callback per fermare il programma nel caso finisca la 
memoria (almeno credo).
A mio parere se ti ritrovi ad usare molto malloc e realloc, forse è il 
caso di usare C++ e <vector>
E.

 caso di usare C++ e <vector>
Non fa una piega. Solo che in questo caso l'uso del C è imposto.
Grazie per la risposta intanto.



-- 
-riko

 bianca? :-P
Il valore di ritorno di fopen direi che và sempre controllato. Per 
malloc non è detto. In molte situazioni una soluzione sensata è quella 
di terminare immediatamente il programma, se la memoria finisce. Ho 
visto che tipicamente si utilizza una funzione utente (che di solito si 
chiama xmalloc) con la stessa signature di malloc, solo che ti 
garantisce di tornare un puntatore valido, perché se la memoria finisce 
ci pensa lei a fermare tutto e avvisare l'utente.
E.

 quando chiedi 10 in realtà ne riserva 16.
La soluzione non sembra molto sensata se devi allocare blocchi di 
grandi dimensioni.  Su macchine x86 in genere la malloc() ritorna 
un'area che è allineata a 4/8 byte sia per la maggiore efficienza, che 
per l'allineamento con il bus.  In alcuni casi l'allineamento potrebbe 
essere adeguato alle dimensioni della cache per ottimizzare anche 
l'accesso ai dati.
Diversa è la considerazione su come viene espanso lo heap per allocare 
lo spazio riservato ai blocchi di memoria rilasciati dalla malloc(). 
Sempre per le macchine x86 è di 4096 byte per l;architettura a 32 bit 
e una quantità maggiore che non conosco per l'archittetura a 64 bit.
Ciao
Giovanni
-- 
   A computer is like an air conditioner,
   it stops working when you open Windows.
   Registered Linux user #337974  < 
http://giovanni.homelinux.net/
 >

?manu* ha scritto:

soluzione classica:
xmalloc.h
#include <stdlib.h>
void *xmalloc(size_t size);
xmalloc.c
#include <stdio.h>
#include "xmalloc.h"
void *xmalloc(size_t size)
{
	void *x = malloc(size);
	if (!x) {
		fprintf(stderr, "out of memory\n");
		exit(EXIT_FAILURE);
	}
	return x;
}