PDA

View Full Version : [C] problema con i file


D4rkAng3l
04-05-2005, 18:04
Stavo provando a fare un programma preso dal manuale...però apparte non funzionare (compila ma non funziona bene) non capisco il perchè di alcune cose che mi sembrano strane...

Il programma dovrebbe chiedere in input il nome di un file,crearlo e scriverci dentro quello che viene immesso da tastiera finchè non si preme il tasto ? a questo punto chiude il file e termina l'esecuzione...

Il codice è questo:

/* KTOD Un programma di copia dalla tastiera a disco */

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

int main(int argc, char *argv[]){

FILE *fp; // Puntatore a file
char ch; // Carattere

if(argc != 2){
printf("Hai dimenticato di scrivere il nome del file.\n");
exit(1);
}

if((fp=fopen(argv[1], "w")) == NULL){
printf("Impossibile aprire il file.\n");
exit(1);
}

do{
ch = getchar(); // Prendi un carattere da tastiera e mettilo in ch
putch(ch, fp);
}while(ch != '$');

fclose(fp);
return 0;
}

Non capisco perchè in questa riga:

int main(int argc, char *argv[]){

vengono passati degli argomenti al main...che sono?che significano? e prechè non funziona ? copiato pari pari dal manuale....

Grazie

mjordan
04-05-2005, 18:25
Stavo provando a fare un programma preso dal manuale...però apparte non funzionare (compila ma non funziona bene) non capisco il perchè di alcune cose che mi sembrano strane...

Il programma dovrebbe chiedere in input il nome di un file,crearlo e scriverci dentro quello che viene immesso da tastiera finchè non si preme il tasto ? a questo punto chiude il file e termina l'esecuzione...

Il codice è questo:

/* KTOD Un programma di copia dalla tastiera a disco */

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

int main(int argc, char *argv[]){

FILE *fp; // Puntatore a file
char ch; // Carattere

if(argc != 2){
printf("Hai dimenticato di scrivere il nome del file.\n");
exit(1);
}

if((fp=fopen(argv[1], "w")) == NULL){
printf("Impossibile aprire il file.\n");
exit(1);
}

do{
ch = getchar(); // Prendi un carattere da tastiera e mettilo in ch
putch(ch, fp);
}while(ch != '$');

fclose(fp);
return 0;
}

Non capisco perchè in questa riga:

int main(int argc, char *argv[]){

vengono passati degli argomenti al main...che sono?che significano? e prechè non funziona ? copiato pari pari dal manuale....

Grazie

Sbagli concettualmente.
Il programma non chiede in input il nome di un file ma VUOLE in input il nome del file. Non ho compilato e eseguito, ma noto che questa potrebbe essere la prima causa del tuo problema.

Nella riga del main(), argc identifica il numero di argomenti passati al programma mentre argv e' un array di stringhe, che contiene appunto i parametri passati al programma.
Inoltre la funzione putch() non so da dove provenga, ma non e' affatto standard. Sostituiscila con putc(). In ultimo, il programma termina la sua esecuzione una volta digitato il carattere '$' e non '?'.

D4rkAng3l
04-05-2005, 18:27
ok..ma allora come glielo dò in input il nome del file..dove glielo devo mettere?

VICIUS
04-05-2005, 18:29
ok..ma allora come glielo dò in input il nome del file..dove glielo devo mettere?
glielo passi come argomento quando lo lanci ./programma nome_del_file.txt
nei sorgenti poi lo leggi accedendo ad argv[1]

ciao ;)

D4rkAng3l
04-05-2005, 18:31
glielo passi come argomento quando lo lanci ./programma nome_del_file.txt
nei sorgenti poi lo leggi accedendo ad argv[1]

ciao ;)

ahhhh ora ho capito, quindi gli argomenti del main vengono passato lanciando al lancio del programma...questo non c'era scritto...fico...buono a sapersi

RaouL_BennetH
04-05-2005, 18:32
Sbagli concettualmente.

Inoltre la funzione putch() non so da dove provenga, ma non e' affatto standard. Sostituiscila con putc(). In ultimo, il programma termina la sua esecuzione una volta digitato il carattere '$' e non '?'.

Difatti, è definita in <conio.h> e tra l'altro, prende un solo argomento e non due.

Con "difatti" intendo che non è standard :)

