Newsgroup: it.comp.lang.c
Titolo: funzione gets

Ciao.
Sul libro trovo scritto a proposito della funzione gets:
Prototipo della funzione:
char *gets(char *s)
Descrizione della funzione:
Legge i caratteri dallo standard input e li immagazzina nel vettore s,
finché non incontra un carattere newline o un indicatore di fine del
file. Alla fine del vettore sarà accodato un carattere NULL di
terminazione.
Poi ho fatto il seguente programmino:
#include <stdlib.h>
#include <stdio.h>
int main()
{
    char * Pstr;
	printf("Inserire una stringa:\n");
	gets(Pstr);
    system("pause");
    return 0;
}
Il compilatore non dà errori, quando però eseguo il programma .exe si
apre una finestra del debugger che non permette di proseguire
l'esecuzione..
Sapreste spigarmi perché il programmino sopra non funziona?
Grazie

    char * Pstr;
Ciao, un vettore non un puntatore. Alla gets, poi, passerai l'indirizzo del 
vettore cioè il suo nome (Pstr).
Un saluto,
Maxime. 

 del vettore cioè il suo nome (Pstr).
Detto in parole semplici, andrew (piu' sono esperti, piu' difficile 
parlano) non hai riservato uno spazio di memoria (vettore) dove gets puo' 
mettere il risultato.
Il puntatore Pstr, all'inizio del programma ha un valore casuale, dove il 
programma non puo' scrivere perche' o appartiene ad altri programmi, o va 
oltre la memoria.
Inizializza un vettore (array di char) con
char Pstr[100];
...oppure...
char stringa[100];
char *Pstr;
Pstr = stringa; // equivale a Pstr = &stringa[0];
Appena impari ad usare gets, passa alla piu' sicura fgets.
Ciao
-- 
enos76

 Ciao
oppure allocare lo spazio necessario con malloc
#include <stdlib.h>
#include <stdio.h>
int main()
{
    char *Pstr;
    if ( Pstr = malloc(100) ) {
        printf ("Inserire una stringa : ");
        gets (Pstr);
        printf ("%s\n", Pstr);
        free (Pstr);
    }
    return 0;
}
-- 
Arrivare a Venezia dalla terra ferma č come entrare
 dalla porta di servizio.
                                             - T. Mann -

 Appena impari ad usare gets, passa alla piu' sicura fgets.
meglio, passaci *prima*
-- 
-riko

Appena impari ad usare gets, passa alla piu' sicura fgets.
Non c'è nulla di propedeutico in gets() rispetto a fgets(). Fa bene a
passare a fgets() direttamente.

	gets(Pstr);
Perché è ovvio che devi prima allocare della memoria in cui
memorizzare i caratteri letti. Non ti sembra?

Ciao, un vettore non un puntatore. 
No, la gets() accetta un puntatore e sia che si allochi memoria da
indirizzare tramite puntatore, sia che si riservi memoria sullo stack
dichiarando un vettore, alla gets() verrà comunque passato un
puntatore. Nel caso alla gets() si passi il nome di un vettore, NON
verrà passato l'"indirizzo del vettore" come tu dici, ma il nome del
vettore decadrà in puntatore al primo elemento. Occhio ad usare una
terminologia ESTREMAMENTE precisa quando si parla, in C, di vettori e
puntatori.

mettere il risultato.
Allocare uno spazio di memoria NON significa parlare di vettore. La
malloc() restituisce l'indirizzo della zona di memoria allocata, che
viene quindi attribuito alla variabile puntatore.

 viene quindi attribuito alla variabile puntatore.
Mi riferivo al caso specifico, parlando di vettore in contrasto con il 
solo puntatore che aveva dichiarato andrew.
Chiedo scusa per essermi espresso male, grazie della correzione.
-- 
enos76


Trovo giusta la tua precisazione e gentile chi ha voltuto chiarificare le 
mie parole ma in realtà io intendevo semplicemente far notare a andrew che 
ha riportato un pezzo di testo ...
[riporto/s]
Sul libro trovo scritto a proposito della funzione gets:
Prototipo della funzione:
char *gets(char *s)
Descrizione della funzione:
Legge i caratteri dallo standard input e li immagazzina nel vettore s,
finché non incontra un carattere newline o un indicatore di fine del
file. Alla fine del vettore sarà accodato un carattere NULL di
terminazione.
[riporto/e]
...dove nella descrizione si parla di vettore. Lui, invece, ha dichiarato 
solo un puntatore. Non volevo essere ne ermetico ne impreciso. 

