PDA

View Full Version : [C] porting windows-mac


-hide-
12-01-2009, 19:39
Questo di seguito è il codice di un programma da me realizzato che su windows funziona, ma su mac no.
Cosa devo aggiustare per portarlo su Mac?

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

#define ELEM 100 // Numero massimo di contatti
#define NCHAR 21 // Numero di caratteri per l'erray

// Definizione della struttura
typedef struct {
char nome[NCHAR];
char cognome[NCHAR];
char telefono[NCHAR];
char citta[NCHAR];
} account;

// Variabili globali
account rubrica[ELEM];
int num_account = 0;

// Prototipi delle funzioni
void InsContatto (char nom[], char cogn[], char tel[], char cit[]);
void ModContatto (char nom[], char cogn[]);
void Cancella (char nom[], char cogn[]);
void Visualizza (char nom[], char cogn[]);

int main()
{ //OPEN main
int scelta; /* per inserire la scelta del menu' */
char n[NCHAR]; /* per inserire il nome */
char m[NCHAR]; /* per inserire il cognome */
char c[NCHAR]; /* per inserire la citta' */
char t[NCHAR]; /* per inserire il numero di telefono */
for (;scelta!= 0;)
{ //OPEN for
printf ("Rubrica V 1.0\n\n");
printf ("\t\t INDEX\n");
printf ("\t***************************\n");
printf ("\t* 1 - Inserisci Contatto *\n");
printf ("\t* 2 - Modifica Contatto *\n");
printf ("\t* 3 - Cancella Contatto *\n");
printf ("\t* 4 - Visualizza Contatto *\n");
printf ("\t* *\n");
printf ("\t* 0 - Esci dal programma *\n");
printf ("\t***************************\n\n");
printf ("Digita: ");
scanf ("%d", &scelta);
switch (scelta)
{ //OPEN switch
case 0: // Exit
break;
case 1: // Inserisci contatto
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
printf ("Telefono: ");
fflush (stdin);
gets (t);
printf ("Citta': ");
fflush (stdin);
gets (c);
printf ("\n");
InsContatto(n,m,t,c);
break;
case 2: // Modifica Contatto
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
ModContatto (n,m);
break;
case 3: // Cancella
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
Cancella (n,m);
break;
case 4: // Visualizza
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
Visualizza (n,m);
break;
} //CLOSED switch
} //CLOSED for
return 0;
} //CLOSED main

// Definizione delle funzioni
void InsContatto (char nom[], char cogn[], char tel[], char cit[])
{ //OPEN InsContatto
int i;
if (num_account == ELEM)
{ //OPEN if
printf ("Hai raggiunto il limite massimo di contatti\n\n");
return;
} //CLOSED if
for (i=0; i<=num_account; i++)
{ //OPEN for
if ((strcmp (nom,rubrica[i].nome)==0) && (strcmp (cogn,rubrica[i].cognome)==0))
{ //OPEN if
printf ("Nome e Cognome utente esistono in memoria\n\n");
return;
} //CLOSED if
} //CLOSED for
strcpy (rubrica[num_account].nome,nom);
strcpy (rubrica[num_account].cognome,cogn);
strcpy (rubrica[num_account].telefono,tel);
strcpy (rubrica[num_account].citta,cit);
printf ("\nIl contatto e' stato inserito correttamente\n\n");
num_account++;
return;
} //CLOSED InsContatto

void ModContatto (char nom[], char cogn[])
{ //OPEN ModContatto
int i;
for (i=0; i<=num_account; i++)
{ //OPEN for
if ((strcmp (nom,rubrica[i].nome)!=0) && (strcmp (cogn,rubrica[i].cognome)!=0))
{ //OPEN if
printf ("Il contatto non esiste\n\n");
return;
} //CLOSED if
else
{ //OPEN else
printf("Nuovo Nome: ");
fflush (stdin);
gets (rubrica[i].nome);
printf("Nuovo Cognome: ");
fflush (stdin);
gets (rubrica[i].cognome);
printf("Nuovo Telefono: ");
fflush (stdin);
gets (rubrica[i].telefono);
printf("Nuova Citta': ");
fflush (stdin);
gets (rubrica[i].citta);
return;
} //CLOSED else
} //CLOSED for
} //CLOSED ModContatto

void Cancella (char nom[], char cogn[])
{ //OPEN cancella
int i;
for (i=0; i<=num_account; i++)
{ //OPEN for
if ((strcmp (nom,rubrica[i].nome)!=0) && (strcmp (cogn,rubrica[i].cognome)!=0))
{ //OPEN if
printf ("Il contatto non esiste\n\n");
return;
} //CLOSED if
else
{ //OPEN else
rubrica[i].nome[0] ='\0';
rubrica[i].cognome[0] ='\0';
rubrica[i].telefono[0] ='\0';
rubrica[i].citta[0] ='\0';
printf ("\nContatto cancellato\n\n");
num_account--;
return;
} //CLOSED else
} //CLOSED for
} //CLOSED Cancella

