[C] Stringa che può contenere spazi

kokoko1
Ciao ragazzi, come da titolo non riesco ad inserire gli spazi nelle stringhe utilizzando il semplice scanf. Ad esempio se volessi scrivere nella stringa cognome "Di Natale", il programma termina l'esecuzione. Vi posto il codice sorgente sperando possiate aiutarmi. Vi ringrazio in anticipo.

#include
#include
#include
main()
{
struct persona{
char nome[20];
char cognome[20];
int eta;
char sesso[2];
} pers;
printf("inserire nome: ");
scanf("%s", pers.nome);
printf("inserire cognome: ");
scanf("%s", pers.cognome);
printf("inerire l'eta: ");
scanf("%d", &pers.eta);
printf("inserire il sesso M/S: ");
scanf("%s", pers.sesso);
printf("%s\n%s\n%d\n%s\n", pers.nome, pers.cognome, pers.eta, pers.sesso);
system("PAUSE");
return 0;
}

Risposte
hamming_burst
Ti consiglio di leggere le proprietà della funzione scanf:

http://digilander.libero.it/uzappi/C/li ... scanf.html

se vedi il costrutto "s", dice:
Accetta una stringa di caratteri non comprendente gli spazi. Alla fine e' aggiunto il terminatore '\0'. L'area di memoria puntata dal puntatore passato in argomento deve essere sufficientemente ampia da contenere i caratteri letti in input ed in piu' il terminatore. L'input del campo si arresta quando viene incontrato uno spazio, oppure quando e' stata raggiunta la lunghezza della stringa definita dall'ampiezza massima.

kokoko1
"ham_burst":
Ti consiglio di leggere le proprietà della funzione scanf:

http://digilander.libero.it/uzappi/C/li ... scanf.html

se vedi il costrutto "s", dice:
Accetta una stringa di caratteri non comprendente gli spazi. Alla fine e' aggiunto il terminatore '\0'. L'area di memoria puntata dal puntatore passato in argomento deve essere sufficientemente ampia da contenere i caratteri letti in input ed in piu' il terminatore. L'input del campo si arresta quando viene incontrato uno spazio, oppure quando e' stata raggiunta la lunghezza della stringa definita dall'ampiezza massima.

Ti ringrazio per il link. Dunque come potrei fare a risolvere il problema senza lo scanf?

hamming_burst
Allora, per usare scanf viene una cosa sporca, che non consiglio. Se sai scanf() è come un pattern, pui impostare te cosa leggere e cosa no, ma lasciamo stare.

Se vuoi rimanere con librerie dello standard C, usa la funzione fgets(), che ti permette di controllare il numero di caratteri letti. Se usi gets() non hai nessun controllo, hai un bel baco di sicurezza (buffer overflow).
Se no il modo "corretto" sarebbe usare la getline() come è citato nelle man linux, ma sono componenti di librerie non comprese nello standard C.

Comunque:

 char *fgets(char *s, int size, FILE *stream); 


con stream:

- stdin = 0
- stdout = 1

questo è il link della funzione:

http://digilander.libero.it/uzappi/C/li ... fgets.html

Se hai problemi nello scrivere il codice siamo qua :-)

kokoko1
"ham_burst":
Allora, per usare scanf viene una cosa sporca, che non consiglio. Se sai scanf() è come un pattern, pui impostare te cosa leggere e cosa no, ma lasciamo stare.

Se vuoi rimanere con librerie dello standard C, usa la funzione fgets(), che ti permette di controllare il numero di caratteri letti. Se usi gets() non hai nessun controllo, hai un bel baco di sicurezza (buffer overflow).
Se no il modo "corretto" sarebbe usare la getline() come è citato nelle man linux, ma sono componenti di librerie non comprese nello standard C.

Comunque:

 char *fgets(char *s, int size, FILE *stream); 


con stream:

- stdin = 0
- stdout = 1

questo è il link della funzione:

http://digilander.libero.it/uzappi/C/li ... fgets.html

Se hai problemi nello scrivere il codice siamo qua :-)

Grazie per la disponibilità. Poichè mi sono avvicinato da poco alla programmazione, non riesco a capire come modificare il mio codice originario con la funzione fgets. Potresti essere così gentile da mostrarmi come dovrebbe essere scritto il codice con tale funzione? Scusa l'ignoranza :oops:

hamming_burst
Si immaginavo che fossi all'inizio, ma nessun problema, da qualche parte bisogna pur partire :-)

allora vediamo di spiegartelo facile,

