View Full Version : [c++] struct e new
Ho una struttura così:
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
{
bool IF[8];
};
Nel caso sopra posso avere fino a 7 bool
ho bisogno che bool IF[x] sia incrementato in modo automatico a runtime oppure decrementato.
In pratica bool IF[x]; all'inizio non si conosce quanti indici può contenere quindi a runtime devo fare bool IF[0]; poi bool IF[1]; ecc ecc. anche decrementandolo.
Credo che bisogna usare la new ma nella struct così formata non ne sono capace...
Volutomitra
20-10-2006, 20:40
#define MAX_ITEMS 100
typedef struct struttura
{
int n_items;
bool *item;
public:
struttura (void)
{
n_items = 0;
item = new bool[MAX_ITEMS];
}
void add_item (bool _item)
{
if (n_items < MAX_ITEMS)
item[n_items++] = _item;
}
};
struttura *mStruttura = new struttura();
mStruttura->add_item(true);
mStruttura->add_item(false);
#define MAX_ITEMS 100
typedef struct struttura
{
int n_items;
bool *item;
public:
struttura (void)
{
n_items = 0;
item = new bool[MAX_ITEMS];
}
void add_item (bool _item)
{
if (n_items < MAX_ITEMS)
item[n_items++] = _item;
}
};
struttura *mStruttura = new struttura();
mStruttura->add_item(true);
mStruttura->add_item(false);
ti ringrazio
in pratica dici
#define MAX_ITEMS 100
struct GAMEMSG_OKAY
{
int idN;
bool IF[MAX_ITEMS];
};
void add_item (bool _item)
{
if (n_items < MAX_ITEMS)
item[n_items++] = _item;
}
... ok
Ho aperto il 3d perchè volevo risparmiare sulle dimensioni della struttura.
Come lo messa io all'inizio l'ho definita a [8] quindi la struttura ha sizeof(GAMEMSG_OKAY) di tot mentre pensavo di iniziare da 0 e mano a mano che incremento gli item la struttua aumentasse il suo sizeof().
La domanda e il metodo era per risparmiare sui byte della struttura facendo:
bool IF[MAX_ITEMS];
la struttura ha un sizeof(GAMEMSG_OKAY) maggiore del mio [8]... o sbaglio!!!
Volutomitra
20-10-2006, 22:15
La domanda e il metodo era per risparmiare sui byte della struttura facendo:
bool IF[MAX_ITEMS];
la struttura ha un sizeof(GAMEMSG_OKAY) maggiore del mio [8]... o sbaglio!!!
Non sbagli. Se vuoi allocare dinamicamente ogni nuovo dato potresti pensare ad una lista... Hai presente?
Non sbagli. Se vuoi allocare dinamicamente ogni nuovo dato potresti pensare ad una lista... Hai presente?
si la conosco.
fai un esempio... di lista per la struct postata per allocare e deallocare in modo dinamico.
struct GAMEMSG_OKAY
{
bool IF;
struct GAMEMSG_OKAY *next;
public:
GAMEMSG_OKAY (void)
{
IF = false; // Non è necessario...
next = NULL;
}
// Aggiunge un nuovo elemento in coda alla lista. Il valore ritornato
// è di comodo...
struct GAMEMSG_OKAY *addItem(bool value)
{
struct GAMEMSG_OKAY *newElem = new struct GAMEMSG_OKAY;
newElem->IF = value;
struct GAMEMSG_OKAY *ptr = this;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = newElem;
return newElem; // Di comodo...
}
// Elimina l'elemento in coda alla lista.
// NOTA: se la lista contiene almeno un elemento (quello iniziale), nulla
// viene eliminato.
void removeItem(void)
{
struct GAMEMSG_OKAY *oldPtr = NULL;
struct GAMEMSG_OKAY *ptr = this;
while (ptr->next != NULL)
{
oldPtr = ptr;
ptr = ptr->next;
}
if (oldPtr != NULL)
{
oldPtr->next = NULL;
delete ptr;
}
return;
}
// Restituisce il valore booleano nella posizione specificata.
// Se l'elemento non esiste, ritorna -1.
short int getItem(unsigned int numItem)
{
struct GAMEMSG_OKAY *ptr = this;
while (numItem > 0)
{
ptr = ptr->next;
if (ptr == NULL)
return -1;
numItem--;
}
return ptr->IF;
}
// Setta il valore booleano nella posizione specificata.
// Se l'elemento non esiste, ritorna -1, altrimenti 0.
short int setItem(unsigned int numItem, bool value)
{
struct GAMEMSG_OKAY *ptr = this;
while (numItem > 0)
{
ptr = ptr->next;
if (ptr == NULL)
return -1;
numItem--;
}
ptr->IF = value;
return 0;
}
}; // END OF struct GAMEMSG_OKAY
// Esempio d'uso. Non controllo i possibili errori, per quanto i "metodi"
// lo permettano: comunque eventuali errori sono causati da
// errati parametri passati.
// NOTA: values rappresenta sempre il primo elemento (la testa della lista).
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
// NOTA: è come se facessi values->setItem(0, true);
values->IF = true;
values->addItem(true);
values->addItem(false);
values->setItem(0, false);
values->addItem(true);
values->setItem(2, true);
values->removeItem();
bool test = values->getItem(2);
test = values->getItem(0);
Compilato con Visual Studio (i NULL sono maiuscoli, compilando per Win32...).
EDIT: stanotte non riesco a prendere sonno... :muro:
azz... hai fatto tutto!!
mi hai risparmiato un bel lavoro... grazie ;) (ripassare le liste ecc ecc.)
struct GAMEMSG_GENERIC
{
DWORD dwType;
};
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
come hai messo tu posso usare sempre:
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
{
bool IF;
struct GAMEMSG_OKAY *next;
giusto?
anche io non prendo sonno ;) ;)
Edit:
Domani lo studio e cerco di integrarlo prossimamente il tuo code.
- gli inserimenti vanno in testa si?
- su 5 elementi tolgo il 3 e scalo gli altri ok?
azz... hai fatto tutto!!
mi hai risparmiato un bel lavoro... grazie ;) (ripassare le liste ecc ecc.)
Prego ;)
struct GAMEMSG_GENERIC
{
DWORD dwType;
};
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
come hai messo tu posso usare sempre:
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
{
bool IF;
struct GAMEMSG_OKAY *next;
giusto?
Giusto, ma stai attento ad una cosa:quando crei una nuova struttura GAMEMSG_OKAY (nel mio codice di esempio finale "values"), il puntatore alla struttura punta sempre al primo elemento della lista! (a meno che non lo cambi esplicitamente tu con cose del tipo "values = nuovopuntatore"...)Quindi, se aggiungi alla dichiarazione della struttura ": public GAMEMSG_GENERIC" e fai:
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
values->dwType = 1; // Ad esempio...
"dwType" si riferirà sempre al primo elemento della lista! Quindi, abbiamo bisogno di una piccola modifica per ottenere un puntatore all'elemento della lista da modificare. Come puoi notare, quando aggiungo un nuovo elemento, il puntatore ritornato è prorpio quello che fa al caso nostro, però così comè è scomodo per i nostri scopi (a te serve ottenerlo in qualunque momento).
Mi sembra più opportuno, quindi, modificare il codice affinchè:
1) per settare un valore nella struttura, meglio avere il puntatore all'elemento e poi fare ad esempio: curElem->IF = FALSE; curElem->dwType = 2; ecc...
2) quindi la setItem e la getItem vanno modificate.
La modifica la trovi tra poco ;)
- gli inserimenti vanno in testa si?
No, così com'è vanno in coda (è più comodo per l'uso che ne devi fare).
- su 5 elementi tolgo il 3 e scalo gli altri ok?
Adesso viene eleminato sempre l'ultimo elemento aggiunto (che è quello in coda). Se vuoi togliere un elemento preciso, dobbiamo lievemente modificare il codice. Quindi, ti posto il codice riveduto per venire incontro alle tue esigenze (nota che la setItem non serviva più!):
int main(void)
{
struct GAMEMSG_GENERIC
{
DWORD dwType;
// Mi permetto di aggiungere un costruttore, visto come usiamo la struttura.
public:
GAMEMSG_GENERIC (void)
{
dwType = 0;
}
};
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
{
bool IF;
struct GAMEMSG_OKAY *next;
public:
GAMEMSG_OKAY (void)
{
IF = false;
next = NULL;
}
// Aggiunge un nuovo elemento in coda alla lista. Il valore ritornato
// è di comodo...
struct GAMEMSG_OKAY *addItem(void)
{
struct GAMEMSG_OKAY *newElem = new struct GAMEMSG_OKAY;
struct GAMEMSG_OKAY *ptr = this;
while (ptr->next != NULL)
ptr = ptr->next;
ptr->next = newElem;
return newElem; // Di comodo...
}
// Restituisce un puntatore all'elemento richiesto.
// Se l'elemento non esiste, ritorna NULL.
struct GAMEMSG_OKAY *getItem(unsigned int numItem)
{
struct GAMEMSG_OKAY *ptr = this;
while (numItem > 0)
{
ptr = ptr->next;
if (ptr == NULL)
return NULL;
numItem--;
}
return ptr;
}
// Elimina l'elemento specificato dalla lista.
// Se l'elemento non esiste o la lista contiene un solo elemento,
// ritorna -1, altrimenti 0.
// NOTA: Non è mai possibile eliminare il primo elemento (quello in
// posizione 0, anche se la lista ne contiene di più).
short int removeItem(unsigned int numItem)
{
struct GAMEMSG_OKAY *oldPtr = NULL;
struct GAMEMSG_OKAY *ptr = this;
// Cerco l'elemento interessato.
while (numItem > 0)
{
oldPtr = ptr;
ptr = ptr->next;
if (ptr == NULL)
// L'elemento richiesto non esiste.
return -1;
numItem--;
}
if (oldPtr != NULL)
{
// Tutto ok, rimuovo l'elemento.
oldPtr->next = ptr->next;
delete ptr;
return 0;
}
else
// La lista contiene solo un elemento (non eliminabile...).
return -1;
}
}; // END OF struct GAMEMSG_OKAY
// Esempio d'uso. Non controllo i possibili errori, per quanto i "metodi"
// lo permettano: comunque eventuali errori sono causati da
// errati parametri passati.
struct GAMEMSG_OKAY *anItem;
// NOTA: values rappresenta sempre il primo elemento (la testa della lista).
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
values->addItem();
values->addItem();
// Ora abbiamo 3 elementi nella lista. Inizio a "divertirmi" :)
anItem = values->getItem(1);
// Nota l'importanza dei costruttori: se omettessi la seguente riga,
// wNum varrebbe poi 0 (e non un valore indefinito... - anche se
// normalmente i compilatori c++ settano automaticamente tutte le variabili
// non inizializzate esplicitamente a 0, ma noi facciamo i precisini, quindi... ;)
anItem->dwType = 5;
DWORD wNum = anItem->dwType;
bool bVal = anItem->IF;
values->removeItem(1);
// Nulla mi vieta di fare...
anItem = values->addItem();
// ...e settare direttamente (senza dover fare getItem()):
anItem->IF = true;
} // END OF main
Come vedi, il codice risulta anche più compatto.
Per essere precisi, bisogna prevedere un distruttore per la struttura GAMEMSG_OKAY (dal momento che alloca memoria che poi diverrebbe irraggiungibile, portando a memory leak). E' molto semplice da fare, lascio a te il compito, se poi hai problemi ti dò volentieri qualche suggerimento ;)
EDIT: comunque secondo me è rischioso poter cancellare un qualunque elemento dell'array dinamico, invece che solo l'ultimo, perché altrimenti perdi l'ordine dei valori. Se ad esempio crei 3 elementi (numerati quindi 0, 1 e 2), e poi rimuovi il secondo elemento (in posizione 1), quello in poizione 2 passa in posizione 1 ( quindi altri eventuali valori scalano di una posizione indietro). Conseguentemente, una getItem(1) ti darà il valore dell'elemento che prima era in posizione 2. Secondo me può portare ad incasinarsi nella scrittura del resto del tuo codice. Poi se ti serve così... :) Altrimenti usi la removItem del post precedente (che cancellava sempre e solo l'ultimo elemento della lista).
Innanzitutto grazie per il tut...
ti dico a cosa mi serve.
Il tut che hai fatto è proprio ok ben fatto.
Adopero un server e client e questo sotto sono le strutture per sapere:
#define GAME_MSGID_DELETE 8
#define GAME_MSGID_CREATE 9
#define GAME_MSGID_OKAYIT 10
// bytes allineati pop
#pragma pack( push, 1 )
struct GAMEMSG_GENERIC
{
DWORD dwType; //numero del valore
};
struct GAMEMSG_OKAY : public GAMEMSG_GENERIC
{
int idN; // id del player
bool IF[8];
//...altri dati
};
struct GAMEMSG_CREATE_PLAYER : public GAMEMSG_GENERIC
{
int idN; // id del player
};
struct GAMEMSG_DESTROY_PLAYER : public GAMEMSG_GENERIC
{
int idN; // id del player
};
// Pop the old pack alignment
#pragma pack( pop )
quando invio o ricevo estraggo il valore di dwType e faccio ciò che serve entrando nell'if interessato.
come vedi bool IF[8]; l'ho messo fino ad un max di 7 player.
il sizeoff della struttura è 980 bytes mi è stato richiesto e detto di togliere [8] per tutti i dati e iniziarlo a NULL e incremntare,o decrementare (uscita del player) a runtime per avere meno di 980 bytes da inviare (chiaro che incrementando i player > i bytes della struttura da inviare che possono essere anche maggiori di 980 bytes).
Il sistema della lista è ottimo per questo ma come dici tu potrebbe incasinarsi in un sistema di client server con chiari problemi di non capirci + niente.
Io per ora lo lascio come ho fatto cmq mi studio ciò che hai postato... poi vedo un pò cosa fare.
i client che si loggano vanno in testa naturalmente e naturalmente possono uscire e può essere che su 3 esca il 2 quindi devo scalare il 3 al 2. Quando si rilogga il 3 non deve andare in coda ma in testa.
cmq detto questo secondo te è meglio implementare ciò che hai scritto oppure è meglio lasciarlo come ho fatto, a titolo informativo, secondo il tuo punto di vista?
ciao
Il mio punto di vista è usare una lista, nel modo che ho postato prima (l'ultimo codice). Alla fine la differenza sta nell'aggiungere un elemento alla lista con addItem (se richiesto), e prenderlo con variabile->getItem[numero]->IF invece che con variabile[numero].IF...
Il casino a mio parere risiederebbe nella possibilità di eleminare un qualunque elemento della lista, invece che l'ultimo in automatico. Ti conviene, secondo me, usare l'ultimo codice da me postato, ma sostituendo il "metodo" removeItem(unsigned int) con la removeItem(void) del primo codice postato. Così sei tranquillo ed usi la struct in pratica come se fosse statica.
Faccio un esempio di uso pratico.
Metodo tradizionale:
struct GAMEMSG_OKAY values;
values[0].IF = true;
values[0].dwType = 3;
values[1].IF = true;
values[1].dwType = 7;
values[2].IF = false;
Con la struct postata prima:
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
values->getItem(0)->IF = TRUE; // Caso particolare: essendo values la testa della lista, puoi fare anche "values->IF = TRUE", ma per farti capire un uso generico...
values->getItem(0)->dwType = 3;
values->addItem();
values->getItem(1)->IF = true;
values->getItem(1)->dwType = 7;
values->addItem();
values->getItem(2)->IF = false;
// Ora se l'elemento 2 non ti serve più...
values->removeItem();
// Però nessun casino, perchè la posizione degli elementi (ed i valori memorizzati) rimangono immutati!
EDIT: nota che la getItem() torna NULL se l'elemento richiesto non è presente, quindi puoi anche fare un controllo errori, se ad esempio vuoi prendere l'elemento in posizione 7 in una lista di 5 elementi...
EDIT 2: Attenzione però se mandi la struttura via socket! Quello è solo un puntatore a memoria allocata sul tuo sistema, se mandi quello mandi solo e sempre 4 bytes (8 su sistemi a 64 bit) contenenti l'indirizzo...
A questo punto, devi anche prevedere l'invio della struttura (ma è banale).
EDIT 3: rileggo meglio le tue richieste e modifico la struttura di conseguenza.
Cosa intendi quando dici che i client nuovi vanno in testa? nel senso che, ogni volta che un client si logga, tu devi prevedere un nuovo valore di IF e questo deve essere il primo della lista (per intenderci nel modo tradizionale, IF[0])?
Cosa intendi quando dici che i client nuovi vanno in testa? nel senso che, ogni volta che un client si logga, tu devi prevedere un nuovo valore di IF e questo deve essere il primo della lista (per intenderci nel modo tradizionale, IF[0])?
ciao
esempio (naturalmente sia il client che il server hanno le stesse struct identiche)... questo è chiaro ;)
- Il server è avviato tutto è a NULL.
- Il cient si avvia ma ancora è tutto a NULL.
si logga il primo client che viene accettato dal server che implementa
IF[0]=true;
il client riceve l'OK che è stato accettato, ora anche il client avrà
IF[0]=true;
si logga il secondo client che viene accettato dal server che implementa
IF[1]=true;
il client riceve l'OK che è stato accettato, ora anche il client avrà
IF[1]=true;
[2] poi [3] ecc ecc.
su 4 client esce il n. 2
sul server la routine di logoff
a [0] rimane il primo client
a [1] rimane il secondo
a [2] passa il terzo
a [3] passa il quarto
sui client stessa cosa
se si rilogga qualcunaltro va in testa ovvero sarà il [4]
ciao
esempio (naturalmente sia il client che il server hanno le stesse struct identiche)... questo è chiaro ;)
- Il server è avviato tutto è a NULL.
- Il cient si avvia ma ancora è tutto a NULL.
si logga il primo client che viene accettato dal server che implementa
IF[0]=true;
il client riceve l'OK che è stato accettato, ora anche il client avrà
IF[0]=true;
si logga il secondo client che viene accettato dal server che implementa
IF[1]=true;
il client riceve l'OK che è stato accettato, ora anche il client avrà
IF[1]=true;
[2] poi [3] ecc ecc.
su 4 client esce il n. 2
sul server la routine di logoff
a [0] rimane il primo client
a [1] rimane il secondo
a [2] passa il terzo
a [3] passa il quarto
sui client stessa cosa
se si rilogga qualcunaltro va in testa ovvero sarà il [4]
Benissimo, allora il codice del mio post #8 fa proprio al caso tuo ;)
Comunque vedo che abbiamo un'idea diversa di testa e di coda di una lista: a me hanno insegnato che, in una lista di ad esempio 4 elementi, l'elemento in posizione 0 è la testa, quello in posizione 3 è la coda :) Guarda caso, il mio codice inserisce i nuovi elementi in coda, che è la tua testa... Comunque è lui, prova ad usarlo, e ricorda: per leggere o scrivere il valore di un paramentro nella struct di un qualsiasi elemento in qualsiasi posizione, ti basta fare:
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
...
// Aggiungo elementi...
...
values->getItem(2)->IF = true; // Assegnazione.
DWORD type = values->getItem(3)->dwType; // Lettura.
invece di:
struct GAMEMSG_OKAY *values = new struct GAMEMSG_OKAY;
struct GAMEMSG_OKAY item;
...
// Aggiungo elementi...
...
item = values->getItem(2);
item->IF = true;
item = values->getItem(3);
DWORD type = item->dwType;
Comunque vedo che abbiamo un'idea diversa di testa e di coda di una lista
Non mi trovo in postazione per verificare il for sulla lista.
ma ricordo di avere un piccolo listato didattico per le liste (devo vedere...) con inserimento (come a te hanno insegnato... la famosa pila forse intendi?) degli elementi in coda e facendo il for(++) per la stampa di 3 elementi inseriti mi ritrovavo 2 1 0. Al che lo rifeci con inserimento in testa quindi nel for(++) mi stampava 0 1 2 che era appunto cioò che volevo.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.