void Visualizza (char nom[], char cogn[])
{ //OPEN Visualizza
int i;
for (i=0; i<=num_account; i++)
{ //OPEN for
if ((strcmp (nom,rubrica[i].nome)==0) && (strcmp (cogn,rubrica[i].cognome)==0))
{ //OPEN if
printf ("Il contatto scelto e': \n");
printf ("\n%s %s\n", rubrica[i].nome, rubrica[i].cognome);
printf ("%s\n%s\n\n", rubrica[i].telefono, rubrica[i].citta);
return;
} //CLOSED if
else
{ //OPEN else
printf ("Il contatto non esiste\n\n");
return;
} //CLOSED else
} //CLOSED for
} //CLOSED Visualizza

DanieleC88
12-01-2009, 20:12
Tutti i gets() sostituiscili con fgets(), tanto per cominciare. Fai conto che gets() non esista. :p
Poi, togli tutti i fflush(stdin), infine riprova. Se non risolve, spiegati meglio: in che senso "non funziona"?

ciao ;)

Aut0maN
12-01-2009, 21:30
mi sembra di intravedere uno degli esempi citati nella guida di Fabrizio Ciacchi di html.it che stò avidamente seguendo anch'io :)

cionci
12-01-2009, 22:43
mi sembra di intravedere uno degli esempi citati nella guida di Fabrizio Ciacchi di html.it che stò avidamente seguendo anch'io :)
Se usa fflush su stdin allo siamo freschi :D

-hide-
12-01-2009, 23:43
Tutti i gets() sostituiscili con fgets(), tanto per cominciare. Fai conto che gets() non esista.
Poi, togli tutti i fflush(stdin), infine riprova. Se non risolve, spiegati meglio: in che senso "non funziona"?


Non credo cambi molto, perché già una cosa simile l'avevo fatta.
Mi spiego meglio. Quando avvio il programma dal mac la prima istruzione di ogni case, cioè il printf "nome" viene saltata e compare una cosa del genere a schermo

nome: cognome:


da qui in poi funziona regolarmente, ma ormai è andato via una cosa importante del programma.

variabilepippo
12-01-2009, 23:54
Se usa fflush su stdin allo siamo freschi


Quello è il minimo...

Questo è l'Hello World proposto in quella "guida", non propriamente conforme allo standard ANSI C:


#include <stdio.h>

main ()
{
printf("Hello World!");
}


:eek:

cionci
13-01-2009, 09:22
Non credo cambi molto, perché già una cosa simile l'avevo fatta.
Mi spiego meglio. Quando avvio il programma dal mac la prima istruzione di ogni case, cioè il printf "nome" viene saltata e compare una cosa del genere a schermo

nome: cognome:


da qui in poi funziona regolarmente, ma ormai è andato via una cosa importante del programma.
Dove fflush effettivamente serviva non ce l'ha messo :D Rimane un invio nello standard input. L'invio non viene prelevato dalla scanf che legge la scelta.
Inserisci sotto alla scanf e al posto di ogni fflush(stdin):

while(getchar() != '\n');

Mi dai il link a questa guida ?

Aut0maN
13-01-2009, 10:34
Dove fflush effettivamente serviva non ce l'ha messo :D Rimane un invio nello standard input. L'invio non viene prelevato dalla scanf che legge la scelta.
Inserisci sotto alla scanf e al posto di ogni fflush(stdin):

while(getchar() != '\n');

Mi dai il link a questa guida ?

Te lo passo io:

http://programmazione.html.it/guide/leggi/32/guida-c/

piuttosto se ne conosci una realizzata meglio me la suggeriresti? :)
(preferirei materiale free)