VegetaSSJ5
04-05-2005, 18:32
la funzione main ha dei parametri impliciti. questi parametri sono i parametri che tu passi da riga di comando al programma. ad esempio quando compili un programma (con il compilatore gcc) scrivi una cosa del tipo:

gcc nomeprogramma.c

oppure

gcc nomeprogramma.c -o programma

come fa il compilatore gcc a sapere quali dati gli hai passato come parametro? i parametri passati da linea di comando al programma sono i parametri del main. il main ha 2 parametri (veramente non sono sempre 2, cmq assumiamone 2) di cui:
- il primo è un intero (che puoi chiamare come ti pare, basta che la dichiari come intero) che indica il numero di parametri che hai passato. questo numero è sempre maggiore o uguale a 1 perchèconta anche il nome del programma (es: gcc nome.c -o ciao, qui la variabile conterrà il valore 4)
- il secondo è un array di stringhe (cioè un array di array di char) dove ogni stringa è un parametro che hai passato al programma
es: gcc nome.c -o ciao

argc --> 4

argv[0] --> gcc
argv[1] --> nome.c
argv[2] --> -o
argv[3] --> ciao


P.S.
quando ho premuto Rispondi ancora non erano state date risposte... :eek:

D4rkAng3l
04-05-2005, 18:36
la funzione main ha dei parametri impliciti. questi parametri sono i parametri che tu passi da riga di comando al programma. ad esempio quando compili un programma (con il compilatore gcc) scrivi una cosa del tipo:

gcc nomeprogramma.c

oppure

gcc nomeprogramma.c -o programma

come fa il compilatore gcc a sapere quali dati gli hai passato come parametro? i parametri passati da linea di comando al programma sono i parametri del main. il main ha 2 parametri (veramente non sono sempre 2, cmq assumiamone 2) di cui:
- il primo è un intero (che puoi chiamare come ti pare, basta che la dichiari come intero) che indica il numero di parametri che hai passato. questo numero è sempre maggiore o uguale a 1 perchèconta anche il nome del programma (es: gcc nome.c -o ciao, qui la variabile conterrà il valore 4)
- il secondo è un array di stringhe (cioè un array di array di char) dove ogni stringa è un parametro che hai passato al programma
es: gcc nome.c -o ciao

argc --> 4

argv[0] --> gcc
argv[1] --> nome.c
argv[2] --> -o
argv[3] --> ciao


P.S.
quando ho premuto Rispondi ancora non erano state date risposte... :eek:

ah sei stato chiarissimo, grazie mille...quindi quà scrivo:
char *argv[]

perchè tanto argv è un puntatore al primo elemento dell'array, mettendoci un * è puntatore a puntatore perchè punta ad un array di array...giusto?

VegetaSSJ5
04-05-2005, 18:39
ah sei stato chiarissimo, grazie mille...quindi quà scrivo:
char *argv[]

perchè tanto argv è un puntatore al primo elemento dell'array, mettendoci un * è puntatore a puntatore perchè punta ad un array di array...giusto?
le stringhe in c si realizzano con gli array (o con i puntatori) di char. quindi se tu scrivi char argv[] oppure char *argv stai implicitamente dichiarando una stringa. se scrivi char argv[][] oppure char *argv[] oppure char **argv stai dichiarando un array di stringhe.

mjordan
04-05-2005, 18:46
Che poi scusa, quale manuale?
Esiste sul pianeta un manuale che presenti come esempio uno schifo di codice del genere? Addirittura include nel file da scrivere il carattere terminatore, che invece non dovrebbe essere scritto.

Questa versione, invece, conclude senza includere il carattere terminatore:


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

int
main(int argc, char ** argv)
{
FILE *fp;
char ch;

if (argc != 2) {
printf("Hai dimenticato di scrivere il nome del file.\n");
exit(1);
}

if ((fp=fopen(argv[1], "w")) == NULL) {
printf("Impossibile aprire il file.\n");
exit(1);
}

while (ch != '$') {
putc(ch, fp);
ch = getchar();
};

fclose(fp);

return 0;
}


Sarei proprio curioso di sapere il titolo di tale scempio.

mjordan
04-05-2005, 18:53
Difatti, è definita in <conio.h> e tra l'altro, prende un solo argomento e non due.

Con "difatti" intendo che non è standard :)

Non la conosco, saresti cosi' gentile da darmi il prototipo e il funzionamento?

VICIUS
04-05-2005, 18:56
Che poi scusa, quale manuale?

