PDA

View Full Version : [C]Alcuni dubbi sulle strutture


Composition86
30-08-2008, 15:09
Sto tentando di far funzionare il seguente programma:

#include <stdio.h>

struct part {
int partNumber;
char *partName[25];
};

typedef struct part Part;

main()
{
struct part a;
char pause;

printf ("Inserire un numero ed una stringa:\n");
scanf ("%d%s", &a.partNumber, &a.partName);
printf ("%d e %s", a.partNumber, *a.partName);

printf ("\nPremere una lettere per terminare il programma.\n");
scanf ("%c", &pause);
return 0;
}
Purtroppo non riesco ad immagazzinare un numero ed una stringa, come richiesto dal gruppo di istruzioni centrale, nonostante penso che la sintassi di scanf e printf sia corretta. Qualche idea?


Inoltre mi sapete dire per quale motivo nella riga
printf ("%d e %s", a.partNumber, *a.partName);
non è necessario l'asterisco per il numero mentre è necessario per poter visualizzare la stringa?
Il mio libro per le stringhe utilizza 3 diverse notazioni (le ultime due utilizzano un puntatore alla struttura), tutte PRIVE di asterisco iniziale:
printf ("%s", a.partName);
printf ("%s", ptr->partName);
printf ("%s", (*ptr).partName);

DanieleC88
30-08-2008, 16:56
struct part {
int partNumber;
char *partName[25];
};
Attenzione... qui cosa stai dichiarando? Un'array statica di 25 caratteri? Un puntatore ad una zona di memoria allocata per 25 caratteri? 25 puntatori a memoria allocata per un puntatore a caratteri? A te riconoscere cos'è. :D

Morale della favola: mi sa che hai usato un asterisco in più. :p

Composition86
30-08-2008, 17:03
La mia idea era di utilizzarlo come un vettore che potesse contenere una stringa ed in effetti, così come l'ho definito, ne dovrebbe poter contenere 25, cosa inutile.
L'ho corretto in:
char partName
eliminando anche l'asterisco dalla scanf, ma il programma continua a bloccarsi.

sirus
30-08-2008, 17:37
#include <stdio.h>
#include <stdlib.h>

struct part {
int partNumber;
char partName[25];
};

int main(int argc, char **argv) {
struct part p;

scanf("%d", &p.partNumber);
scanf("%s", p.partName);
printf("\nPart Number:\t%d", p.partNumber);
printf("\nPart Name:\t%s", p.partName);
printf("\n");

return 0;
}

Una variabile dichiarata come:
char *partName[25];
è un array di 25 puntatori a carattere, potenzialmente può contenere fino a 25 stringhe ma devi allocare dinamicamente lo spazio necessario per contenerle. Invece una variabile dichiarata come:
char partName[25];
è una stringa da 24 caratteri (il 25° è il terminatore).

PS: utilizzare typedef e poi usare struct <nomestruttura> non ha molto senso. ;)

Composition86
30-08-2008, 18:54
Purtroppo queste strutture mi stanno dando parecchi grattacapi, è l'ultimo argomento che devo affrontare per l'esame, ma che fatica. :(

Si, ho corretto tutto ed ho capito le varie differenze, ma purtroppo il programma da te postato mi da' ancora il classico errore di XP!
Ed inoltre mi spieghi perchè ad una scanf hai utilizzato l'ampersand ed all'altra no?

marko.fatto
30-08-2008, 19:24
perchè partName è già un puntatore a carattere (al primo di 25)

Composition86
30-08-2008, 22:47
perchè partName è già un puntatore a carattere (al primo di 25)
Ok, grazie.


Vorrei aggiungere un po' di domande, ammetto che sto trovando l'argomento strutture un po' complicato.
Sto cercando di realizzare un programma (ancora incompleto) che mi archivi i dati di 5 persone, cioè nome cognome ed età:
//Gestione di un archivio di persone
#include <stdio.h>

struct persona {
char *nome[5];
char *cognome[5];
int *eta[5];
};

typedef struct persona Persona;

struct persona dati[5];

void chiediDati (Persona *);

main()
{
char pause;
int i;

printf ("Verranno ora richiesti i dati anagrafici relativi a 5 persone\n\n");

for (i = 0 ; i <= (5 - 1) ; i++) {
printf ("Inserire nome\n");
scanf ("%s", (*dati).nome);
printf ("Inserire cognome\n");
scanf ("%s", (*dati).cognome);
printf ("Inserire eta'\n");
scanf ("%d", &(*dati).eta);
}

for (i = 0 ; i <= (5 - 1) ; i++) {
printf ("Dipendente %d", i);
printf ("Nome: %s",(*dati).nome );
printf ("Cognome: %s",(*dati).cognome);
printf ("Eta': %d", (*dati).eta);
}


printf ("Inserire una lettera per terminare");
scanf ("%c", &pause);
return 0;
Ma qui ho veramente tanti dubbi;
1) La struttura: al suo interno compaiono due vettore di 5 puntatori a carattere che mi servono per nome e cognome ed un vettore di 5 puntatori a numero per l'età: è corretto?
2) Il primo ciclo for: funziona correttamente, ma per puro caso, in quanto ho dovuto introdurre quegli asterischi nelle scanf, andando contro ciò che mi sembrava di aver capito dalla teoria: mi potreste spiegare a cosa servono e se si può avere un'altra forma che non ne faccia uso?
3) Il secondo ciclo for: non funziona e non ho idea sul come farlo funzionare. Se uso la forma del tipo
printf ("Nome: %s", dati.nome );
printf ("Cognome: %s",dati.cognome);
printf ("Eta': %d", dati.eta);
senza parentesi ed asterischi ho un errore di questo tipo:
request for member `nome' in `dati', which is of non-aggregate type `persona[5]'