cionci
13-01-2009, 10:59
piuttosto se ne conosci una realizzata meglio me la suggeriresti? :)
(preferirei materiale free)
Purtroppo non ne conosco :(

Ci sono alcune cose abbastanza inutili in quel codice:

// Popolo la variabile daInserire
printf (" NOME > ");
scanf ("%s", nome);
strcpy(daInserire.nome, nome);
printf (" COGNOME > ");
scanf ("%s", cognome);
strcpy(daInserire.cognome, cognome);
printf (" TELEFONO > ");
scanf ("%s", telefono);
strcpy(daInserire.telefono, telefono);
printf (" EMAIL > ");
scanf ("%s", email);
strcpy(daInserire.email, email);
printf (" SITOWEB > ");
scanf ("%s", sitoweb);
strcpy(daInserire.sitoweb, sitoweb);

Che senso ha usare quelle variabili di appoggio ? Perché non leggere direttamente i membri della struttura ? Anzi, perché non scrivere direttamente le informazioni nel nodo allocato dinamicamente ?

-hide-
13-01-2009, 11:04
Dove fflush effettivamente serviva non ce l'ha messo Rimane un invio nello standard input. L'invio non viene prelevato dalla scanf che legge la scelta.
Inserisci sotto alla scanf e al posto di ogni fflush(stdin):

while(getchar() != '\n');

Allora ho fatto una prova.
L'istruzione scritta dopo la scanf risolve il problema del salto del printf "nome".
Inserendo la stessa funzione prima di tutti i gets si attende un invio per far partire l'istruzione e questo rende il programma un pò troppo lento. Quindi l'ho levato e funziona comunque correttamente.

Mi ero dimenticato una cosa invece. Su mac non mi fa dichiarare scelta come short int. Al momento del lancio del programma da terminale il programma parte già concluso.

cionci
13-01-2009, 11:11
Diciamo che quel ciclo fa la stessa funzione di fflush(stdin).
Comunque è strano, gets non dovrebbe prelevare lo '\n' dallo stdin...l'unica funzione di input che preleva lo '\n' è fgets.
Edit: aspetta, lo devi inserire dopo gets, non prima ;)

Sostituisci SEMPRE gets e scanf("%s", xxx) con fgets. gets non permette di controllare che il numero di caratteri inseriti sia minore della dimensione dei buffer di lettura usati.
http://www.cplusplus.com/reference/clibrary/cstdio/fgets.html

Ad esempio:

char nome[50];
fgets(nome, 50, stdin);

cionci
13-01-2009, 11:17
Assurdo :muro: :muro:


int scelta; /* per inserire la scelta del menu' */
[cut]
for (;scelta!= 0;)


Parte dal presupposto che scelta sia già diverso da zero. In molti compilatori le variabili automatiche vengono inzializzate nello stack proprio con il valore zero. Uno dei pochi che non lo fa è il compilatore Microsoft :muro:
E' questo il motivo per cui ti esce, mah :rolleyes:

Inizializza scelta a 1:

int scelta = 1;

Per lo short, utilizza solo short:

short scelta = 1;

cionci
13-01-2009, 11:27
Cercavo il modo di contattare quelli di html.it per dirgli che la guida era inadeguata, ma non sono riuscito a sapere da dove sia possibile farlo :confused:

-hide-
13-01-2009, 11:41
il while dopo fgets non cambia la cosa di prima. Sempre attende l'invio. E cmq così sembra funzionare correttamente l'inserimento da input.
Lo short pure risolto ^^
Ora però quando faccio visualizza non formatta più il testo come l'ho deciso io. Va a capo per la mia istruzione e poi di nuovo a capo.
fgets magari non è compatibile con printf?!


Per HTML.it prova a contattare l'amministratore del forum.

cionci
13-01-2009, 11:55
Il while lo devi usare con gets, ma non con fgets ;)
fgets ripulisce già lo stdin (legge fino a '\n' compreso).

fgets include lo \n all'interno della stringa. E' per quello che ti stampa strano.

Scrivi una funzione:

int readString(char *buffer, int size)
{
fgets(buffer, size, stdin);
if(buffer[strlen(buffer)] - 1] == '\n')
{
//ho '\n' in fondo alla stringa, allora lo devo rimuovere
buffer[strlen(buffer)] - 1] = '\0';
return 0;
}
//ci sono ancora caratteri in stdin
return 1;
}
Questa funzione sopra può essere generica e permette di far gestire al chiamante il caso in cui ci siano ancora caratteri sullo stdin.
In questo programma, invece, se ci sono altri caratteri su stdin potresti tranquillamente svuotarlo:

void readString(char *buffer, int size)
{
fgets(buffer, size, stdin);
if(buffer[strlen(buffer)] - 1] == '\n')
{
//ho '\n' in fondo alla stringa, allora lo devo rimuovere
buffer[strlen(buffer)] - 1] = '\0';
}
else
{
while(getchar() != '\n');
}
}
Ovviamente restano caratteri nello stdin nel caso in cui venga inserita una stringa più grande della dimensione massima che il vettore di char può contenere.

-hide-
13-01-2009, 12:55
fgets include lo \n all'interno della stringa. E' per quello che ti stampa strano.

Immaginavo. Comunque questa cosa ora vedo di risolverla con gli esempi che mi hai fatto.
Invece visto che ci siamo ne chiedo un'altra. Per pulire lo schermo si usa

system ("clear"); // per unix
system ("cls"); // per windows

Ma dove le vado a mettere nel programma per farmi visualizzare sempre il meno all'uscita dal break. Mi conviene fare un ciclo in cui schiacciando un tasto si pulisce?

