Newsgroup: it.comp.lang.c
Titolo: Strano comportamento di printf.

Ciao.
Tra le funzioni che compongono un programmino che ho scritto ce n'è una 
che stampa il giorno della settimana successivo a quello immesso 
dall'utente. Se ad esempio l'utente digita giovedi, la macchina stampa 
venerdi. 
Se avete voglia, compilate ed eseguite il codice che incollo qui sotto, 
quindi date il comando s seguito da invio ed osservate lo strano 
comportamento di printf.
In pratica, dopo aver correttamente stampato il giorno successivo a 
quello immesso dall'utente, printf, invece di ristampare il prompt che 
chiede all'utente di dare un comando al programma, ristampa il giorno 
della settimana precedentemente digitato dall'utente, privato della sua 
lettera iniziale. 
Qualcuno può fornirmi una spiegazione per questo rompicapo?
Vi ringrazio e vi incollo il codice.
Bizio.
***
//File di intestazione per il programma giorni.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum giorno {lunedi, martedi, mercoledi, giovedi, venerdi, sabato, 
domenica};
typedef enum giorno giorno;
extern char giorni[2][13];
/*Nella prima riga è memorizzato il numero dei giorni di ogni mese 
quando l'anno non è
bisestile. A quest'ultimo è riservata la seconda linea. */
extern char *giorniset[7];
//Funzioni che eseguono calcoli su date e giorni.
char *nomemese(int mese);
int giornodellanno(int anno, int mese, int giorno);
void giornodelmese(int anno, int giorno, int *m, int *d);
giorno giornosucc(giorno g);
giorno giornoprec(giorno g);
//Funzioni di controllo della correttezza dei dati immessi.
void controllodata(int giorno, int mese, int bisestile);
void controllogiorno(int giorno, int bisestile);
//Funzioni che gestiscono gli errori.
void erroredata(void);
void erroregiorno(void);
//Funzioni di stampa.
void stampaistruzioni(void);
void stampahelp(void);
//Funzione per l'uscita dal programma.
void esci(void);
//Inizio file main.c:
/*Esegue alcuni calcoli con i giorni del mese, i giorni della settimana, 
i mesi e gli anni. */
#include "giorni.h"
char giorni[2][13] = { {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 
31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} };;
char *giorniset[7] = {"lunedi", "martedi", "mercoledi", "giovedi", 
"venerdi", "sabato", "domenica"};
int main(void)
{
 int giorno, mese, anno;
 int g, m;
 int i;
 char c, *giornoset = "";
 stampaistruzioni();
 while (1) {
  printf("\n\nFai la tua scelta e premi invio per confermarla: ");
  do
   scanf("%c", &c);
  while (c == '\n');
  switch (c) {
   case 'a':
    printf("\nINserisci giorno, mese ed anno separati da spazio: \n");
    scanf("%d%d%d", &giorno, &mese, &anno);
    printf("\n%d", giornodellanno(giorno, mese, anno));
    break;
   case 'm':
    printf("\nInserisci l'anno e il giorno dell'anno separati da spazio: 
");
    scanf("%d%d", &anno, &giorno);
    giornodelmese(anno, giorno, &g, &m);
    printf("\n%d %s", g, nomemese(m));
    break;
   case 's':
    printf("\nInserisci il giorno della settimana, minuscolo e senza 
accento sull'ultima lettera: ");
    do
     gets(giornoset);
    while (strcmp(giornoset, "") == 0);
    i = 0;
    while (i < 7 && strcmp(giornoset, giorniset[i]) != 0)
     ++i;
    if (i >= 7) {
     printf("Errore: %s non è un giorno della setttimana valido.\n", 
giornoset);
     exit(1);
    }
    else
     printf("\n%s", giorniset[giornosucc(i)]);
    break;
   case 'p':
    printf("\nInserisci il giorno della settimana, minuscolo e senza 
accento sull'ultima lettera: ");
    scanf("%s", giornoset);
    i = 0;
    while (i < 7 && strcmp(giornoset, giorniset[i]) != 0)
     ++i;
    if (i >= 7) {
     printf("Errore: %s non è un giorno della setttimana valido.\n", 
giornoset);
     exit(1);
    }
    else
     printf("\n%s", giorniset[giornoprec(i)]);
    break;
   case 'h':
    stampahelp();
    break;
   case 'q':
    esci();
    break;
   default:
    printf("\n%c non è una scelta valida.", c);
  }
 }
}
//Inizio file calcoli.c:
/*Funzioni di conversione e di calcolo per il programma giorni. */
#include "giorni.h"
char *nomemese(int mese)
{
 char *mesi[13] = {"ignoto", "gennaio", "febbraio", "marzo", "aprile", 
"maggio", "giugno",
 "luglio", "agosto", "settembre", "ottobre", "novembre", "dicembre"};
 return mesi[mese];
}
int giornodellanno(int giorno, int mese, int anno)
//Restituisce il giorno progressivo dell'anno corrispondente alla data 
immessa.
{
 int i, bisestile;
 bisestile = ((anno % 400 == 0) || (anno % 4 == 0 && anno % 100 != 0));
 controllodata(giorno, mese, bisestile);
 for (i = 1; i < mese; ++i)
  giorno += *(&giorni[0][0] + bisestile * 13 + i);
 return giorno;
}
void giornodelmese(int anno, int giorno, int *g, int *m)
//Dice a quale giorno di quale mese corrisponde il giorno dell'anno 
inserito.
{
 int bisestile;
 bisestile = ((anno % 400 == 0) || (anno % 4 == 0 && anno % 100 != 0));
 controllogiorno(giorno, bisestile);
 for (*m = 1; giorno > *(&giorni[0][0] + bisestile * 13 + *m); ++*m)
  giorno -= *(&giorni[0][0] + bisestile * 13 + *m);
 *g = giorno;
}
giorno giornosucc(giorno g)
//Restituisce il giorno della settimana successivo a quello immesso.
{
 return (g + 1) % 7;
}
giorno giornoprec(giorno g)
//Restituisce il giorno della settimana precedente a quello immesso.
{
 if (g == domenica)
  return sabato;
 else
  return (g - 1) % 7;
}
//Inizio file errori.c:
/*File contenente le funzioni che controllano la correttezza dei dati 
inseriti nel programma
giorni e quelle che gestiscono eventuali situazioni di errore.
Attualmente, se si inseriscono giorno e mese errati, il programma non 
stampa un messaggio
d'errore corretto.*/
#include "giorni.h"
void controllodata(int giorno, int mese, int bisestile)
{
 switch (mese) {
  case 1: case 3: case 5: case 7: case 9: case 11: case 12:
   if (giorno < 1 || giorno > 31)
    erroredata();
   break;
  case 4: case 6: case 8: case 10:
   if (giorno < 1 || giorno > 30)
    erroredata();
   break;
  case 2:
   if (bisestile) {
    if (giorno < 1 || giorno > 29)
     erroredata();
   }
   else if (giorno < 1 || giorno > 28)
    erroredata();
   break;
  default:
   printf("Errore nell'immissione del mese.\n Programma terminato.\n");
   exit(1);
 }
}
void controllogiorno(int giorno, int bisestile)
{
 if (!bisestile) {
  if (giorno < 1 || giorno > 365)
   erroregiorno();
 }
 else if (giorno < 1 || giorno > 366)
  erroregiorno();
}
void erroredata(void)
{
 printf("Errore nell'immissione del giorno.\n Programma terminato.\n");
 exit(1);
}
void erroregiorno(void)
{
 printf("Errore nell'immissione del giorno.\nProgramma terminato.\n");
 exit(1);
}
//Inizio file stampa_uscita.c:
//Funzioni per la stampa e per l'uscita dal programma giorni.
#include "giorni.h"
void stampaistruzioni(void)
//Stampa una sorta di manualetto del programma.
{
 printf("\n%s\n",
 "Questo programma esegue alcuni calcoli con le date.\n"
 "Scegliere il comando da eseguire.\n"
 "Premere m per ottenere il giorno del mese corrispondente al giorno 
dell'anno \nimmesso.\n"
 "Premere a per ottenere il giorno dell'anno corrispondente al giorno 
del mese \nimmesso.\n"
 "Premere s per ottenere il giorno della settimana successivo a quello 
immesso.\n"
 "Premere p per ottenere il giorno della settimana precedente a quello 
immesso.\n"
 "Premere h per ottenere un sintetico help sul funzionamento del 
programma.\n"
 "Premere q per uscire dal programma.\n");
}
void stampahelp(void)
//Stampa un elenco dei comandi del programma.
{
 printf("\n\n%s\n",
 "m = giorno del mese\n"
 "a = giorno dell'anno\n"
 "s = giorno successivo\n"
 "p = giorno precedente\n"
 "h = help (questa schermata.\n"
 "q = uscita dal programma.\n");
}
void esci(void)
//Gestisce la conferma e l'annullamento dell'uscita dal programma.
{
 char c;
 while (1) {
  printf("\nSei sicuro di voler uscire dal programma (s/n)? ");
  do {
   scanf("%c", &c);
  } while (c == '\n');
  switch (c) {
   case 's':
   case 'S':
    printf("\nCiao!");
    exit(1);
    break;
   case 'n':
   case 'N':
    return;
   default:
    printf("%c non è un comando valido.\n", c);
    printf("Inserisci s per sì o n per no.\n");
  }
 }
}

 ha scritto:


    printf("\nCiao!");
Ciao!

 char c, giornoset [256];
Potresti spiegarmi perché dovrei effettuare questa sostituzione? 
In particolare:
1 - perché il vettore dev'essere lungo 256?
2 - io dichiaro giornoset come vettore di puntatori a char; perché tu me 
lo fai dichiarare come vetture di char?
Ciao e grazie mille per la risposta.
Bizio. 

lo fai dichiarare come vettore di char?
Perche' tu lo dichiari ma lo fai puntare a una stringa nulla, che
contiene solo il carattere di terminazione. In questo modo, in
fase di avvio, viene allocato alla dimensione di un solo
carattere. La gets *copia* l'input in giornoset, quindi essa deve
risultare abbastanza grande da contenerlo.
Il problema non e' nella definizione, ma nell'allocazione dello
spazio. Avresti, ad esempio, potuto fare:
char *giornoset;
giornoset = malloc (256);
e non avresti avuto problemi.