int
main(int argc, char ** argv)
{
FILE *fp;
char ch;
[...]
while (ch != '$') {
putc(ch, fp);
ch = getchar();
};
[...]
}



Ma in questo modo ch non è inizializato. C'è la possibilità che sia == a '$' e quindi il ciclo non partirebbe neanche. E' meglio porre ch = 0; quando viene dichiarata. oppure fare
while ((ch = getchar ()) != '$')
putc (ch, fp);

ciao ;)

VegetaSSJ5
04-05-2005, 18:57
int putch(int c)

scrive un carattere su stdout

mjordan
04-05-2005, 19:14
Ma in questo modo ch non è inizializato. C'è la possibilità che sia == a '$' e quindi il ciclo non partirebbe neanche. E' meglio porre ch = 0; quando viene dichiarata. oppure fare
while ((ch = getchar ()) != '$')
putc (ch, fp);

ciao ;)

Sono 5 anni che lo standard C impone che le variabili siano automaticamente poste a 0 e i puntatori a NULL dal compilatore in fase di dichiarazione. Se ispezioni con un debugger, vedi che fp punta automaticamente a NULL e ch a 0.
Anche il C ogni tanto si aggiorna, eh!

mjordan
04-05-2005, 19:18
int putch(int c)

scrive un carattere su stdout

Ecco, non ne avevo dubbi la classica estensione Microsoft della min[k]ia.
Praticamente la copia della funzione standard putchar() che gia' e' ridondante perche' ha il comportamento di putc(ch, stdout).

Come aumentare il footprint delle librerie in modo inutile e controverso.

VICIUS
04-05-2005, 19:21
Sono 5 anni che lo standard C impone che le variabili siano automaticamente poste a 0 e i puntatori a NULL dal compilatore in fase di dichiarazione. Se ispezioni con un debugger, vedi che fp punta automaticamente a NULL e ch a 0.
Anche il C ogni tanto si aggiorna, eh!
Sei sicuro ? in gcc anche impostando -std=c99 non vengono inizializzate a 0. :confused:

ciao ;)

mjordan
04-05-2005, 19:42
Sei sicuro ? in gcc anche impostando -std=c99 non vengono inizializzate a 0. :confused:

ciao ;)

Sul mio sistema, compilando con:
gcc -Wall -g -o prova prova.c

e avviando il debugger con:
gdb --readnow prova


GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1".

(gdb) set args file_di_esempio
(gdb) break main
Breakpoint 1 at 0x80484b0: file prova.c, line 9.
(gdb) run
Starting program: /home/mjordan/prova file_di_esempio

Breakpoint 1, main (argc=2, argv=0xbffff664) at prova.c:9
11 if (argc != 2) {
(gdb) p ch
$1 = 0 '\0'
(gdb) p fp
$2 = (FILE *) 0x0
(gdb) quit
The program is running. Exit anyway? (y or n) y

VegetaSSJ5
04-05-2005, 20:05
Ecco, non ne avevo dubbi la classica estensione Microsoft della min[k]ia.
:asd:

VICIUS
04-05-2005, 20:11
Sul mio sistema, compilando con:
gcc -Wall -g -o prova prova.c

e avviando il debugger con:
gdb --readnow prova[...]
strano da me ch è -73 e fp è 0x8qualcosa.

ciao ;)

VegetaSSJ5
04-05-2005, 20:16
mi autonomino giudice della situazione... :O

vicius e mjordan che compilatori usate?? (compilatore, versione, sistema operativo)

VICIUS
04-05-2005, 20:20
mi autonomino giudice della situazione... :O

vicius e mjordan che compilatori usate?? (compilatore, versione, sistema operativo)
ehehe :D
gcc, 3.3.5, linux

ciao ;)

mjordan
04-05-2005, 20:35
mi autonomino giudice della situazione... :O

vicius e mjordan che compilatori usate?? (compilatore, versione, sistema operativo)

A sto punto non credo dipenda niente da tutto cio'. In ogni caso sta scritto pure sul manuale di GCC che anche con il flag -std=gnu89 le variabili vengono assegnate a 0 e i puntatori a NULL. Solo che con -std=gnu89 (il comportamento di default) lo fa come estensione, mentre con -std=c99 lo fa come standard.

mjordan
04-05-2005, 20:39
ehehe :D
gcc, 3.3.5, linux

ciao ;)