Ditemi voi, la confusione è abbastanza.

DanieleC88
30-08-2008, 23:08
Aspetta, mi sa che stai facendo casino con i tipi. Una struttura non fa altro che definire un'area di memoria che è "strutturata" in diversi campi. Definisci la strutturazione dei campi e i tipi che questi contengono, e poi definisci la struttura intera come fosse una variabile comune. Solo, i singoli campi li leggi accedendo al loro nome con la forma "variabile.campo". Se hai un puntatore alla struttura, o la dereferenzi esplicitamente ("(*variabile).campo") o usi l'operatore freccia ("variabile->campo").
struct esempio
{
int numero;
char stringacorta[10];
};

int main()
{
struct esempio *var1;
struct esempio var2;

var2.numero = 123;
var2.stringacorta = "Ciao!";
var1 = &var2;

printf("%s\n", var2.stringacorta);
printf("%d\n", var1->numero);
return 0;
}

Poi, le stringhe in C sono semplicemente zone contigue di memoria contenenti caratteri: quando ne conosci a priori la dimensione massima, puoi usare un'array statica (char stringa[dimensione]), altrimenti devi ricorrere ai puntatori (char *stringa = malloc(dimensione * sizeof(char))). Ciò che facevi prima (e che hai ripetuto nel tuo ultimo pezzo di codice) è stato definire un'array di puntatori a caratteri come campo della struttura, il che non ha molto senso nell'esempio che hai postato. :)

sirus
31-08-2008, 09:16
Si, ho corretto tutto ed ho capito le varie differenze, ma purtroppo il programma da te postato mi da' ancora il classico errore di XP!
Su Windows non ho provato ma su Linux non mi ha dato problemi e sinceramente fatico a trovare un possibile problema in quel programma (a meno di un inserimento errato dei dati visto che la scanf non è proprio la funzione più sicura).

Ed inoltre mi spieghi perchè ad una scanf hai utilizzato l'ampersand ed all'altra no?
Il concetto è semplice.
Alla scanf tu devi passare un parametro (o più di uno) in scrittura. Per realizzare questo tipo di passaggio di parametro in C è necessario ricorrere al passaggio per indirizzo. Il simbolo & davanti ad una variabile semplice significa “prendi l’indirizzo di memoria di questa variabile”, se con una variabile di tipo int ha senso, con una variabile di tipo array di char (ma in generale con qualsiasi tipo di array) non ha senso dato che il nome con cui ti riferisci all’array (nel nostro caso partName) indica già un indirizzo di memoria.
Se invece di aver acquisito una stringa con la scanf avessi voluto acquisire un singolo caratteri avrei scritto:
scanf(“%c”, &partName[0]);
in questo caso il simbolo & è necessario perché con partName[0] mi riferisco ad una precisa cella di memoria mentre con partName ad un indirizzo.


Ma qui ho veramente tanti dubbi;
1) La struttura: al suo interno compaiono due vettore di 5 puntatori a carattere che mi servono per nome e cognome ed un vettore di 5 puntatori a numero per l'età: è corretto?
2) Il primo ciclo for: funziona correttamente, ma per puro caso, in quanto ho dovuto introdurre quegli asterischi nelle scanf, andando contro ciò che mi sembrava di aver capito dalla teoria: mi potreste spiegare a cosa servono e se si può avere un'altra forma che non ne faccia uso?
3) Il secondo ciclo for: non funziona e non ho idea sul come farlo funzionare. Se uso la forma del tipo
printf ("Nome: %s", dati.nome );
printf ("Cognome: %s",dati.cognome);
printf ("Eta': %d", dati.eta);
senza parentesi ed asterischi ho un errore di questo tipo:
request for member `nome' in `dati', which is of non-aggregate type `persona[5]'

Ditemi voi, la confusione è abbastanza.
Intanto rivedrei un po’ il codice...
#include <stdio.h>

struct persona {
char nome[25];
char cognome[25];
int eta;
};

struct persona dati[5];

