Newsgroup: it.comp.lang.c
Titolo: funzioni che restituiscono strutture

Salve a tutti.
Non riesco a capire le funzioni che restituiscono strutture:
ad esemp. ho un hader file in cui definisco una funzione(visibile nel file
pippo.h) che mi legge il nome di un file e il modo di apertura e me li
restituisce tramite una struttura contenente due pntatori.Scrivo il main
dichiaro una struttura e gli assegno quello restituito dalla funz. getname
poi mi visualizzo le due stringhe solo che  mi ritornano i valori strani.Con
le variabili normali le cose mi riescono, stavo cominciando ad imparare le
strutture facendo questo ese inventato da me.Puo essere anche l'ora tarda
avro' fatto qualche cavolata . grazie per l'aiuto.
CIAO
/*file pippo.h*/
#include <stdio.h>
#include <string.h>
#include <malloc.h>
struct f getname();
#define MAX 255
struct f {
   char *name;
   char *mode;
};
struct f getname()
{
    char buffer[MAX];
    struct f pippo;
    printf("Inserire nome file\n");
    if(((
pippo.name
)=(char*)malloc(strlen(fgets(buffer,MAX,stdin))))==NULL)
      printf("Allocazione non riuscita\n");
 
pippo.name
=buffer;
    printf("Inserire modo\n");
    if(((pippo.mode)=(char*)malloc(strlen(fgets(buffer,4,stdin))))==NULL)
      printf("Allocazione non riuscita\n");
      pippo.mode=buffer;
      return pippo;
}
/*file pluto.c*/
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "pippo.h"
int main(void)
{
   struct f pluto;
   pluto=getname();
   printf("%s\n",
pluto.name
);
   printf("%s\n",pluto.mode);
getch();
return 0;
}

}
Il programma corretto è di seguito:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
               char *name;
               char *mode;
        } mystruct;
void inputstring(char *prompt, char *s, int max)
{
     int i;
     if (prompt)
        printf("%s", prompt);
     fgets(s, max, stdin);
     for (i = 0; s[i]; i++)
     {
         if (s[i] == '\n')
            s[i] = '\0';
     }
}
char *dupstr(const char *s)
{
     char *p = malloc(strlen(s)+1);
     if (p) {
        strcpy(p, s);
     }
     return p;
}
int getname(mystruct *s)
{
       char buffer[255];
       inputstring("Inserisci nome: ", buffer, sizeof buffer);
       s->name = dupstr(buffer);
       inputstring("Inserisci modo: ", buffer, sizeof buffer);
       s->mode = dupstr(buffer);
       if ((s->name == 0) || (s->mode == 0))
       {
          return 0;
       }
       return 1;
}
int main()
{
    mystruct s;
    if (getname(&s)) {
       printf("nome = \"%s\", modo = \"%s\"\n", 
s.name
, s.mode);
    }
    else {
       fputs("errore !", stderr);
    }
    return 0;
}
-- 
Andrea Laforgia
#exclude <windows.h>

 C.
Invece a me, diversi compilatori mi hanno sempre dato errori se non faccio
il casting! Ma poi, la malloc non dovrebbe essere del tipo
malloc(n*sizeof(tipo)), dove n e' il numero di elementi e tipo e' il tipo
degli elementi?
--
---------------------------------------------------
There are 10 kinds of people in the world:
those who understand binary, and those who don't
---------------------------------------------------

degli elementi?
Stai allocando dei caratteri e sizeof(char), in _tutte_ le
piattaforme, vale 1, quindi, nella moltiplicazione, puoi ometterlo.


 Il cast su malloc(), in C, non va usato.
Perche' mai ? Io non direi che e' unanimamente sconsigliato,
visto che io lo consiglierei....
A me e' stato utile per almeno 3 motivi:
1) Passando del codice C ad un programma C++ ho evitato svariati warning
2) E' una informazione che chi sta leggendo il codice puo' apprezzare
    perche'  informa sul tipo di dato che sto allocando
3) Alcuni errori di ricopiatura/battitura sono saltati fuori cosi',
    perche' avevo sbagliato ad associare il tipo alla variabile etc.etc.
    Senza il cast esplicito il compilatore si sarebbe lamentato.
ciao,
g.

 g.
ciao Sbirish.

    Senza il cast esplicito il compilatore si sarebbe lamentato.
Non l'ho capita.


 di che genere? non ti seguo qui.
Volevo dire "il compilatore NON si sarebbe lamentato".
Esempio: se ho
int *m;
double *mm;
e poi m=(int *) malloc(120000*sizeof(int));
se per caso mi sbaglio e scrivo mm invece che m (cosa che a volte puo'
capitare se ho molte malloc, calloc e faccio del cut&paste di linee che
poi per sbaglio non modifico correttamente) allora perlomeno
il compilatore mi avverte, invece di ingoiare tutto silentemente.
Ciao,
g.