Il 3.3.5 e' troppo vecchio. E io sto col 4.0.0 che e' troppo nuovo :D
Proprio oggi ho fatto un bug report che e' stato riconosciuto come ice-on-valid-code, meno male che hanno messo il target per il fix nel 4.0.1
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21379

D4rkAng3l
06-05-2005, 11:48
Ragazzi scusate se rompo ancora le balle ma non mi funziona (stò sotto win non sò se c'entra qualcosa):

con il dev c++ compila ma quando dò esegui apre la finestra dos e la richiude subito senza che si reisca a vedere nulla...perchè?!?!

RaouL_BennetH
06-05-2005, 11:59
Ragazzi scusate se rompo ancora le balle ma non mi funziona (stò sotto win non sò se c'entra qualcosa):

con il dev c++ compila ma quando dò esegui apre la finestra dos e la richiude subito senza che si reisca a vedere nulla...perchè?!?!

E' piuttosto semplice, e in diversi 3d è stato già postato, anche da me:

1) O ti apri il prompt del dos e ti porti nella dir dove hai creato l'eseguibile e lo lanci da riga di comando

2) O aggiungi un system("PAUSE") nel sorgente ma non è un buono stile di programmazione

3) Generati un evento che chieda di premere un tasto per uscire (es. premi q per uscire)

Questo perchè stai progettando delle console application.

Ciao :)

D4rkAng3l
06-05-2005, 17:13
ok..adesso ho capito e funziona...

Altro problema...ho fatto il programma opposto...gli si dà in input un file al lancio del programma, come quello che lo scrive, e lui apre un file precedentemente scritto...peccato che non me lo apre...fopen() fallisce ma il file è presente nella dir...booo

/* DTOS: Legge il contenuto di un file e lo visualizza sullo schermo */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

FILE *fp; // Puntatore al file di cui si vuole visualizzare il contenuto
char ch; // Carattere corrente letto dal file puntato da fp

if(argc != 2){
printf("Hai dimenticato di inserire il nome del file da leggere.\n");
exit(1);
}

if((fp = fopen("argv[1]", "r")) == NULL){
printf("Impossibile aprire il file da leggere.\n");
exit(1);
}

ch = getc(fp); // Legge il primo carattere nel file puntato da fp

while(ch != EOF){
putchar(ch); // Visualizza il carattere se non è un carattere EOF
ch = getc(fp); // Legge il carattere successivo nel file puntato da fp
}

fclose(fp); // Chiude il file puntato da fp
return 0;
}

mjordan
06-05-2005, 17:37
ok..adesso ho capito e funziona...

Altro problema...ho fatto il programma opposto...gli si dà in input un file al lancio del programma, come quello che lo scrive, e lui apre un file precedentemente scritto...peccato che non me lo apre...fopen() fallisce ma il file è presente nella dir...booo

/* DTOS: Legge il contenuto di un file e lo visualizza sullo schermo */
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

FILE *fp; // Puntatore al file di cui si vuole visualizzare il contenuto
char ch; // Carattere corrente letto dal file puntato da fp

if(argc != 2){
printf("Hai dimenticato di inserire il nome del file da leggere.\n");
exit(1);
}

if((fp = fopen("argv[1]", "r")) == NULL){
printf("Impossibile aprire il file da leggere.\n");
exit(1);
}

ch = getc(fp); // Legge il primo carattere nel file puntato da fp

while(ch != EOF){
putchar(ch); // Visualizza il carattere se non è un carattere EOF
ch = getc(fp); // Legge il carattere successivo nel file puntato da fp
}

fclose(fp); // Chiude il file puntato da fp
return 0;
}


Perche' a fopen() hai passato il primo argomento tra virgolette. In quel modo va cercando il file che si chiama "argv[1]" non il file contenuto in argv[1]. Se invece togli le virgolette, il programma funziona.

in altre parole devi sostituire:

if ((fp = fopen("argv[1]", "r")) == NULL)


con:

if ((fp = fopen(argv[1], "r")) == NULL)

D4rkAng3l
06-05-2005, 17:41
sono sbadato :mc: :muro:

mjordan
06-05-2005, 18:15
sono sbadato :mc: :muro:

Tranquillo gli errori semantici sono molto piu' comuni degli errori sintattici. Non e' difficile incappare in simili errori. Se ti posso suggerire un miglioramento di stile, utilizza un ciclo do-while per effettuare la lettura dei caratteri. Risparmi di ripetere la getc() due volte:


do {
ch = getc(fp);
putchar(ch);
} while (ch != EOF);


Ciao.