cionci
13-01-2009, 16:11
Immaginavo. Comunque questa cosa ora vedo di risolverla con gli esempi che mi hai fatto.
Non è un esempio, è proprio la funzione che devi inserire nel codice.
Inserisci

readString(nome, NCHAR);

dove nel codice iniziale c'è gets ;)

Invece visto che ci siamo ne chiedo un'altra. Per pulire lo schermo si usa

system ("clear"); // per unix
system ("cls"); // per windows

Ma dove le vado a mettere nel programma per farmi visualizzare sempre il meno all'uscita dal break. Mi conviene fare un ciclo in cui schiacciando un tasto si pulisce?
Spiegati meglio...

-hide-
13-01-2009, 16:15
Ho semplicemente sbagliato a scrivere.
Vorrei visualizzare sempre solo il menù all'uscita dei vari case, quindi dopo il break intendendoci. Cioè si dovrebbe pulire lo schermo e rimanere sempre come prima cosa il menù. Le istruzioni per pulire lo schermo che ho trovato sono quelle, ma non riesco a cogliere la giusta posizione per ottenere ciò che io desidero.

Per le funzioni al più presto faccio;)

cionci
13-01-2009, 16:19
Alla fine dello switch, prima della parentesi chiusa del for ;)

DanieleC88
13-01-2009, 19:14
O all'inizio, appena prima di stampare il menù. :)

cionci
13-01-2009, 19:20
O all'inizio, appena prima di stampare il menù. :)
Forse meglio lì in effetti

-hide-
13-01-2009, 19:49
Mi sa invece di no. Servirà un'istruzione da aggiungere perché se lo metto così liberamente si perde il significato alcune istruzioni di conferma da me inserite o della funzione visualizza. In tal caso non visualizzerebbe più perché finito il break cancella

DanieleC88
13-01-2009, 19:52
Eh? :D

-hide-
13-01-2009, 21:57
Allur. Sempre la fretta. Le cose o si fanno bene o non si fanno :D

Mettendo il system ("clear") dopo il for o prima dello switch, cancella anche alcune parti che dovrebbero momentaneamente rimanere a monitor.

Esempio: se chiedo di visualizzare, deve permettermi di vederlo e quindi deve pulire lo schermo dopo che io leggo le informazioni richieste.

Allora a sto punto magari è necessario un if di richiesta pulisci schermo. Spero sia più chiaro:cool:

DanieleC88
13-01-2009, 22:04
Allora mettilo prima del while ed alla fine del while.

cionci
14-01-2009, 10:32
Allur. Sempre la fretta. Le cose o si fanno bene o non si fanno :D

Mettendo il system ("clear") dopo il for o prima dello switch,
Prima dello switch non te l'ha detto nessuno di metterlo :D

cionci
14-01-2009, 10:51
Il posto dove metterlo è:

int main()
{ //OPEN main
int scelta; /* per inserire la scelta del menu' */
char n[NCHAR]; /* per inserire il nome */
char m[NCHAR]; /* per inserire il cognome */
char c[NCHAR]; /* per inserire la citta' */
char t[NCHAR]; /* per inserire il numero di telefono */
for (;scelta!= 0;)
{ //OPEN for <-----------QUI
printf ("Rubrica V 1.0\n\n");
printf ("\t\t INDEX\n");
printf ("\t***************************\n");
printf ("\t* 1 - Inserisci Contatto *\n");
printf ("\t* 2 - Modifica Contatto *\n");
printf ("\t* 3 - Cancella Contatto *\n");
printf ("\t* 4 - Visualizza Contatto *\n");
printf ("\t* *\n");
printf ("\t* 0 - Esci dal programma *\n");
printf ("\t***************************\n\n");
printf ("Digita: ");
scanf ("%d", &scelta);
switch (scelta)
{ //OPEN switch
case 0: // Exit
break;
case 1: // Inserisci contatto
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
printf ("Telefono: ");
fflush (stdin);
gets (t);
printf ("Citta': ");
fflush (stdin);
gets (c);
printf ("\n");
InsContatto(n,m,t,c);
break;
case 2: // Modifica Contatto
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
ModContatto (n,m);
break;
case 3: // Cancella
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
Cancella (n,m);
break;
case 4: // Visualizza
printf ("\nNome: ");
fflush (stdin);
gets (n);
printf ("Cognome: ");
fflush (stdin);
gets (m);
Visualizza (n,m);
break;
} //CLOSED switch
} //CLOSED for
return 0;
} //CLOSED main

Se non ti si ferma in tempo per leggere l'output metti un "readString" di attesa dopo la chiusura dello switch oppure dopo i rami dello switch che necessitano attesa.