avere un  cast esplicito mi fa ricordare il tipo della variabile.
Che a te il cast esplicito faccia "ricordare" mi può star bene, ma
questo non è motivo sufficiente a consigliarne l'utilizzo.


 "chiarimento su malloc()" 
Ho guardato. Sostanzialmente viene detto che i problemi possono
nascere se uno si dimentica di includere stdlib. Ora, nei dodici
e passa anni che programmo in C non ho mai fatto un programma che
non contenesse almeno un errore, ma non penso di aver mai dimenticato
una volta le include iniziali. Quindi mi sembra un po' pochino come
motivo.
 >Ribadisco: in C il valore di ritorno di malloc() castato può
 >introdurre problemi e va evitato.
Non mi hai convinto della apoditticita' della situazione.
Direi che e' uno di quei casi dove si puo' esercitare la
liberta' di coscienza...e non vale la pena scatenare una guerra di
religione.
ciao,
g.

 modalità standard è C++.
Appunto, uso win per programmi GUI che hanno una interazione con il
maledetto utente (vedi: 
http://www.imc.pi.cnr.it/~resta/verba.html
 )
quindi in C++, ma le procedure sono in puro C (e di solito le sviluppo
sotto linux) poi le infilo in dei programmi C++ con bottoni e altre
cavolate per le quali mi devo necessariamente interfacciare con il C++.
Ciao,
g.

religione.
Niente affatto, fidati di ciò che ti viene detto da chi,
probabilmente, il linguaggio lo conosce meglio di te:
[Errata Corrige del K&R II]
"142: The remark about casting the return value of malloc ("the proper
method is to declare ... then explicitly coerce") needs to be
rewritten. The example is correct and works, but the advice is
debatable in the context of the 1988-1989 ANSI/ISO standards. It's not
necessary (given that coercion of void * to ALMOSTANYTYPE * is
automatic), and possibly harmful if malloc, or a proxy for it, fails
to be declared as returning void *. The explicit cast can cover up an
unintended error. On the other hand, pre-ANSI, the cast was necessary,
and it is in C++ also."


sotto linux) poi le infilo in dei programmi C++ con bottoni
Quello che non riesco a spiegare è che, nel momento stesso in cui
incorpori quelle routine in codice C++, DIVENTANO codice C++, non sono
più codice C e questo è di _estrema_ rilevanza.  Da quel momento in
poi vengono compilate in modalità C++ e SONO _a tutti gli effetti_
codice C++, NON C.


Io non capisco niente sto cercando di imparare e mi sono comprato dei libri
e ogni tanto chiedo anche qui.
Volevo solo dire che se andate a guardare il libro linguaggio c seconda
edizionen W.Kernighan vi accorgerete che gli esemp sulla malloc sono scritti
con l'esplecitazione del casting a char.
Percaso e' sbagliato?
Che problemi puo' portare mettercelo o non ?
Se e' la stessa cosa a che fine questa discussione?
Ciaoz

 compilavi ? C o C++ ?
In C++, ecco perche' mi dava errore... Uso il borland turbo c++ 3.0, ma non
ho visto opzioni per compilare in C o C++, al massimo posso scegliere tra
ANSI C, Turbo C, Kernighan & Ritchie e Unicode.

ho visto opzioni per compilare in C o C++
La distinzione dovrebbe essere fatta in base all'estensione del file
(.C o .CPP), come avviene, ad es., con gcc.  Con Borland C++ Builder,
invece, ti viene esplicitamente richiesto.  


Percaso e' sbagliato?
Sì, è sbagliato.  Nel messaggio precedente ho riportato proprio
l'Errata Corrige al libro.


 l'Errata Corrige al libro.
Giusto a titolo di completezza posto un link all'Errata Corrige completa del 
libro (la versione inglese... per quella italiana si adatta senza troppi 
problemi), che tra l'altro ti spiega anche perche' il K&R necessita di 
correzioni.
http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html
 
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

 introdurre problemi e va evitato.  Se si vuol rendere il
Due pezzi presi dallo standard C 99:
#include <stdlib.h>
void *malloc(size_t size);
6.3.2.3
A pointer to void may be converted to or from a pointer to any incomplete or
object
type. A pointer to any incomplete or object type may be converted to a
pointer to void
and back again; the result shall compare equal to the original pointer.
Inoltre viene specificato che la performazione di una conversione da parte
del cast operator deve essere uguale ad una conversione implicita effettuata
da qualsiasi altro operatore.
Indipendetemente da una conversione implicita, lasciata all'operatore = , o
da una cast esplicito sul valore di ritorno della malloc() lo standard ha
definito un comportamento opportuno verso il quale tutte le implementazioni
devono orientarsi.
Se effettivamente una conversione di questo genere potrebbe altresě
risultare dannosa, cosa peraltro poco probabile con quanto scritto sopra, vi
sarebbe sicuramente un nota o nella descrizione della malloc stessa oppure
nell'appendice dello standard riservata alla lista degli undefined behavior.
Ciao.