scanf() penso tu abbia capito che non può essere usato allo scopo del tuo problema, perchè come "proprietà" ha di salvare solo i caratteri fino ad un carattere speciale, in questo caso "spazio" e "carrello".

fgets() bufferizza "size" caratteri, nella stringa "s", catturati da stdin. I caratteri li legge da uno "stream", diciamo un file virtuale chiamato stdin, la linea di comando in input. OK?

per farla facile ti imposto la funzione corretta, però modichi il codice te correttamente con la risoluzione del tuo problema:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>

#define SIZE_MAX_STRING 20

struct persona{
char nome[SIZE_MAX_STRING];
char cognome[SIZE_MAX_STRING];
int eta;
char sesso[2];
} pers; 


int main(){




fgets(pers.cognome,SIZE_MAX_STRING,STDIN_FILENO);


return 0;
}



il resto a te.

spiegazione:

- SIZE_MAX_STRING: massimo numero di caratteri che una stringa può contenere. Un appunto te pui scrivere al massimo SIZE_MAX-1 caratteri, ricordati che c'è il carattere '\0' come terminatore di una stringa.
- STDIN_FILENO: numero magico inserito nella libreria "unistd.h", vedi include sopra, che sta a sostituire lo stream stdin, per semplificarti la vita.

dovrebbe essere tutto a posto così. Prova ora, come prima siamo qua se hai bisogno :-)

EDIT:
ho corretto alcune piccole cose, mi son ricordato che alcuni compilatori ti possono dare errori o warning che forse non sai risolvere.
Ti dico solo che alcuni nomi sono "privati" se usati da altre librerie e il compilatore ti può dare errori per quello, rivedi con le modifiche (poche) che ho fatto.
Poi in alcuni casi ci possono essere errori anche con la versione del C, ecc... se non capisci ti spiego volentieri le modifiche.

Deckard1
Puoi usare una getchar innestata nella condizione di un while: continui a leggere nuovi caratteri finché non leggi un "a capo". Occhio che però se salvi i vari caratteri in una stringa allocata staticamente ti tocca fare il check sul numero di caratteri letti: se dichiari s come un array di 20 caratteri devi inserire un'ulteriore condizione in modo da non accettare più di 20 caratteri.

kokoko1
"ham_burst":
Si immaginavo che fossi all'inizio, ma nessun problema, da qualche parte bisogna pur partire :-)

allora vediamo di spiegartelo facile,

scanf() penso tu abbia capito che non può essere usato allo scopo del tuo problema, perchè come "proprietà" ha di salvare solo i caratteri fino ad un carattere speciale, in questo caso "spazio" e "carrello".

fgets() bufferizza "size" caratteri, nella stringa "s", catturati da stdin. I caratteri li legge da uno "stream", diciamo un file virtuale chiamato stdin, la linea di comando in input. OK?

per farla facile ti imposto la funzione corretta, però modichi il codice te correttamente con la risoluzione del tuo problema:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>

#define SIZE_MAX_STRING 20

struct persona{
char nome[SIZE_MAX_STRING];
char cognome[SIZE_MAX_STRING];
int eta;
char sesso[2];
} pers; 


int main(){




fgets(pers.cognome,SIZE_MAX_STRING,STDIN_FILENO);


return 0;
}



il resto a te.

spiegazione:

- SIZE_MAX_STRING: massimo numero di caratteri che una stringa può contenere. Un appunto te pui scrivere al massimo SIZE_MAX-1 caratteri, ricordati che c'è il carattere '\0' come terminatore di una stringa.
- STDIN_FILENO: numero magico inserito nella libreria "unistd.h", vedi include sopra, che sta a sostituire lo stream stdin, per semplificarti la vita.

dovrebbe essere tutto a posto così. Prova ora, come prima siamo qua se hai bisogno :-)

EDIT:
ho corretto alcune piccole cose, mi son ricordato che alcuni compilatori ti possono dare errori o warning che forse non sai risolvere.
Ti dico solo che alcuni nomi sono "privati" se usati da altre librerie e il compilatore ti può dare errori per quello, rivedi con le modifiche (poche) che ho fatto.
Poi in alcuni casi ci possono essere errori anche con la versione del C, ecc... se non capisci ti spiego volentieri le modifiche.

Sei stato molto chiaro, poi ieri sera ho staccato essendo un pò fuso dopo una giornata di studio ed ora sto cercando a mente fresca di rivedere il codice. Dunque io utilizzo il Dev-C++ 4.9.9.2. Riguardando il mio codice e facendo le opportune modifiche, credo che il risultato dovrebbe essere questo (ho utilizzato la funzione fgets anche per il nome):