aristide ha scritto:

Grazie per la risposta.
Io avrei detto 
[...]
if ( Pstr = malloc(100 * sizeof(char)) ) {
[...]
Sbaglio?
-- 
Questo articolo e` stato inviato dal sito web 
http://www.nonsolonews.it

 Sbaglio?
Si e no!:)
In base allo standard C, sizeof(char) e' garantito sempre uguale a 1
quindi moltiplicare per sizeof(char) non e' sbagliato ma e' comunque 
inutile.
ciao
Giacomo


In effetti e' la descrizione iniziale ad essere scorretta, quando dice
"Legge i caratteri dallo standard input e li immagazzina nel vettore s"
dovrebbe parlare di "area di memoria puntata da s" e non di "vettore"
ciao
Giacomo

Giacomo Degli Esposti ha scritto:

ok, vero giacché una variabile di tipo char occupa un byte, ed è atta a memorizzare numeri interi in -128 ÷ 127 (estremi inclusi).


solo un puntatore.
E ha fatto bene. Sia un puntatore, per il quale allocare
opportunamente memoria, sia un vettore sufficientemente dimensionato
vanno bene. E' il libro a usare il termine impreciso.

 vettore decadrà in puntatore al primo elemento
...sta di fatto che comunque la gets riceve l'indirizzo della zona di
memoria predisposta per memorizzare la stringa. Potrei assicurarti che
in molti testi è semplicemente scritto che considerando un:
char str[]
dire str oppure &str[0] è la stessa cosa e ritengo che sia più che
sufficiente dal punto di vista della programmazione; il più, ritengo sia
una puntualizzazione. Quindi, dal mio punto di vista, per dimostrarsi
diligente, avrebbe dovuto scrivere:
{
      char str[257];
      str[0] = '\0';
      printf("Inserire una stringa:\n");
      gets(&str[0]);
      system("pause");
      return 0;
}
mentre trovo meno corretto suggerire la via della malloc ma solo perché
ritengo che spesso ne venga fatto un uso spropositato e fuori luogo
oltre che aggiungere ulteriori incognite al funzionamento del programma
in quanto tra i possibili valori di ritorno è contemplata l'eventualità
che l'allocazione possa non andare a buon fine.
Parlando di malloc vorrei aggiungere un commento relativo al fatto che 
spesso, come è accaduto in questo thread, si consiglia, di fronte a 
linee di codice del tipo:
char *pStr;
pStr = (char *)malloc(100 * sizeof(char));
di togliere il recast perché malloc restituisce un "void *" e quindi 
inutile, così pure "sizeof(char)" perché definito dallo standard uguale 
a 1. Cose assolutamente vere ma, personalmente, penso che molti dei 
partecipanti a questo gruppo di discussione durante le loro giornate si 
debbano scontrare con svariate realtà lavorative quindi riterrei più 
propedeutico per quel che riguarda sizeof(char) suggerire, piuttosto, un 
approccio del tipo:
typedef char tMyStep;
tMyStep *MyBuffer;
MyBuffer = (tMyStep *)malloc(100 * sizeof(tMyStep));
che all'esigenza permette a tutto di continuare a funzionare con una 
semplice modifica al typedef. Per quel che riguarda il recast, invece, 
non suggerirei di toglierlo nonostante sia superfluo perché:
a) tanto non fa danno e ti evita di saltellare per il codice a cercare 
    di che tipo è il puntatore dell'area di memoria allocata 
dinamicamente. C'è l'hai scritto a fianco.
b) non so se a voi è mai capitato ma a me succede spesso di metter mano 
a vecchi programmi su vecchie piattaforme che ospitano vecchi 
compilatori e per l'esempio ne cito uno su sistema unix/Olivetti della 
"Green Hills". Tale compilatore non ammette in nessun caso assegnamenti 
tra tipi diversi senza recast nemmeno per i "void *" e non lo segnalava 
come warning ma come error! Evidentemente nessuno gli ha mai parlato dei 
nuovi standard. Ho rimpianto il fatto che l'ex-programmatore non fosse 
stato prolisso nella scrittura.
Insomma bella la teoria se si studia ma quando si lavora anche un po' di 
praticità non guasterebbe.
Vi ringrazio per l'attenzione e saluto tutti.
Maxime.

praticità non guasterebbe.
I consigli che vengono dati qui dentro sono normalmente frutto della
pratica, non solo della teoria. Non siete gli unici a lavorare con il
C.

 praticità non guasterebbe.
Nessuna teoria: ho imparato a NON mettere il cast mentre lavoravo su un 
sistema in cui l'intero era a 16 bit e i puntatori a 32. Se dimentichi 
di mettere l'include il compilatore non ti dice niente per via del cast 
esplicito, ma genera codice come se malloc restituisse un valore a 16 
bit mentre la funzione ne restituisce 32. Immaginati quanta fatica ho 
fatto a trovare l'origine di quegli errori ceh capitavano una volta si e 
mille no! Altro che teoria! ;)
ciao
Giacomo

Nonostante abbia espanso il mio concetto non hai di nuovo capito nulla 
oppure non mi sono ancora espresso correttamente, forse la causa è il 
fatto che conoscendo anche il C++ vieni condizionato nelle risposte 
oppure non sei tra noi nelle problematiche reali.

> >      gets(&str[0]);
Inutile? Appena hai il prompt a console (dos/linux/unix) digita 
semplicemente il EOF poi vedrai cosa troverai nel buffer. Però stampalo 
con una printf non guardaci dentro con un debugger. :-)

oppure non sei tra noi nelle problematiche reali.
Ne dubito, dopo diversi anni passati a programmare professionalmente.

semplicemente il EOF poi vedrai cosa troverai nel buffer.
Non ha senso indagare cosa c'è nel buffer in caso di EOF. E' evidente
che non si è ricevuto input e quindi gets() non ha memorizzato nulla.
Voglio sperare che nei tuoi programmi in cui affronti "problematiche
reali" tu testi il codice d'uscita di gets().

Ma non occorre metterlo due volte: basta una volta sola, nel sizeof()
Perdonami, ma è una cazzata. Tanto vale scrivere:
MyBuffer = malloc(100 * sizeof *MyBuffer);
Perché se tanto devi cercare il tipo di MyBuffer, ce l'avrai scritto
nella sua dichiarazione e, se vorrai modificarlo, non dovrai
modificare due punti diversi.

 mille no! Altro che teoria! ;)
Mi collego a questa frase ed a quella che ho commentato con un sorriso: 
la prima.
Mi vergogno quasi a raccontare questa cosa ma, uno dei trucchi che si 
usavano anni fa, sotto DOS, per confondere i debugger (e rendere sicure 
le protezioni sui giochi) era quello di scrivere una semplice funzione 
che riceveva un parametro dal quale (sto parlando di DOS) si ricavava la 
posizione nello stack, per poi poterlo risalire e modificare il punto di 
ritorno della funzione (quello "pushato" dalla call); quindi, con una 
return finire in un altro punto del programma diverso da quello 
successivo alla call. :-)

 "If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned."
Non preoccuparti. Nei miei programmi gets non ce ne sono.

 modificare due punti diversi.
Anche se MyBuffer l'hai ricevuto come parametro della funzione?

 > "If end-of-file is encountered and no characters have been read into the
array, the contents of the array remain unchanged and a null pointer is
returned."
Riportando questo brano del manuale che cosa vuoi sottolineare?
Proprio per quel che viene detto, non ha senso indagare cosa c'è
nell'array se si riceve un EOF.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Anche se MyBuffer l'hai ricevuto come parametro della funzione?
???? fai un esempio concreto del problema, cortesemente.


 
?
Compila questo:
#include "conio.h"
#include "stdlib.h"
#include "malloc.h"
typedef double tMyStep;
void _tmain(void);
void f(void *);
void _tmain(void)
{	
	tMyStep *MyBuffer;
	MyBuffer = malloc(100 * sizeof(*MyBuffer));
	printf("sizeof out: %d\n", sizeof(*MyBuffer));
	f(MyBuffer);
	free(MyBuffer);
	_getch();
}
void f(void *MyBuf)
{
	printf("sizeof in : %d\n", sizeof(*MyBuf));
}
A me da come risultato questo:
1>------ Inizio compilazione: Progetto: prova, Configurazione: Debug 
Win32 ------
1>Compilazione in corso...
1>prova.cpp
1>prova.cpp(19) : error C2440: '=': impossibile convertire da 'void *' a 
'tMyStep *'
1>La conversione da 'void*' a puntatori a valori non 'void' richiede un 
cast esplicito
1>prova.cpp(30) : error C2100: riferimento indiretto non valido

 1>prova.cpp(30) : error C2100: riferimento indiretto non valido
scusate se mi intrometto, ma forse stai compilando in c++
a me questo lo compila
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef double tMyStep;
void f(void *);
int main()
{
        tMyStep *MyBuffer;
        MyBuffer = malloc (100 * sizeof(*MyBuffer));
        printf("sizeof out: %d\n", sizeof(*MyBuffer));
        f(MyBuffer);
        free(MyBuffer);
}
void f (void *MyBuf)
{
      tMyStep *MyBuf2;
 
      printf ("sizeof in : %d\n", sizeof(*MyBuf));
 
      MyBuf2 = MyBuf;
      printf ("sizeof in 2 : %d\n", sizeof(*MyBuf2));
}
L'output è :
sizeof out: 8
sizeof in : 1
sizeof in 2 : 8
-- 
Gli uomini sono come gli aquiloni,
più gli si da corda meglio si tengono.
                                             - Alexandre Dumas, figlio -

 
ehmm ... in effetti stavo provando "Visual C++ 2008 Express Edition". 
Scusate. Comunque, nonostante abbia proposto un caso estremo, nella 
funzione mi son giocato la reale dimensione.

 Compila questo:
<snip>
A parte che il codice che riporti non è standard, quindi funziona solo
sulla tua piattaforma, ho già spiegato moltissime volte che sizeof si
applica correttamente al nome di un vettore, *NON* ad un puntatore,
proprio perché il vettore *NON* decade in puntatore al primo elemento. Ho
scritto molte volte che il caso in cui il nome di un array viene passato
ad una funzione, decade *SEMPRE* in puntatore al primo elemento, quindi
l'operatore sizeof non deve/può essere usato. In ogni caso, non hai
capito: io stavo parlando della malloc().


 1>prova.cpp(30) : error C2100: riferimento indiretto non valido
E comunque se passi un void* non puoi aspettarti di applicare un sizeof.


 
Guarda che l'ho copiato da un tuo post. Comunque ci rinuncio. Stai solo 
continuando a sgusciare.

 Guarda che l'ho copiato da un tuo post. 
Stai delirando. Non ho mai scritto codice del genere. Se ti riferisci alla
malloc(), il mio codice era limitato a quello: l'allocazione. Ed aveva un
senso preciso che non hai colto. Il resto sono tue elucubrazioni
sconclusionate. Continui a ribattere a questioni tecniche sparando
sciocchezze.


 sciocchezze.
...e non mi hai capito nemmeno cosě.

 MyBuffer = malloc(100 * sizeof *MyBuffer);
... non si trova in un contesto. A mio parere dovresti mettere nelle tue 
risposte la stessa attenzione che pretendi dagli altri.

 .... non si trova in un contesto.
Si riferisce al contesto iniziale. E' quanto meno ovvio. E ora vedi di
darci un taglio con 'ste cazzate.


 ....e non mi hai capito nemmeno cosě.
L'idea che tu dica stronzate non la prendi neanche in considerazione, vero?


 
Certo. Io si.
Lasciamo perdere il mio codice precedente e commentiamo questo.
#include "stdlib.h"
void main(void);
void s1(char []);
void s2(char *);
void main()
{	
	char s[100];
	printf("\n%d\n", sizeof(s));
	printf("\n%d\n", sizeof(*s));
	s1(s);
	s2(s);
	system("pause");
}
void s1(char str [])
{
	printf("\n%d\n", sizeof(str));
	printf("\n%d\n", sizeof(*str));
}
void s2(char *str)
{
	printf("\n%d\n", sizeof(str));
	printf("\n%d\n", sizeof(*str));
}

 
Lo farò certamente avrei, però, preferito avessi scritto *vediamo*.

 modificare due punti diversi.
In generale e' vero, non a caso questa e' la risposta "canonica" che 
danno i guru del linguaggio su comp.lang.c
Ma si stava parlando dell'opportunita' di castare o meno il risultato 
della malloc, non di mettere o meno il sizeof. La mia risposta va letta 
in quel contesto. Se la estrapoli e' chiaro che risulta imprecisa.
ciao
Giacomo