View Full Version : [C] Consigli su creazione lista
Andrea16v
30-08-2007, 13:47
Devo creare una lista da una serie di dati statistici prelevati da un secondo programma che sono riuscito a completare.
La mia funzione che crea la lista riceve in ingresso: un risultato (stringa dim variabile da 1 a 30 char) e un id sessione (intero a 3 cifre).
Per ogni risultato voglio tenere conto di quante volte viene ricevuto in ogni sessione (sempre intero a 3 cifre) quindi ho scelto di fare una cosa del genere:
typedef struct nodo
{
struct nodo *next;
char *result;
int (*sessioni)[2];
}
Come posso sviluppare la funzione che riceve i dati non sapendo quanti siano in partenza? In particolare non so come comportarmi per inizializzare la lista (solo alla prima chiamata suppongo) e allocare lo spazio tramite malloc...
Come posso sviluppare la funzione che riceve i dati non sapendo quanti siano in partenza? In particolare non so come comportarmi per inizializzare la lista (solo alla prima chiamata suppongo) e allocare lo spazio tramite malloc...Vedi un mio esempio in <questo> (http://www.hwupgrade.it/forum/showthread.php?t=1526774) thread.
Andrea16v
30-08-2007, 21:56
Le operazioni da fare le ho capite (in altri linguaggi non avrei problemi a farlo), però non mi sono chiare proprio alcune operazioni che fai nella funzione append.
Lo riquoto un secondo:
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo
{
int data;
struct nodo *next;
} NODO, *PNODO, **PPNODO;
int List_Append (PPNODO pproot, int data)
{
PNODO pnodo;
if (pproot == NULL)
return 0;
if ((pnodo = (PNODO) malloc (sizeof (NODO))) == NULL)
return 0;
pnodo->data = data;
pnodo->next = NULL;
while (*pproot != NULL)
pproot = &(*pproot)->next;
*pproot = pnodo;
return 1;
}
int main (void)
{
PNODO proot = NULL;
List_Append (&proot, 27);
List_Append (&proot, 7);
List_Append (&proot, 87);
return 0;
}
Ora, correggimi se sbaglio: con il primo if testi che la lista sia stata inizializzata, in caso contrario non è possibile utilizzarla quindi esci (con 0 perchè restituisci il numero di elementi inseriti).
Con il secondo if controlli che ci sia spazio sufficiente (la malloc non restituisca NULL), in caso contrario esci. La mia malloc è molto più complessa avendo un array di lunghezza non fissa?
Poi assegni i valori al nuovo nodo (con puntatore next nullo in quanto lo metti in fondo), scorri "ricorsivamente" la struttura sino alla fine e inserisci...
grazie mille!
però non mi sono chiare proprio alcune operazioni che fai nella funzione append.Non c'è problema, spiego subito.
Ora, correggimi se sbaglio: con il primo if testi che la lista sia stata inizializzata, in caso contrario non è possibile utilizzarla quindi esciIl primo test controlla 'pproot' che è un puntatore ad una variabile di tipo PNODO. In quel punto della funzione non interessa tanto se il PNODO è NULL (che vuol dire lista vuota) ma che l'indirizzo passato di tale variabile sia NULL o no. È chiaro che se passi un indirizzo con una espressione &proot, l'indirizzo non è certamente NULL ma tecnicamente la possibilità di passare un NULL alla Append esiste.
(con 0 perchè restituisci il numero di elementi inseriti).No, per come l'ho pensata io è da intendere: 0=append fallito, 1=append riuscito. In pratica è uno stato booleano.
Con il secondo if controlli che ci sia spazio sufficiente (la malloc non restituisca NULL), in caso contrario esci.Esatto, questa è una cosa molto importante.
La mia malloc è molto più complessa avendo un array di lunghezza non fissa?No, non dovrebbe essere molto più complessa, bisogna solo vedere come è fatta la tua struttura dati.
Poi assegni i valori al nuovo nodo (con puntatore next nullo in quanto lo metti in fondo), scorri "ricorsivamente" la struttura sino alla fine e inserisci...Sì, tra l'altro ho usato il "trucchetto" di usare un puntatore a puntatore, perché in questo modo non devo differenziare tra primo nodo (da assegnare al root) o successivi nodi (da assegnare al next precedente).
Andrea16v
31-08-2007, 16:58
Penso di aver capito abbastanza: ho provato ad adattarlo ai miei scopi, per ora lasciando ancora da parte le cose difficili, questo è il risultato (che definirei abbastanza penoso..):
typedef struct nodo
{
char *result;
int sessione;
struct nodo *next;
} NODO, *PNODO, **PPNODO;
int main() {
PNODO proot = NULL;
list_Append (&proot, "PrimoRisultato", 1);
list_Append (&proot, "SecondoRisultato", 2);
list_Append (&proot, "TerzoRisultato", 2);
list_Append (&proot, "QuartoRisultato", 3);
stampa (&proot);
return 0;
}
int list_Append (PPNODO pproot, char *result, int sessione)
{
PNODO pnodo;
if (pproot == NULL)
return 0;
if ((pnodo = (PNODO) malloc (sizeof (NODO))) == NULL)
return 0;
pnodo->result = result;
pnodo->sessione = sessione;
pnodo->next = NULL;
while (*pproot != NULL)
pproot = &(*pproot)->next;
*pproot = pnodo;
return 1;
}
void stampa (PPNODO pproot)
{
if (pproot == NULL)
exit(1);
printf("Risultato: %s\n", (*pproot)->result);
printf("Id sessione: %d\n\n", (*pproot)->sessione);
stampa((*pproot)->next);
}
void stampa (PPNODO pproot)
{
if (pproot == NULL)
exit(1);
printf("Risultato: %s\n", (*pproot)->result);
printf("Id sessione: %d\n\n", (*pproot)->sessione);
stampa((*pproot)->next);
}Io farei stampa così:
void stampa (PNODO pnodo)
{
while (pnodo != NULL)
{
printf("Risultato: %s\n", pnodo->result);
printf("Id sessione: %d\n\n", pnodo->sessione);
pnodo = pnodo->next;
}
}
Per il resto mi sembra ok. Una cosa sola a cui prestare attenzione sono gli eventuali puntatori che rappresentano dei dati nella struttura del nodo (cioè escluso il next). Nel tuo caso è il puntatore 'result'. Copi semplicemente il valore del puntatore ma questo vuol dire che non è la lista ad essere "responsabile" e "proprietaria" dell'area di memoria a cui punta ma è il chiamante all'esterno che deve gestirla.
Finché assegni l'indirizzo di stringhe "literal", no problem.
Andrea16v
03-09-2007, 11:49
Ho provato a complicare un po' le cose aggiungendo la matrice.
Ad ogni risultato ho associato una matrice di due colonne in cui la prima riporta il numero di sessione e la seconda il numero di volte che il risultato è pervenuto in quella sessione. Dovrei trovare un modo per scorrere la matrice verticalmente sino all'ultima riga, ma ora come ora non mi sono venute idee (salvo inserire nella struct un campo che mi dice il numero di sessioni in cui appare quel risultato). Inoltre c'è sicuramente anche qualche problema di allocazione...
int list_Append (PPNODO pproot, char *result, int sessione)
{
PNODO pnodo;
int i;
if (pproot == NULL)
return 0;
if ((pnodo = (PNODO) malloc (sizeof (NODO))) == NULL)
return 0;
while (*pproot != NULL) {
/*cerco il risultato nella lista dei risultati*/
if((*pproot)->result) == result) {
/*cerco la sessione all'interno del nodo*/
for(i=0;i<???) /*dovrei iterare sino all'ultima riga*/
if( (*pproot)->sessioni[i][0] == sessione){
(*pproot)->sessioni[i][1]++;
return 1;
}
}
/*la sessione non e' presente, la aggiungo*/
(*pproot)->sessioni[i][0] = sessione;
(*pproot)->sessioni[i][1] = 1;
return 1;
}
pproot = &(*pproot)->next;
}
/* il risultato non e' presente, lo aggiungo in coda*/
pnodo->result = result;
pnodo->sessioni[0][0] = sessione;
pnodo->sessioni[0][1] = 1;
pnodo->next = NULL;
*pproot = pnodo;
return 1;
}
ps: il modello della struct è nel primo post!
Ho provato a complicare un po' le cose aggiungendo la matrice.Puoi spiegare meglio come deve essere questa matrice?
Perché tra l'altro:
a) Fare int (*sessioni)[2] vuol dire "un puntatore ad un array di 2 int". Ho il dubbio che probabilmente non è proprio quello che ti serve.
b) Nella funzione non assegni un valore a questo puntatore. Fai:
pnodo->sessioni[0][0] = sessione;
pnodo->sessioni[0][1] = 1;
e cioè cerchi di accedere agli elementi nell'array puntato ma pnodo->sessioni non è inizializzato, quindi ... boh.
c) Nel while fai dei return 1 ma in caso di tale uscita, hai comunque allocato un NODO che poi non viene usato (memory leak).
Andrea16v
03-09-2007, 14:23
a) Fare int (*sessioni)[2] vuol dire "un puntatore ad un array di 2 int". Ho il dubbio che probabilmente non è proprio quello che ti serve.
La specifica che devo seguire riguardo alla struct parla in effetti di "puntatore ad un array di 2 int" ma, ragionando un po' sulla cosa, non ho trovato il modo di esprimere quello che mi serve in quel modo, quindi ho pensato di usare una matrice in cui memorizzo un id sessione nella prima colonna e il numero di hit di quel risultato in quella sessione nella seconda colonna. La matrice avrà un numero di righe che puo' crescere nel tempo: viene inizializzata ad 1 all'atto della creazione del nodo con l'arrivo del primo risultato e può arrivare a 999.
E' valida come idea oppure effettivamente si poteva fare anche con un puntatore ad un array di 2 int?
b) Nella funzione non assegni un valore a questo puntatore. Fai:
pnodo->sessioni[0][0] = sessione;
pnodo->sessioni[0][1] = 1;
e cioè cerchi di accedere agli elementi nell'array puntato ma pnodo->sessioni non è inizializzato, quindi ... boh.
Il mio intento era di creare un nuovo nodo da aggiungere alla lista e assegnare alle variabili della struct i valori ricevuti dalla funzione come parametro.
La dinamica del tutto è la seguente: ricevo un risultato, controllo se il risultato è già in lista, se non è in lista lo aggiungo in coda, se è già in lista controllo se era già stato ricevuto in quella sessione scorrendo la prima colonna della matrice, in caso positivo aumento il numero di hit di quella sessione e esco, in caso negativo aggiungo una riga alla matrice con il numero sessione e 1 come numero hit.
c) Nel while fai dei return 1 ma in caso di tale uscita, hai comunque allocato un NODO che poi non viene usato (memory leak).
Giusto, questo è un errore che non avevo visto. Chiamerò la malloc del NODO solo quando sono arrivato al caso in cui debba crearlo da zero. Ma ogni volta che aggiungo una riga alla matrice devo allocare esplicitamente il relativo spazio o viene fatto "in automatico"? Viva Java... :)
La specifica che devo seguire riguardo alla struct parla in effetti di "puntatore ad un array di 2 int" ma, ragionando un po' sulla cosa, non ho trovato il modo di esprimere quello che mi serve in quel modo, quindi ho pensato di usare una matrice in cui memorizzo un id sessione nella prima colonna e il numero di hit di quel risultato in quella sessione nella seconda colonna. La matrice avrà un numero di righe che puo' crescere nel tempo: viene inizializzata ad 1 all'atto della creazione del nodo con l'arrivo del primo risultato e può arrivare a 999.
E' valida come idea oppure effettivamente si poteva fare anche con un puntatore ad un array di 2 int?Allora i due valori rappresentano un "record" e devi fare un array di record. Pertanto è meglio se definisci una struttura:
typedef struct
{
int id;
int hit;
} SESSIONE;e poi metti nel nodo un puntatore a SESSIONE:
SESSIONE *sessioni;
L'array delle sessioni ovviamente lo allochi dinamicamente quando crei un nodo e lo assegni al puntatore.
Andrea16v
03-09-2007, 16:15
Ho guardato un po' come verrebbe con l'array di record e cosa dovrei cambiare negli altri moduli del programma e mi viene un bel caos, dovrei rifare una marea di cose che al momento sono faticosamente funzionanti, preferisco insistere sulla strada della matrice.
RisultatoA
[2][6]
[4][3]
[7][1]
da intendersi come: nella seconda sessione ricevuto sei volte, nella quarta sessione ricevuto tre volte, ecc
La dinamica del tutto è la seguente: ricevo un risultato, controllo se il risultato è già in lista, se non è in lista lo aggiungo in coda, se è già in lista controllo se era già stato ricevuto in quella sessione scorrendo la prima colonna della matrice, in caso positivo aumento il numero di hit di quella sessione e esco, in caso negativo aggiungo una riga alla matrice con il numero sessione e 1 come numero hit.
Qualche suggerimento su come gestire le malloc nei vari casi? :mc:
Questo è quando ho prodotto:
nsess è stato aggiunto alla struct: indica il numero di sessioni in cui il risultato è presente, e quindi il numero di righe della matrice...
int list_Append (PPNODO pproot, char *result, int sessione)
{
PNODO pnodo;
int i;
if (pproot == NULL)
return 0;
while (*pproot != NULL) {
if(((*pproot)->result) == result) {
for(i=0;i<(*pproot)->nsess;i++){
if( (*pproot)->sessioni[i][0] == sessione){
(*pproot)->sessioni[i][1]++;
return 1;
}
}
/*la sessione non e' presente, la aggiungo*/
(*pproot)->sessioni[i][0] = sessione;
(*pproot)->sessioni[i][1] = 1;
(*pproot)->nsess++;
return 1;
}
pproot = &(*pproot)->next;
}
/* il risultato non e' presente, lo aggiungo in coda*/
if ((pnodo = (PNODO) malloc (sizeof (NODO))) == NULL)
return 0;
pnodo->result = result;
pnodo->sessioni[0][0] = sessione;
pnodo->sessioni[0][1] = 1;
pnodo->next = NULL;
pnodo->nsess = 1;
*pproot = pnodo;
return 1;
}
if ((pnodo = (PNODO) malloc (sizeof (NODO))) == NULL)
return 0;
pnodo->result = result;
pnodo->sessioni[0][0] = sessione;
pnodo->sessioni[0][1] = 1;Continuo a non vedere la allocazione di una area per questi benedetti int. A costo di essere petulante, ripeto che pnodo->sessioni è solo un puntatore e gli va assegnato qualcosa prima di poterlo dereferenziare (accedere al contenuto puntato).
Un esempio banale:
int (*sessioni)[2];
int arr[2];
sessioni = &arr;In questo caso assegno l'indirizzo di un altro array.
Ma posso pure allocare dinamicamente la memoria per i due int:
int (*sessioni)[2];
sessioni = (int(*)[2]) malloc (2 * sizeof (int));
E se volessi allocare 10 righe:
sessioni = (int(*)[2]) malloc (2 * 10 * sizeof (int));
sessioni[0][0] = ....
sessioni[0][1] = ....
....
sessioni[9][0] = ....
sessioni[9][1] = ....
nico88desmo
03-09-2007, 21:33
Mi intrometto nella discussione chiedendo 2 cose;
Questi due modi sono equivalenti vero?
int (*sessioni)[2];
int arr[2];
come pure questi, giusto?
&(*pproot);
pproot;
Questi due modi sono equivalenti vero?
int (*sessioni)[2];
int arr[2];
No sono due cose diverse, il primo è "un puntatore ad un array di 2 int" mentre il secondo è "un array di due int". L'indirizzo del secondo è assegnabile al primo (come appunto nel mio esempio sopra).
come pure questi, giusto?
&(*pproot);
pproot;
In questo caso sì, sono equivalenti (sebbene il primo sia un po' "stupido").
Andrea16v
05-09-2007, 11:58
...vedi post sotto!
Andrea16v
10-09-2007, 00:43
Continuo a non vedere la allocazione di una area per questi benedetti int. A costo di essere petulante, ripeto che pnodo->sessioni è solo un puntatore e gli va assegnato qualcosa prima di poterlo dereferenziare (accedere al contenuto puntato).
Giusto, mi sono un po' guardato la malloc e la realloc, pensavo l'assegnamento dello spazio fosse del tutto automatico...
Comunque ancora un paio di cose non mi tornano:
la mia struttura è fatta così:
typedef struct nodo
{
struct nodo *next;
char *result;
int (*sessioni)[2];
int pippo; //aggiunto per esempio
int pluto[4]; //aggiunto per esempio
}
Quando chiamo la malloc con il parametro sizeof (NODO) quanto spazio viene allocato per la struttura sopra?
Esempio: se voglio scrivere qualcosa nel campo nodo->result potrei farlo senza richiamare la malloc (ho un esempio però che non funziona!), mentre se voglio scrivere in sessioni[..] non posso in quanto sessioni è un puntatore e la malloc precedente non ha allocato spazio per i puntatori definiti nella struct..
pluto[0] dovrebbe essere "disponibile" senza ulteriori malloc però se volessi espandere l'array a 6 posizioni potrei chiamare realloc(&pluto, 6*sizeof(int))
Vorrei insomma capire con che criterio viene allocato lo spazio con la chiamata sizeof(NODO)
Quando chiamo la malloc con il parametro sizeof (NODO) quanto spazio viene allocato per la struttura sopra?Ogni variabile ha una dimensione ben precisa, pure i puntatori, ovviamente.
Prendiamo la tua struttura originale:
typedef struct nodo
{
struct nodo *next;
char *result;
int (*sessioni)[2];
}Sono tutti e tre dei puntatori. Su architetture a 32 bit un puntatore è appunto 32 bit, quindi 4 byte. Totale: 12 byte allocati per la struttura.
Esempio: se voglio scrivere qualcosa nel campo nodo->result potrei farlo senza richiamare la malloc (ho un esempio però che non funziona!)La questione è un'altra: a 'result' potresti assegnare l'indirizzo di una stringa literal e non avresti mai problemi, potresti assegnare l'indirizzo di una stringa allocata al di fuori della funzione di Append oppure nella funzione Append potresti allocare memoria sufficiente e quindi duplicare la stringa passata.
La questione quindi è: chi deve gestire la memoria di quella stringa, in pratica chi deve essere "responsabile" della gestione dell'area di memoria puntata da result.
Se nella funzione di Append fai una cosa come:
pnodo->result = result;
vuol dire semplicemente che la funzione non sa nulla di come è stata gestita l'allocazione della stringa e si limita solo a copiare l'indirizzo. Quindi sei tu che dovrai preoccuparti all'esterno di allocare/deallocare (eventualmente) la memoria.
mentre se voglio scrivere in sessioni[..] non posso in quanto sessioni è un puntatore e la malloc precedente non ha allocato spazio per i puntatori definiti nella struct..La malloc per il NODO ha allocato spazio per i puntatori. Ma se tu che dovrai valorizzarli con opportuni valori.
pluto[0] dovrebbe essere "disponibile" senza ulteriori malloc però se volessi espandere l'array a 6 posizioni potrei chiamare realloc(&pluto, 6*sizeof(int))Per come hai dichiarato pluto, cioè int pluto[4];, non puoi ridimensionarlo in alcun modo. Quello è un array di dimensione fissa. Nella struttura ci saranno quindi già 4*sizeof(int) byte allocati per questa variabile. E l'indirizzo di questo array è anche fisso. Per dirla in altri termini, l'epressione 'pluto' non può essere un l-value, cioè non puoi fare ad esempio: pluto = realloc........
Andrea16v
10-09-2007, 11:04
Ogni variabile ha una dimensione ben precisa, pure i puntatori, ovviamente.
Prendiamo la tua struttura originale:
typedef struct nodo
{
struct nodo *next;
char *result;
int (*sessioni)[2];
}Sono tutti e tre dei puntatori. Su architetture a 32 bit un puntatore è appunto 32 bit, quindi 4 byte. Totale: 12 byte allocati per la struttura.
Ok, quindi nel momento in cui dichiaro un puntatore, ho sempre un'allocazione di 4 byte, indipendentemente dal "tipo" del puntatore, un puntatore ad un array di 2 int, come sopra, sarà uguale ad un puntatore ad un array di 20 int, con un campo solo per l'indirizzo iniziale dell'array! Per errore sono riuscito a scrivere int in questo campo senza che il compilatore mi avvisasse, quindi pensavo lo spazio per i 2 int fosse già allocato!
La questione è un'altra: a 'result' potresti assegnare l'indirizzo di una stringa literal e non avresti mai problemi, potresti assegnare l'indirizzo di una stringa allocata al di fuori della funzione di Append oppure nella funzione Append potresti allocare memoria sufficiente e quindi duplicare la stringa passata.
Capisco ora a cosa ti riferivi in un post precedente. Nel mio caso la memoria deve essere gestita all'interno del nodo, e il programma che manda le stringhe ad append mi invia un array di caratteri, quindi dovrei allocare spazio e duplicare con strcpy o strncpy. Ho fatto delle prove anche inviando delle stringhe literal "ciao" e in effetti non serve nè allocare, nè duplicare...
Per come hai dichiarato pluto, cioè int pluto[4];, non puoi ridimensionarlo in alcun modo. Quello è un array di dimensione fissa. Nella struttura ci saranno quindi già 4*sizeof(int) byte allocati per questa variabile. E l'indirizzo di questo array è anche fisso. Per dirla in altri termini, l'epressione 'pluto' non può essere un l-value, cioè non puoi fare ad esempio: pluto = realloc........
Giusto, perchè la realloc funziona solo su locazioni di mem. ottenute tramite malloc...
Nel caso avessi dichiarato quindi sessioni come array di 2 int e non puntatore a, non avrei potuto aumentarlo dinamicamente a seconda delle esigenze.
Ultima cosa: tutte le volte che chiamo la malloc() è necessario testarne il valore di ritorno? Nel mio caso ho 3 chiamate: una sul sizeof(NODO), la seconda per la stringa e la terza per la matrice/array, quindi mi ritroverei un codice un po' incasinato..
Per errore sono riuscito a scrivere int in questo campo senza che il compilatore mi avvisasse, quindi pensavo lo spazio per i 2 int fosse già allocato!Perché la malloc non azzera il blocco di memoria, in pratica ci trovi "spazzatura", quindi un indirizzo che potrebbe essere NULL o non NULL e in tal caso non sai a cosa punta. Se lo dereferenzi per scriverci, può succedere un po' di tutto, dal sporcare altre zone vitali del programma (e avere crash in seguito) al segmentation fault immediato.
Ultima cosa: tutte le volte che chiamo la malloc() è necessario testarne il valore di ritorno? Nel mio caso ho 3 chiamate: una sul sizeof(NODO), la seconda per la stringa e la terza per la matrice/array, quindi mi ritroverei un codice un po' incasinato..Sì, sarebbe meglio se testassi il valore fornito da ogni malloc. Non è che ti si incasina più di tanto il codice.
Se ad esempio la malloc del NODO e ok ma poi la malloc per sessioni fallisce, beh, basta che fai il free di ciò che hai allocato prima e ritorni NULL.
Andrea16v
12-09-2007, 12:40
Ho fatto ancora delle prove sulla realloc, il frammento seguente mi funziona, ma è giusto dal punto di visto logico? Se ho capito bene il programma potrebbe funzionare anche eliminando la chiamata alla malloc(), però lo spazio non verrebbe riservato, quindi ulteriori operazioni potrebbero andare ad alterare il contenuto dell'array...
int (*s)[2];
int i=0, dim=2;
s = (int(*)[dim]) malloc (dim * sizeof(int));
while(i<dim){
*(s[i])= ...;
i++;
}
dim = dim + 2; // aggiungo due posizioni
s = (int(*)[dim]) realloc(s, dim * sizeof(int));
*(s[i]) = ...;
*(s[i+1]) = ...;
dim = dim + 6; // ne aggiungo altre sei
s = (int(*)[dim]) realloc(s, dim * sizeof(int)):
*(s[i+2]) = ...;
*(s[i+3]) = ...;
...
*(s[i+7]) = ...;
Qualcosa ancora non mi è chiaro: quando dichiaro un puntatore ad un array, a cosa serve dichiarare la lunghezza dell'array? X es: dichiarare (int*)s[2] è diverso da dichiarare (int*)s[10] o impatta solo sulla intelligibilità del comando?
Idem dicasi per il cast sulle chiamate malloc e realloc è solo una questione stilistica o impatta in qualche modo sulla "gestione dello spazio"?
Ho fatto ancora delle prove sulla realloc, il frammento seguente mi funziona, ma è giusto dal punto di visto logico?Non va bene il cast (int(*)[dim]). Quel 'dim' tra [ ] non è una cosa che deve cambiare, cioè non è quello che denota la dimensione. Deve essere sempre 2 in quanto il puntatore punta ad un array di 2 int. Poi ovviamente puoi avere più elementi fatti così (array di 2 int appunto).
Rileggi bene il mio post #12.
Comunque io piuttosto ragionerei in termini di "righe", ovvero:
int (*sessioni)[2];
int righe = 1;
sessioni = (int(*)[2]) malloc (righe * 2 * sizeof (int));
....
righe = 10;
sessioni = (int(*)[2]) realloc (sessioni, righe * 2 * sizeof (int));
Se ho capito bene il programma potrebbe funzionare anche eliminando la chiamata alla malloc(), però lo spazio non verrebbe riservato, quindi ulteriori operazioni potrebbero andare ad alterare il contenuto dell'array...Devi per forza allocare memoria e assegnarne il puntatore a sessioni. Altrimenti .... bang.
Qualcosa ancora non mi è chiaro: quando dichiaro un puntatore ad un array, a cosa serve dichiarare la lunghezza dell'array? X es: dichiarare (int*)s[2] è diverso da dichiarare (int*)s[10] o impatta solo sulla intelligibilità del comando?
Idem dicasi per il cast sulle chiamate malloc e realloc è solo una questione stilistica o impatta in qualche modo sulla "gestione dello spazio"?Dichiarando un puntatore come:
int (*sessioni)[2];
dici solamente che quello è un puntatore che "sa" di puntare ad un array che contiene 2 int. Questo però non alloca alcuna memoria per gli int, ma solo per il puntatore. La dimensione [2] nella dichiarazione è importante perché altrimenti il compilatore non saprebbe poi come tradurre una espressione come:
sessioni[4][1]
Cioè deve sapere quanto è grande l'elemento puntato per poter calcolare l'indirizzo della riga i-esima.
È poi il programmatore che deve usare indici corretti. Per dirla in un altro modo con un esempio:
int (*sessioni)[2];
int righe = 4;
sessioni = (int(*)[2]) malloc (righe * 2 * sizeof (int));
con 4 righe, ognuna appunto di 2 int, sarebbe corretto fare:
sessioni[0][0] oppure sessioni[0][1] oppure sessioni[1][0] ..... sessioni[3][1]
Ma nota che fare sessioni[0][2] è equivalente a fare sessioni[1][0].
Per fare un esempio ancora più banale, se ho un int *p e il puntatore mettiamo che abbia valore 1000, allora p[0] punta alla locazione 1000 ma p[1] punta alla locazione 1004.
Insomma, il compilatore deve conoscere la dimensione dell'elemento puntato per poter tradurre correttamente l'espressione di accesso.
Andrea16v
14-09-2007, 10:25
con 4 righe, ognuna appunto di 2 int, sarebbe corretto fare:
sessioni[0][0] oppure sessioni[0][1] oppure sessioni[1][0] ..... sessioni[3][1]
Ma nota che fare sessioni[0][2] è equivalente a fare sessioni[1][0].
Questo perchè la notazione matriciale è solo logica e viene convertita a tempo di compilazione in un array? Es. in un array di n int: s[2][1] = s[2*n+1]
Quindi nel nostro caso sessioni[1][0] sarebbe equivalente a sessioni[2] e le due notazioni potrebbero essere ovunque intercambiabili oppure sessioni[1][0] sarebbe equivalente a *(sessioni[2]) come mi è parso di vedere in via sperimentale.. :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.