View Full Version : Un ripasso in "C"
scusate se vi chiedo cose banali ma èda un pò che non programmo :(
parlando di strutture ........
struct nome_non_obbligatorio{
int età;
char nome[50];
} nome_struttura;
e se voglio allocare 50 strutture di quel tipo scrivo:
struct nome_struttura[50];
giusto ?
e se desidero allocare 'n' strutture dinamicamente ?
qui ahimè on mi ricordo più nulla :(
grazie 1000
RaouL_BennetH
08-02-2005, 13:10
per l'allocazione dinamica delle strutture, è una cosa che sinceramente non ho ancora mai studiato (considera però che il C lo studio proprio da poco) ma, volendo ragionare di 'fantasia' (anzi, di ignoranza...) mi viene da pensare che potresti farlo con i puntatori e con malloc.
Faccio un esempio, ma non so proprio se possa essere corretto:
typedef struct STRUTTURA *PSTRUTTURA;
PSTRUTTURA variabile = (PSTRUTTURA)malloc(sizeof(struct STRUTTURA));
di sicuro ho scritto una grande, enorme, cassata, ma spero apprezzerai l'inutile contributo di char che ho dato al tuo post :)
Piccolo edit per il codice da te postato:
struct nome_non_obbligatorio{
int età;
char nome[50];
} nome_struttura;
Non è proprio così:
dove tu dici "nome_struttura", non è il nome (etichetta della struttura) ma l'istanza.
Poi, se non erro una struttura deve necessariamente avere un'etichetta (quella che tu hai chiamato "nome_non_obbligatorio").
Quindi:
struct etichetta {
variabili.......
} istanza ;
e, sempre se ho capito bene le strutture, puoi evitare inizialmente di dichiarare un'istanza, ma non un'etichetta (il nome della struttura).
Ziosilvio
08-02-2005, 13:54
Originariamente inviato da misterx
struct nome_non_obbligatorio{
int età;
char nome[50];
} nome_struttura;
Questo dichiara una variabile di nome "nome_struttura" e tipo "struct nome_non_obbligatorio".
Se ti interessa che nome_struttura sia un altro nome per struct nome_non_obbligatorio, devi cominciare la definizione con la parola typedef.
e se desidero allocare 'n' strutture dinamicamente ?
Ammettiamo che tu abbia usato typedef, e che nome_struttura sia un altro nome per struct nome_non_obbligatorio.
Se vuoi allocare dinamicamente n oggetti di tipo nome_struttura, ordinati in un vettore, devi dichiarare un puntatore a puntatori a nome_struttura:
nome_struttura **ns;
allocare una sequenza di n puntatori a nome_struttura:
ns = malloc(n*sizeof(nome_struttura*));
e allocare, a partire da ciascuno di essi, un oggetto di tipo nome_struttura:
for (i=0; i<n; i++)
ns[i] = malloc(sizeof nome_struttura);
Fa' attenzione, perché per comodità non ho scritto la gestione delle eccezioni.
Originariamente inviato da Ziosilvio
scusa Ziosilvio, ma è meglio se uso un ulteriore esempio meno teorico e più pratico in quanto mi sono perso :)
struct {
int età;
char nome[50];
} agenda;
supponiamo di avere in un file i seguenti dati:
22 annalisa
35 patrizia
30 anna
40 aldo
45 giovanni
50 giacomo
e di volerli memorizzare dinamicamente nella struttura sopra; ovviamente io, non conosco a priori il numero di strutture da allocare in memoria, quindi, si dovrà ricorrere alla malloc()
ahimè, non mi ricordo nella maniera più assoluta come dichiarare un "array" di puntatori (**ptr???) che punteranno alle n-esime strutture :muro:
Ziosilvio
08-02-2005, 21:46
Originariamente inviato da misterx
struct {
int età;
char nome[50];
} agenda;
Con questa sintassi, agenda è il nome di una variabile, non di un tipo; e non puoi dichiarare un array di variabili di un tipo senza nome.
Dovresti fare così:
typedef struct agenda {
int age;
char name[50];
} agenda;
Questo codice contemporaneamente definisce un tipo strutturato di nome "struct agenda", e un nome alternativo "agenda" per tale tipo.
supponiamo di avere in un file i seguenti dati:
22 annalisa
35 patrizia
30 anna
40 aldo
45 giovanni
50 giacomo
e di volerli memorizzare dinamicamente nella struttura sopra; ovviamente io, non conosco a priori il numero di strutture da allocare in memoria, quindi, si dovrà ricorrere alla malloc()
Se non conosci a priori né il numero di righe né un massimo per tale numero, allora dovresti usare una lista, non un array.
Oppure: ricavare il numero delle righe del file, e allocare dinamicamente un array di tanti puntatori ad agenda quante sono le righe del file.
ahimè, non mi ricordo nella maniera più assoluta come dichiarare un "array" di puntatori (**ptr???) che punteranno alle n-esime strutture :muro:
Sì, la sintassi è proprio quella.
non ho mai usato le liste, che vantaggio offrono ?
Ziosilvio
09-02-2005, 08:34
Originariamente inviato da misterx
non ho mai usato le liste, che vantaggio offrono ?
Vantaggi: allochi tutta e sola la memoria che ti serve davvero.
Svantaggi: fare una ricerca diventa più dispendioso in termini di tempo.
grazie ziosilvio
una domanda sulla scanf()
stavo facendo delle prove di input con la scanf e non mi è chiaro il suo comportamento; se passo a questa:
scanf("%c %d %d %d %s",&carattere, &a, &b, &c, &s);
t 123 456 678 pippo
tra un parametro e l'altro vi sono più di uno spazio, ma scanf() li vede come se fossero separati da uno solo; è corretto questo suo comportamento ? (in pratica lavora per me togliendomi gli spazi ridondanti ?)
se ora digito:
<spazio>t 123 456 678 pippo
con uno spazio iniziale (prima della lettera 't'), viene generato un output senza senso del tipo:
"4260124 4232996 4247784"
ha senso tutto ciò ?
ultima domanda
se dalla scanf() scritta sopra desidero che il parametro '%s' stringa possa essere di lunghezza variabile a piacere dell'utente, come dichiaro la variabile 's' ?
Fenomeno85
11-02-2005, 10:24
allora la funzione scanf è la + pericolosa che c'è ... cmq la dimesione della stringa è definita con una lunghezza e sforare la lunghezza significa fare danni.
Il miglior modo per le stringhe è questo:
fgets (stdin, sString, iLung);
ricordati che se dichiari una stringa di N elementi, quindi diciamo che iLung = N i caratteri massimi che puoi scriverci sono N-1 dato che la funzione che ti ho postato mette già il terminatore di stringa il /0.
~§~ Sempre E Solo Lei ~§~
ma io devo per forza usare la scanf() :muro:
Fenomeno85
11-02-2005, 10:36
ah cmq in casi in cui non puoi sapere a priori il numero degli elementi si ricorre per forza ad allocazioni dinamiche.
Ti metto modificato per il tuo semplice caso:
#define N 50
typedef struct Info{
int iAge;
char cName[N];
}Data;
typedef struct EL{
Data Info;
struct EL *pNext;
} Node;
/* visualizza la lista */
void See_List (Node *pHead){
while (pHead != NULL){
/* visualizza tutti i campi che ti interessano */
printf ("%s\t%d",pHead->Info.cName, pHead->Info.iAge);
}
}
/* inserimento in testa */
void Insert_Element (Node **pHead, Data Value){
Node *pApp;
pApp = malloc (sizeof(Node));
pApp->Info = Value;
if (*pHead == NULL){
pApp->pNext = NULL;
*pHead = pApp;
}
else{
pApp->pNext = *pHead;
*pHead = pApp;
}
}
/* main */
int main (void){
Node *Head;
/* funtion */
return (0);
}
Non l'ho compilato l'ho fatto in due minuti ma dovrebbe essere tutto corretto.
Se hai domande chiedi pure.
~§~ Sempre E Solo Lei ~§~
Fenomeno85
11-02-2005, 10:37
Originariamente inviato da misterx
ma io devo per forza usare la scanf() :muro:
posso sapere il perchè??
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
posso sapere il perchè??
~§~ Sempre E Solo Lei ~§~
è per un progetto ed è vivamente consigliato l'uso della scanf() per via della formattazione
nelle specifiche del progetto mi si dice che l'input sarà sempre corretto, quindi, nessuna necessità di un controllo, ma, l'ulimo parametro della scanf() deve essere una stringa della quale non si conosce a priori la sua lunghezza
potrei usare un:
char *s;
ma punterebbe a cosa ?
Fenomeno85
11-02-2005, 10:51
va be però la dimensione la devi per forza mettere dato che una stringa la devi mettere sotto un array oppure metterla dinamicamente non ne ho la + pallida idea e non so neanche se è possibile :wtf:
~§~ Sempre E Solo Lei ~§~
Ziosilvio
11-02-2005, 10:51
Originariamente inviato da misterx
una domanda sulla scanf()
stavo facendo delle prove di input con la scanf e non mi è chiaro il suo comportamento; se passo a questa:
scanf("%c %d %d %d %s",&carattere, &a, &b, &c, &s);
t 123 456 678 pippo
tra un parametro e l'altro vi sono più di uno spazio, ma scanf() li vede come se fossero separati da uno solo; è corretto questo suo comportamento ? (in pratica lavora per me togliendomi gli spazi ridondanti ?)
Sì, è corretto.
Nella tua chiamata, scanf si aspetta una stringa costituita da un carattere, tre numeri interi, e una stringa, separati l'uno dall'altro da uno o più caratteri di spaziatura.
Comunque io userei questa sintassi:
scanf("%c%d%d%d%s",&carattere,&a,&b,&c,&s");
se ora digito:
<spazio>t 123 456 678 pippo
con uno spazio iniziale (prima della lettera 't'), viene generato un output senza senso del tipo:
"4260124 4232996 4247784"
ha senso tutto ciò ?
Sì, ha senso.
Lo spazio è un carattere, quindi scanf scrive ' ' in &carattere.
Dopodiché dovrebbe leggere uno spazio, invece si ritrova 't', quindi termina senza modificare gli altri valori.
ultima domanda
se dalla scanf() scritta sopra desidero che il parametro '%s' stringa possa essere di lunghezza variabile a piacere dell'utente, come dichiaro la variabile 's' ?
Devi costruirti "a mano" la stringa di formato (cioè il primo parametro di scanf), facendo in modo che tra '%' ed 's' ci sia una sequenza di cifre che rappresenta la lunghezza massima della stringa.
Originariamente inviato da Fenomeno85
va be però la dimensione la devi per forza mettere dato che una stringa la devi mettere sotto un array oppure metterla dinamicamente non ne ho la + pallida idea e non so neanche se è possibile :wtf:
~§~ Sempre E Solo Lei ~§~
io l'ho trovato un sistema per catturare l'input "ridontante" della scanf() :)
Fenomeno85
13-02-2005, 09:36
Originariamente inviato da misterx
io l'ho trovato un sistema per catturare l'input "ridontante" della scanf() :)
vai spara mi interessa saperlo
~§~ Sempre E Solo Lei ~§~
Originariamente inviato da Fenomeno85
vai spara mi interessa saperlo
~§~ Sempre E Solo Lei ~§~
quello che chiedevo in definitiva era questo:
#include <stdio.h>
#include <stdlib.h>
char *creaparola(int carattere, char terminatore);
int main()
{
char comando, *buf;
int a, b ,c;
int carattere;
printf("Digita una comando: ");
scanf("%c%d%d%d%c",&comando, &a, &b, &c, &carattere);
buf = creaparola(carattere,'\n');
printf("%c %d %d %d %s",comando, a, b, c, buf);
return 0;
}
/****************************************************************************/
char *creaparola(int carattere, char terminatore)
{
char *buf='\0';
int i = 0;
while((carattere = getchar()) != terminatore){
buf = (char *) realloc(buf, i+1);
buf[i++] = (char)carattere;
}
buf[i]='\0';
return buf;
}
Fenomeno85
13-02-2005, 10:07
ok ma ti appoggi sempre a una funzione esterna quindi è inutile prendere il carattere nello scanf.
Comunque il mio consiglio è quello di non mettere i prototipi ma di usare una gerarchia quale: le funzioni chiamate sono sempre sopra le funzioni chiamanti. Se diventa molto lungo il progetto sai almeno dove cercare e diventa + leggibile.
~§~ Sempre E Solo Lei ~§~
questa porzione di codice, riempie una lista dall'alto verso il basso nel senso che, l'ultimo elemento ad entrare è anche il primo ad uscire quindi, lista di tipo LIFO
Ma come diamine si fa a riempirla al contrario ?
Ho provato a memorizzare un puntatore alla struttura chiamato "old" di modo che la struttura precedente riceva prima di una nuova allocazione l'indirizzo della nuova struttura; ma perchè diamine non funziona ?
struct punti {
int x1, y1;
char *nomepunto;
struct punti *next;
} ;
typedef struct punti punti ;
punti *testapnt = NULL, *tmppnt;
punti *old = NULL;
void punto(int x1 , int y1, char *nomepunto){
if(old != NULL)
tmppnt->next = old;
tmppnt= (punti *) malloc(sizeof(punti ));
tmppnt->x1 = x1;
tmppnt->y1 = y1;
tmppnt->nomepunto= nomepunto;
tmppnt->next = NULL; // casomai la lista finisce, eventualmente il NULL viene sovrascritto da "old"
old = tmppnt; // memorizzo indirizzo precedente
(if testapnt == NULL)
testapnt = tmppnt;
}
Fenomeno85
13-02-2005, 11:39
// per il nodo standardizzalo mettendo solo il puntatore al prossimo nodo e una struttura che contiene tutti i dati.
typedef struct Info{
int x, y;
char *nomepunto;
}Data;
typedef struct EL {
Data Info;
struct EL *pNext;
} Node;
void Punto (Data Information, Node **pHead){
Node *App;
Node *last;
App = (Node*)malloc(sizeof(Node));
App->Info = Information;
App->pNext = NULL;
last = *pHead;
if (last == NULL){
*pHead = App;
}
else{
while (last!=NULL && last->pNext != NULL){
last=last->pNext;
}
last->pNext = App;
}
}
Così funziona.
~§~ Sempre E Solo Lei ~§~
grazie fenomeno85 ma trovo molto più semplici le liste, soprattutto perchè ho poco tempo a disposizione per terminare il mio progetto
Fenomeno85
14-02-2005, 10:11
Originariamente inviato da misterx
grazie fenomeno85 ma trovo molto più semplici le liste, soprattutto perchè ho poco tempo a disposizione per terminare il mio progetto
il codice che ti ho postato era per le liste
~§~ Sempre E Solo Lei ~§~
riuscite a dirmi perchè "EliminaRettangoli()" nella fase di deallocazione mi genera un'eccezione ?
void AggiungiRettangolo(int x1 , int y1, int x2, int y2)
{
tmp_rect= malloc(sizeof(rettangoli));
tmp_rect->x1 = x1;
tmp_rect->y1 = y1;
tmp_rect->x2 = x2;
tmp_rect->y2 = y2;
tmp_rect->next = testa_rect;
testa_rect = tmp_rect;
}
void EliminaRettangoli()
{
tmp_rect = testa_rect; // mi posiziono in cima alla lista
while(tmp_rect != NULL)
{
free(tmp_rect);
tmp_rect = tmp_rect->next;
}
}
scusate ma ho risolto da me.....
ho capito il meccanismo, poi vi posto il motivo del mio errore :)
ok, tutto chiaro
void EliminaRettangoli()
{
rettangoli *prev;
tmp_rect = testa_rect; // mi posiziono in cima alla lista
while(tmp_rect != NULL)
{
prev = tmp_rect->next;
free(tmp_rect);
tmp_rect=prev;
}
}
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.