main() {
char pause;
int i;

printf ("Verranno ora richiesti i dati anagrafici relativi a 5 persone\n\n");

for (i = 0; i < 5; i++) {
printf ("Inserire nome\n");
scanf ("%s", dati[i].nome);
printf ("Inserire cognome\n");
scanf ("%s", dati[i].cognome);
printf ("Inserire eta\n");
scanf ("%d", &dati[i].eta);
}

for (i = 0; i < 5; i++) {
printf("Dipendente %d\n", i);
printf("Nome: %s\n", dati[i].nome );
printf("Cognome: %s\n", dati[i].cognome);
printf("Eta': %d\n", dati[i].eta);
}


printf ("Inserire una lettera per terminare");
scanf ("%c", &pause);
return 0;
}
dichiarare una struttura dati come quella che avevi scritto per un caso del genere non aveva senso, come prima, utilizzare typedef e poi struct <nomestruttura> non ha senso, tranto vale evitare il typedef, (1) non capisco perché ti accanisci nell’utilizzare i puntatori anche quando non è necessario (a meno che non è l’esercizio che te lo chiede, in tal caso dovresti ricorrere all’allocazione dinamica). Alle altre domande ti ha già risposto DanieleC88. ;)

Composition86
31-08-2008, 11:03
Aspetta, mi sa che stai facendo casino con i tipi. Una struttura non fa altro che definire un'area di memoria che è "strutturata" in diversi campi. Definisci la strutturazione dei campi e i tipi che questi contengono, e poi definisci la struttura intera come fosse una variabile comune. Solo, i singoli campi li leggi accedendo al loro nome con la forma "variabile.campo". Se hai un puntatore alla struttura, o la dereferenzi esplicitamente ("(*variabile).campo") o usi l'operatore freccia ("variabile->campo").

Poi, le stringhe in C sono semplicemente zone contigue di memoria contenenti caratteri: quando ne conosci a priori la dimensione massima, puoi usare un'array statica (char stringa[dimensione]), altrimenti devi ricorrere ai puntatori (char *stringa = malloc(dimensione * sizeof(char))). Ciò che facevi prima (e che hai ripetuto nel tuo ultimo pezzo di codice) è stato definire un'array di puntatori a caratteri come campo della struttura, il che non ha molto senso nell'esempio che hai postato. :)
Ok, stiamo già risolvendo qualche dubbio.

Su Windows non ho provato ma su Linux non mi ha dato problemi e sinceramente fatico a trovare un possibile problema in quel programma (a meno di un inserimento errato dei dati visto che la scanf non è proprio la funzione più sicura).
Ieri era il dev che faceva casini (mi capita che esegue la versione precedente dello stesso programma, anche se non "dovrebbe" più essercene traccia in memoria): tutti e due i programmi funzionano a dovere, adesso ho qualcosa con cui confrontare. ;)

Il concetto è semplice.
Alla scanf tu devi passare un parametro (o più di uno) in scrittura. Per realizzare questo tipo di passaggio di parametro in C è necessario ricorrere al passaggio per indirizzo. Il simbolo & davanti ad una variabile semplice significa “prendi l’indirizzo di memoria di questa variabile”, se con una variabile di tipo int ha senso, con una variabile di tipo array di char (ma in generale con qualsiasi tipo di array) non ha senso dato che il nome con cui ti riferisci all’array (nel nostro caso partName) indica già un indirizzo di memoria.
Se invece di aver acquisito una stringa con la scanf avessi voluto acquisire un singolo caratteri avrei scritto:
scanf(“%c”, &partName[0]);
in questo caso il simbolo & è necessario perché con partName[0] mi riferisco ad una precisa cella di memoria mentre con partName ad un indirizzo.
Ok, questa parte adesso è chiara.


dichiarare una struttura dati come quella che avevi scritto per un caso del genere non aveva senso, come prima, utilizzare typedef e poi struct <nomestruttura> non ha senso, tranto vale evitare il typedef, (1) non capisco perché ti accanisci nell’utilizzare i puntatori anche quando non è necessario (a meno che non è l’esercizio che te lo chiede, in tal caso dovresti ricorrere all’allocazione dinamica). Alle altre domande ti ha già risposto DanieleC88. ;)
Si, sto cercando di fare degli esercizi in cui utilizzo un po' di tutto. Qui l'obiettivo iniziale era usare le funzioni e la chiamata per riferimento, quindi i puntatori. Ammetto che stavo anche facendo casino. :O


Adesso vedo se riesco a sfruttare i vostri consigli.
Vi ringrazio per l'enorme aiuto! :D

DanieleC88
31-08-2008, 14:00
Si, sto cercando di fare degli esercizi in cui utilizzo un po' di tutto.
Fai benissimo a sperimentare: è lo spirito giusto. :)
Però devi stare attento a non fare un minestrone; quando provi nuove cose cerca sempre di chiederti se sono coerenti con la loro definizione e se ti sembrano corrette, per prima cosa. Se credi che tutto possa funzionare ed è logicamente corretto, butta giù del codice e fai la prova empirica. :D

ciao ;)