nell'appendice dello standard riservata alla lista degli undefined behavior.
No, niente affatto.  Il brano dello standard che riporti č
assolutamente _irrilevante_ rispetto a quello che si sta dicendo. 
Tra l'altro, quel brano cita il normale comportamento della
trasformazione di un puntatore void in un qualsiasi altro puntatore,
che in C č assolutamente automatico (leggi: non necessita di alcun
cast, come lo standard, giustamente, omette di dire).  
Il problema č la congiunzione dell'uso di malloc() con il cast
esplicito.  In determinate circostanze crea problemi.  
Ribadisco: si č parlato moltissime volte di questi aspetti qui e su
comp.lang.c, pregasi di rileggere i vecchi messaggi.


Ciao Andrea,
ho controllato per sicurezza gli eventuali punti contrastanti con quanto ho
affermato nel mio precedente messaggio, sempre all'interno dello standard
99, eppure gli unici casi in cui la malloc non è definita è quando:
"non-null pointer returned by a call to the calloc, malloc, or realloc
function
with a zero requested size is used to access an object (7.20.3).
The pointer argument to the free or realloc function does not match a
pointer
earlier returned by calloc, malloc, or realloc, or the space has been
deallocated by a call to free or realloc (7.20.3.2, 7.20.3.4).
The value of the object allocated by the malloc function is used (7.20.3.3).
"
Mentre risulta essere definita dall'implementazione quando:
"
Whether the calloc, malloc, and realloc functions return a null pointer or a
pointer to an allocated object when the size requested is zero (7.20.3).
"
Calcola però che se il C prevede che una conversione venga effettuata in un
certo modo, non vi devono essere dei casi in cui ciò non avviene. Inoltre il
cast operator non elimina le eventuali situazioni undefined di un cast
implicito.
Se un cast implicito provoca un undefined behavior in una determinata
situazione, il medesimo comportamento indefinito si avrà anche con un cast
esplicito.
Un cast esplicito forza la conversione laddove non può essere perfomata
implicitamente,  rende il codice talvolta più scorrevole e può essere
utilizzato per effettuare alcune conversioni - che non trovano controparte
nelle conversioni implicite - appartenenti alla categoria degli unspecified
behavior.
Non dubito affatto che quanto hai riportato sia corretto per quanto riguarda
il C K&R; ma sicuramente se lo standard avesse lasciato in sospeso quel
punto si sarebbe protratta quella che è e rimane una carenza nella semantica
del linguaggio.
Comunque, se hai modo di controllare lo standard, indicami pure se vi sono
punti sull'argomento che per disattenzione - e soprattuto per mancanza di
comprensione dell'inglese :-) - ho tralasciato.

implicitamente,  
No, un cast esplicito, formalmente, forza la conversione COMUNQUE e
SEMPRE.  Il problema è che in C, quel tipo di conversione, è
AUTOMATICO, quindi non necessità di ALCUN cast, specialmente in
seguito al fatto che, dimenticando di includere stdlib.h, il codice
può diventare una mina.


 #exclude <windows.h>
Oh, un altro fan della magnifica famiglia Windows :-)
Ciao.

 esplicito.  In determinate circostanze crea problemi.
Che derivano comunque da errori del programmatore.
Ciao.

 Che derivano comunque da errori del programmatore.
Si, ma il compilatore potrebbe segnalarteli (ti aiuta), mentre se usi il 
cast esplicito li riduci di molto (praticamente li annulli e rifiuti il suo 
aiuto).
Perche' ti metti a fare un cast esplicito che ammazza i controlli di tipo, 
quando ne avviene gia' uno implicito che mantiene quel poco di type 
checking che fa' il C?
Noti che c'e' qualcosa di illogico in tutto questo?
E' questo la principale argomentazione CONTRO il cast sulla malloc :)


sorprese, perché ciò andrebbe contro la semantica del C stesso.
Ma non si sta parlando di questo !


Che derivano comunque da errori del programmatore.
E quindi ? č proprio di errori del programmatore da evitare che si sta
parlando.


}
ma se s=NULL allora potrebbe essere strlen(s)=0
e p=malloc(1)!=0 e if e
così strcpy(p,s) cerca di accedere a un puntatore nullo e crash non
previsto

ma se s=NULL 
Si suppone che s sia != NULL, come in tutte le funzioni di libreria
standard.
p.s.: impara a quotare meglio i tuoi messaggi.