#include
#include
#include
#include
#define SIZE_MAX_STRING 20
struct persona{
char nome[SIZE_MAX_STRING];
char cognome[SIZE_MAX_STRING];
int eta;
char sesso[2];
} pers;

int main() {
printf("inserire nome: ");
fgets(pers.nome,SIZE_MAX_STRING,STDIN_FILENO);
printf("inserire cognome: ");
fgets(pers.cognome,SIZE_MAX_STRING,STDIN_FILENO);
printf("inerire l'eta: ");
scanf("%d", &pers.eta);
printf("inserire il sesso M/S: ");
scanf("%s", pers.sesso);
printf("%s\n%s\n%d\n%s\n", pers.nome, pers.cognome, pers.eta, pers.sesso);
system("PAUSE");
return 0;
}
Ma qui sorge un problema. Quando lo eseguo con il compilatore mi da direttamente errore e non riesce ad eseguirlo, a cosa può essere dovuto? Inoltre quando utilizzo fgets, per stampare a video vale sempre il "%s" come facevo con lo scanf? Ti ringrazio per la pazienza.

kokoko1
"Deckard":
Puoi usare una getchar innestata nella condizione di un while: continui a leggere nuovi caratteri finché non leggi un "a capo". Occhio che però se salvi i vari caratteri in una stringa allocata staticamente ti tocca fare il check sul numero di caratteri letti: se dichiari s come un array di 20 caratteri devi inserire un'ulteriore condizione in modo da non accettare più di 20 caratteri.

Potresti spiegarti meglio con un esempio pratico? Sono ancora alle prime armi :(

hamming_burst
uuuh scusa ho fatto un'assunzione ieri sera, che ho dato per scontanto.
Usi Windows...

la libreria "unistd.h" è priopria dei sistemi Unix, per rimanere generali basta usare un altro sistema delle librerie standard "stdio.h".

Invece di usare il numero magico "STDIN_FILENO", basta fare così, togliere la libreria "unistd.h" che è inutile, e usare un puntatore giò pronto a stdin.

Perciò:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SIZE_MAX_STRING 20

struct persona{
char nome[SIZE_MAX_STRING];
char cognome[SIZE_MAX_STRING];
int eta;
char sesso[2];
} pers;


int main(){



fgets(pers.cognome,SIZE_MAX_STRING, stdin);


return 0;
} 



prova ora. Quello che ho fatto, è la stessa cosa che fa "STDIN_FILENO", solo che funziona solo su sistemi Unix.

Inoltre quando utilizzo fgets, per stampare a video vale sempre il "%s" come facevo con lo scanf?


bhè certo che è uguale, printf è stampa su stdout, qualunque sia l'input.
fgets(), gets(), scanf(), sono "equivalenti" catturano caratteri dallo standard input (stdin) e lo salvano su stringhe (interi, ecc).

Quello che ti suggerisce Deckard è creare te le funzionalità di "fgets" e i controlli. Così per capire come funzionano le stringhe e i possibili errori che ne derivano.

kokoko1
"ham_burst":
uuuh scusa ho fatto un'assunzione ieri sera, che ho dato per scontanto.
Usi Windows...

la libreria "unistd.h" è priopria dei sistemi Unix, per rimanere generali basta usare un altro sistema delle librerie standard "stdio.h".

Invece di usare il numero magico "STDIN_FILENO", basta fare così, togliere la libreria "unistd.h" che è inutile, e usare un puntatore giò pronto a stdin.

Perciò:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SIZE_MAX_STRING 20

struct persona{
char nome[SIZE_MAX_STRING];
char cognome[SIZE_MAX_STRING];
int eta;
char sesso[2];
} pers;


int main(){



fgets(pers.cognome,SIZE_MAX_STRING, stdin);


return 0;
} 



prova ora. Quello che ho fatto, è la stessa cosa che fa "STDIN_FILENO", solo che funziona solo su sistemi Unix.

Inoltre quando utilizzo fgets, per stampare a video vale sempre il "%s" come facevo con lo scanf?


bhè certo che è uguale, printf è stampa su stdout, qualunque sia l'input.
fgets(), gets(), scanf(), sono "equivalenti" catturano caratteri dallo standard input (stdin) e lo salvano su stringhe (interi, ecc).

Quello che ti suggerisce Deckard è creare te le funzionalità di "fgets" e i controlli. Così per capire come funzionano le stringhe e i possibili errori che ne derivano.

Ho risolto il problema! Ti ringrazio infinitamente per la pazienza e la disponibilità che mi hai dato, sei stato molto chiaro :)
Ti auguro buone feste e buon Natale :wink:

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.