Newsgroup: it.comp.lang.c
Titolo: Mi arrendo

Perchï¿œ, secondo voi, questo codice non funziona???
 
Sto provando a portare un vecchio programma C (console) da unix a 
windows, uso mingw/gcc 4.6.2. Il programma gira bene finchï¿œ non incontra 
la prima strcpy/strcat/strqualcosa, poi aspetta qualche secondo ed esce 
con codice errore 0xC0000005 (checcazz???)
 
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* molti altri include */
 
int main(int argc, char *argv[])
{
char	games[256];
strcpy(games, "games/default");
 
/* ecc. ecc. */
 
}
 


Penso che il problema sia in quell ecc. ecc.


Questo frammento ï¿œ ok.. credo che l'errore sia altrove :)
 
-- 
Vincenzo Mercuri


 
PS: ovviamente sto dando per scontato che il codice non mostrato
contenga almeno un "return 0;" da qualche parte, o equivalenti.

 Questo frammento ï¿œ ok.. credo che l'errore sia altrove :)
 
Ho provato a sostituire/cambiare funzioni: non serve. Ogni volta che il 
programma incontra una funzione di libreria della serie str***() crasha 
nel modo sopra descritto. Il codice di errore riportato, sotto windows, 
si riferisce a un errore GPF generico, il che mi porta a ritenere che la 
funzione usi un puntatore non valido. Ma perchï¿œ?
 
Comincio a sospettare che il problema sia in qualche include: il 
programma originale usava diversi include (tipo termios.h) che sotto 
windows semplicemente non esistono, e mi sono dovuto arrangiare a 
trovare include equivalenti e/o a sostituire le funzioni nel codice con 
altre di windows... forse uno di questi include "nuovi e diversi" 
contenga qualcosa che faccia sclerare le lib. Ma come? E qual'ï¿œ???
 
Per inciso, come dici anche tu, se metto quel pezzetto di codice in un 
"hello world" di prova, funziona benissimo.
 
 

 "hello world" di prova, funziona benissimo.
 
Nel frammento che hai postato c'ï¿œ solo una chiamata a strcpy(), fatta
in modo corretto. Ma potrebbe essere che nel codice che non hai postato
la situazione non sia cosï¿œ semplice.
 
-- 
Vincenzo Mercuri

Il 15/08/2012 12:35, Massimo Soricetti ha scritto:

Se lo segui con un debugger ï¿œ quella la funzione che si pianta (o un 
altra strcpy) ?

 altra strcpy) ?
 
Sto cercando di capire come far fungere gdb con codeblocks... appena ci 
riesco te lo dico :-(

 strcpy(games, "games/default");
                      ^
se sei su win e cerchi di aprire una directory con questo path (con il
separatore / invece di \) mi sa che crea un po' di problemi.
 
Ciao Jack
-- 
Yoda of Borg am I! Assimilated shall you be! Futile resistance is, hmm?

 
 
So...
Come tutti ben sappiamo il separatore di directory sui sistemi unix è il carattere '/', mentre sui sistemi windows è '\' (tralascio gli altri, ma che io sappia è comunque uno dei due anche se, N.B. potrebbe essere uno qualsiasi, anche la lettera 'q', quindi in teoria... lascio a voi le conclusioni che mi hanno un po' sconvolto).
Come tutti ben sappiamo, poi, in C il carattere di escape nelle stringhe è '\' (come nei familiari '\n', '\0').
In windows, quando si programma in C, si tende quindi a utilizzare o l'escape del carattere di escape ('\\') o qualche estensione del compilatore (@"c:\pippo\" per chi ama i compilatori MS).
In questo caso il separatore di directory è unix e il sistema è windows. Il sistema potrebbe anche fare qualcosa di brutto andando a cercare la directory (sarebbe strano, ma chissà?) ma di sicuro il compilatore non potrebbe fare cose strane con la stringa (se ad esempio fosse '\q' farebbe un escaping, mentre non è questo il caso).
Direi quindi che questo non è riconducibile al problema dell'OP.
Per quanto riguarda questo, anch'io tendenzialmente direi che si tratta di altro, per cui una domanda: <per l'OP> ma hai provato a compilare quello che hai postato qui? No perché se non compila è un problema di installazione/configurazione, per cui potresti smadonnare per giorni inutilmente..
M2C
Ciao!

 M2C
 
L'OP ha detto di aver compilato quel frammento di codice in un "hello 
world"
di prova, senza errori. Il che mi fa dedurre che l'errore stia altrove..
ma i poteri della mia sfera di cristallo non mi permettono di andare 
oltre :)
 
-- 
Vincenzo Mercuri


Se non riesci a usare il debugger puoi andare con i vecchi metodi pre 
debugger
 
tante fprintf(STDERR,"%s %d  %s\n",__FILE__,__LINE__," punto 1")
ad esempio nei punti che consideri caldi
 
 
 

 con codice errore 0xC0000005 (checcazz???)
 
NO CHE CAZZO LO DICO IO. ED AGGIUNGO VAFFANCULO RICCHIONE.
 
Prima di tutto posta tutto il messaggio di errore che restituisce 
gcc e non solo il codice: magari se lo leggi puoi anche capire cosa
è successo.
 
Seconda cosa prima di postare passa il codice dell'errore a san google
che magari trovi centinaia di pagine che trattano l'argomento. 
E magari ti accorgi che gcc non trova la libreria e che il bug è noto.
 
E visto che l'errore sta nel linker posta il comando che usi per 
compilare e linkare il programma.
 
E visto che l'errore non sta tanto nel linker ma nella versione delle
librerie che il tuo sistema operativo usa, dicci quale sistema 
operativo usi.
 
Infine, visto che sei incappato in un bug di gcc, non postare qui.
 
PLONK

 separatore / invece di \) mi sa che crea un po' di problemi.
 
Non ï¿œ quella la strcpy su cui si impalla l'exe. E comunque ï¿œ 
irrilevante: ho giï¿œ detto che qualsiasi funzione di libreria dï¿œ 
problemi. Per dire, se commento la strcpy incriminata, il programma si 
impalla su una strcat() poche righe piï¿œ sotto.
 
Come detto, ho anche provato a fare un piccolo programmino di prova e 
compilare codice contenente strcpy, strlen, strdup ecc. ecc.: nessun 
problema, tutto funziona benissimo.
 
Quindi, gcc e codeblocks, per conto loro, funzionano. In questo 
particolare codice, perï¿œ, le funzioni di libreria sclerano e non so 
perchï¿œ. Forse mi conviene postare una porzione un pï¿œ piï¿œ ampia di 
codice... ecco qua la funzione in cui si impalla tutto:
 
----------------------------------------------------
 
char	*
default_game()
{
	FILE		*fp;
	static char	file[256];
	char		line[256], games[256];
 
	strcpy(games, "games/default");
 
	if ((fp = fopen(games, "r")) == NULL) {
		fprintf(stderr, "2 - fopen %s", games);
		return (NULL);
	}
	if (fgets(line, sizeof(line), fp) == NULL) {
		fprintf(stderr, "%s: no default game available\n", games);
		return (NULL);
	}
	fclose(fp);
	line[strlen(line) - 1] = '\0';
	strcat("games/", line);
	return (file);
}
------------------------------------------------
 
 


 
Bingo.
 
In effetti la strcpy costruiva un pezzo di path per un file, e in 
effetti subito dopo c'era una fopen()... i miei tentativi con gdb su 
codeblocks indicavano che il blocco avveniva sulla strcpy e non sulla 
fopen dopo. :-(
 
Cambiato il path con uno piï¿œ "windowsiano" il problema scompare :-)
 

conclusioni che mi hanno un po' sconvolto).
 
Certo, ma / e' un carattere accettabile per un nome di file/directory in
windows? Perche' se non lo e', crea problemi.
E se non sbaglio non lo e'.


 Cambiato il path con uno pi� "windowsiano" il problema scompare :-)
 
:)
 
ormai chiunque abbia fatto un porting (in un qualsiasi linguaggio) tra
due OS differenti ci ha sbattuto il naso.



accodare line ad una costante, ï¿œ li il problema
La sintassi di strcat ï¿œ strcat(char* dest,const char* src)
forse volevi strcat(line,"games/");
 
 

 Cambiato il path con uno più "windowsiano" il problema scompare :-)
 
 
Strano, perchè sapevo che la libc di Windows accettava anche i path con 
separatore di directory UNIX.
 
 
Ciao  Manlio

 E se non sbaglio non lo e'.
 
Forse intendi dire se � accettabile come separatore? Si.
Non so voi, ma se scrivo "cd MinGW/bin" nel terminale cmd e mi trovo in
"C:\" entro nella directory senza problemi. Stessa cosa per l'accesso
a files: se scrivo "notepad C:/MinGW/file.txt" lo apre senza problemi.
Le API win32 di Windows supportano entrambi i separatori senza problemi,
solo che nel caso di "\" come ha detto fmassei devi ricordarti di usare
la sequenza di escape "\\".
 
-- 
Vincenzo Mercuri

 separatore di directory UNIX.
 
Esatto, ed è quello che sapevo anch'io, almeno per quanto riguarda win32.
 
-- 
Vincenzo Mercuri

 }
[..]
 
Dichiari "file", array che non usi mai. Poi lo restituisci, a meno che
la funzione postata non sia al completo direi che non ha assolutamente
senso questo valore di ritorno.
 
-- 
Vincenzo Mercuri

 Esatto, ed � quello che sapevo anch'io, almeno per quanto riguarda win32.
 
solo da voi.



 
Il modo migliore � provare. Sul mio sistema (Windows 7 64-bit)
funziona come previsto. Naturalmente il file deve gi� esistere
(se si vuole usare la "fopen" dell'OP).
 
-- 
Vincenzo Mercuri

 
 
Fondamentalmente se si utilizza mingw sotto win è per avere lo *stesso* codice compilabile e funzionante su linux e windows, quindi mettere un path hard-coded è un errore quantomeno di concetto.
Sinceramente non so se funzioni o meno, di sicuro io personalmente cercherei un modo di o passargli la stringa dall'esterno (quindi da parametro o da file di configurazione) o leggere un file nella cartella corrente (cosa che però potrebbe essere complicata, a seconda dell'utilizzo della directory corrente).
Quindi, sempre personalmente per fare le cose a modino, su un sistema compatibile POSIX io farei prendere da riga di comando il path del file (o il path del file di configurazione che lo contiene), visto che non vedo altri modi portabili per ottenere lo stesso risultato (ad avere fantasia si potrebbe anche lasciare il file nella stessa directory dell'eseguible, combinare una serie di getcwd()/chdir()/dirname() (su argv[0]) e soprattutto scrivere una buona gestione dell'errore per quando il file non potrà essere aperto a causa di chissà quali permessi utente).
Ciao!

 Fondamentalmente se si utilizza mingw sotto win � per avere lo *stesso* codice compilabile e funzionante su linux e windows, quindi mettere un path hard-coded � un errore quantomeno di concetto.
[..]
 
Infatti, proprio questo il punto. Quello che cercavo di dire prima �
che per esempio un codice grezzo come questo non produce alcun errore,
il path � accessibile senza problemi su entrambi Unix e Windows, e su
entrambi MinGW e CL, basta creare una cartella chiamata "folder" e un
file "filename.txt" all'interno, nella stessa directory del sorgente:
 
#define _CRT_SECURE_NO_WARNINGS
 
#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
     FILE *fp;
     char path[] = "folder/filename.txt";
 
     fp = fopen(path, "r");
 
     if ( !fp ) {
         fprintf(stderr, "Non posso aprire il file %s\n", path);
         exit(EXIT_FAILURE);
     }
 
     return 0;
}
 
 
-- 
Vincenzo Mercuri

 
 
Il codice che hai scritto ovviamente funziona, ma ad esempio nei due casi che scrivo sotto non riuscirebbe mai ad aprire il file:
- L'applicativo è lanciato con una diversa cwd (possibile sia su linux che su windows, da shell, bash o batch che sia)
- Su unix potresti avere permessi tale per cui una cartella è accessibile in esecuzione ma non in lettura.
Questi sono giusto i primi due casi che mi sovvengono, ma di sicuro che ne sono molti altri più o meno esotici.
 
IMO l'unica, come ho detto, è prendere il file da argv o da un cfg (il cui path è ovviamente passato in argv :) ), in maniera che l'applicativo funzioni per come dice l'utente, al netto delle possibili infinite installazioni/configurazioni in cui potrebbe essere utilizzato.
 
Ciao!

 IMO l'unica, come ho detto, � prendere il file da argv o da un cfg (il cui path � ovviamente passato in argv :) ), in maniera che l'applicativo funzioni per come dice l'utente, al netto delle possibili infinite installazioni/configurazioni in cui potrebbe essere utilizzato.
 
Si questo sarebbe ancora meglio, ripeto, dipende dall'uso che ne far�.
Ma anche nel caso della funzione che ha postato ci sono forse troppe
condizioni date per scontate, e un programma che effettua pochi controlli
� facile che fallisca. Per esempio, se nella sua lista di giochi compare
solo una stringa tipo "NeedForSpeed", senza altre linee, quindi senza
newline, il suo programma produrra la stringa "NeedForSpee" e chiaramente
quando andr� a vedere se quel gioco esiste, magari confrontandola alla
stringa corretta il programma dir� che il gioco non c'�.
 
 
-- 
Vincenzo Mercuri


Non ï¿œ detto, il segmentation fault ï¿œ  implementation defined
Semmai il compilatore dovrebbe dare un warning perchï¿œ le stringhe sono 
tipo const char* e strcpy come primo parametro vuole un char*
 
In gcc  i warning vengono abilitati con l' opzione -Wall
Se il nostro amico non ha abilitato i warning in compilazione
ecco che non se ne ï¿œ accorto
 


 
Credo che l'OP non sia l'unico a non aver abilitato i warnings :)
E aggiungo che non bastano "-Wall" e "-Wextra" per leggere qualcosa
in riferimento al potenziale UB. Succede solo abilitando 
"-Wwrite-strings".
Almeno su gcc-4.7 e gcc-4.6.3 ï¿œ cosï¿œ.
 
-- 
Vincenzo Mercuri


 
Ho fatto una prova, ï¿œ vero (gcc 4.6.3)
Essendo piu abituato al C++ mi sembra strano che il C non dia un warning 
con -Wall per eliminare il qualificatore const
 
 
 
 
 

 }
 
 
Per la cronaca, se compilo questo codice con gcc ho questo:
 
$ make boom.o
cc -Werror -Wall -Wextra -Wold-style-definition -Wmissing-declarations -
Wredundant-decls -Wmissing-noreturn -Wshadow -Wpointer-arith -Wcast-align 
-Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-
enum -Wswitch-default -Winit-self -Wmissing-include-dirs -Wundef -
Waggregate-return -Wmissing-format-attribute -Wnested-externs -std=c99 -
pedantic   -c -o boom.o boom.c
boom.c:1:8: error: no previous declaration for ‘default_game’ [-
Werror=missing-declarations]
boom.c: In function ‘default_game’:
boom.c:1:8: error: old-style function definition [-Werror=old-style-
definition]
boom.c:2:2: error: unknown type name ‘FILE’
boom.c:6:2: error: implicit declaration of function ‘strcpy’ [-
Werror=implicit-function-declaration]
boom.c:6:2: error: incompatible implicit declaration of built-in function 
‘strcpy’ [-Werror]
boom.c:8:2: error: implicit declaration of function ‘fopen’ [-
Werror=implicit-function-declaration]
boom.c:8:2: error: nested extern declaration of ‘fopen’ [-Werror=nested-
externs]
boom.c:8:10: error: assignment makes pointer from integer without a cast 
[-Werror]
boom.c:8:34: error: ‘NULL’ undeclared (first use in this function)
boom.c:8:34: note: each undeclared identifier is reported only once for 
each function it appears in
boom.c:9:3: error: implicit declaration of function ‘fprintf’ [-
Werror=implicit-function-declaration]
boom.c:9:3: error: incompatible implicit declaration of built-in function 
‘fprintf’ [-Werror]
boom.c:9:11: error: ‘stderr’ undeclared (first use in this function)
boom.c:13:2: error: implicit declaration of function ‘fgets’ [-
Werror=implicit-function-declaration]
boom.c:13:2: error: nested extern declaration of ‘fgets’ [-Werror=nested-
externs]
boom.c:14:3: error: incompatible implicit declaration of built-in 
function ‘fprintf’ [-Werror]
boom.c:18:2: error: implicit declaration of function ‘fclose’ [-
Werror=implicit-function-declaration]
boom.c:18:2: error: nested extern declaration of ‘fclose’ [-Werror=nested-
externs]
boom.c:19:2: error: implicit declaration of function ‘strlen’ [-
Werror=implicit-function-declaration]
boom.c:19:7: error: incompatible implicit declaration of built-in 
function ‘strlen’ [-Werror]
boom.c:20:2: error: implicit declaration of function ‘strcat’ [-
Werror=implicit-function-declaration]
boom.c:20:2: error: incompatible implicit declaration of built-in 
function ‘strcat’ [-Werror]
boom.c:20:2: error: passing argument 1 of ‘strcat’ discards ‘const’ 
qualifier from pointer target type [-Werror]
boom.c:20:2: note: expected ‘char *’ but argument is of type ‘const char 
*’
cc1: all warnings being treated as errors
make: *** [boom.o] Errore 1
$ 
 
 
 
 
-- 
By ZeD


[taglio l'infinita serie di errori]
 
Adesso non esageriamo.. questo succede se compili la funzione in un
sorgente senza includere headers e senza main.. se aggiungi
 
#include <stdio.h>
#include <string.h>
 
e un semplice main l'output di gcc con le stesse opzioni è:
 
--------
boom.c:8:1: error: no previous declaration for ‘default_game’
             [-Werror=missing-declarations]
boom.c: In function ‘default_game’:
boom.c:8:1: error: old-style function definition 
[-Werror=old-style-definition]
boom.c:25:2: error: passing argument 1 of ‘strcat’ discards ‘const’ 
qualifier
              from pointer target type [-Werror]
In file included from boom.c:2:0:
/usr/include/string.h:136:14: note: expected ‘char * restrict’ but argument
is of type ‘const char *’
cc1: all warnings being treated as errors
--------
 
dove appunto come dice l'ultima linea tutti i warnings sono trattati come
errori.. questa opzione è un po' drastica.. personalmente preferisco che
la compilazione si fermi al primo errore (vero) piuttosto, perchè in genere
il primo causa la cascata degli errori successivi (opzione 
"-Wfatal-errors").
 
Il *warning* (più) rilevante è:
 
--------
boom.c: In function ‘default_game’:
boom.c:25:2: warning: passing argument 1 of ‘strcat’ discards ‘const’
              qualifier from pointer target type [enabled by default]
In file included from boom.c:2:0:
/usr/include/string.h:136:14: note: expected ‘char * restrict’ but
argument is of type ‘const char *’
--------
-- 
Vincenzo Mercuri

 
 
Minchia! :O
E io che pensavo di essere paranoico :D
Ciao!
 
P.S. Ma riesci a compilare qualcosa con queste CFLAGS? Non le ho mai provate, ma ad occhio non credo di conoscere alcun codice "famoso" che lo passerebbe..

con -Wall per eliminare il qualificatore const
 
Un puntatore costante e un puntatore a costante sono due cose diverse.
Inoltre, il left value di una stringa 'litteral' come "abcd" NON E`
const char *, ma E` static char *, questo e` il motivo per cui il
compilatore non si lamenta quando l'OP ha fatto cose del tipo:
 
strcat("games/", line);
 
 
 
Esempi (provate a compilare):
 
  char *const x="a";
  char const *y="b";
  const char *z="c";
  char *t="d";
  strcat(x,"k");
  strcat(y,"k");
  strcat(z,"k");
  strcat(t,"k");
-- 
andrea - ar italy, com

 lo passerebbe..
 
 
Veramente la maggiorparte dei flags li ho presi dal blog di uno 
sviluppatore gnome (non ricordo assolutamente il sito, il nome dello 
sviluppatore e su cosa lavorava)
 
e, -pedantic a parte, non mi fiderei a usare programmi che non possono 
essere compilati senza rimuovere questi controlli...
 
-- 
By ZeD

 compilatore non si lamenta
 
direi uno static const char *
(anche perché i literal tendenzialmente andrebbero nella parte read-only dell'eseguibile finale, ma YMMV)
Ciao!


Diciamo che in molti usano tante CFLAGS nel proprio Makefile, io pure
sono uno di quelli che come un pazzo si è andato a vedere tutti i
possibili warnings di gcc e li ho inseriti in un Makefile che uso come
template che poi modifico all'occorrenza. La maggior parte dei progetti
open source producono un sacco di warnings quando li vai a compilare.
C'è però una, fra tutte quelle opzioni, che in pratica non permetterebbe
di compilare la maggior parte di tutti questi programmi: "-Werror".
Con questa in pratica tutti i warnings diventano errori, quindi anche
un semplice programma che ha solo una funzione oltre al main, definita
prima del main stesso, non si puo' compilare.
 
-- 
Vincenzo Mercuri


#include <stdio.h>
static void a(void) { printf("hello!\n"); }
int main(void) { a(); return 0; }
 
Questo compila tranquillamente... o non ho capito cosa volevi dire?
Ciao!


E sarà proprio lo "static" che hai aggiunto che non fa lamentare gcc,
visto che deve produrre solo linkage interno, in questo caso. Ma se levi
lo static e compili con le opzioni che dicevamo prima (in realtà ti bastano
solo "-Werror" e "-Wmissing-declarations") allora non riuscirai a compilare.
 
-- 
Vincenzo Mercuri


 
No, invece è proprio 'const char *'.
 
-- 
Vincenzo Mercuri

No, invece è proprio 'const char *'.
 
Ho 'ripassato' il K&R per vedere la definizione, ho visto che "abc" e`
una costante stringa, quindi il suo puntatore dovrebbe essere un
puntatore ad una costante stringa.
 
Il puntatore in se stesso purtroppo non e` const. La cosa e` sottile,
perche' l'indirizzo di "abc" e` solo un puntatore ad una stringa, e la
stringa e` costante. In pratica, quando passi "abc" ad una funzione
che chiede un char *, l'informazione che la stringa e` costante si
perde, e strcat("abc","d") non genera segnalazioni dal compilatore.
 
Deve quindi essere il programmatore ad attribuire al puntatore il suo
corretto tipo, che come hai detto, nel nostro caso e` const char *,
ovvero una chiamata fatta come strcat((const char*)"abc","d") genera
il warning del compilatore.



Si, il compilatore fa delle opportune "promozioni" o "degradazioni"
per accordare i tipi degli argomenti passati e i parametri formali delle
funzioni. Quello che tu dici "deve quindi essere il programmatore ad
attribuire al puntatore il suo corretto tipo" è una cosa sacrosanta,
che bisogna sempre accertarsi di fare. Nello specifico però, indipenden-
temente dal qualificatore che diamo all'argomento, l'oggetto in sè,
ovvero lo string literal, è non modificabile per definizione. Significa
che il compilatore è libero di collocarlo in una zona della memoria a
sola lettura. Inoltre, tentare di modificare uno string literal genera
"undefined behavior". E' molto facile in C ritrovarsi un codice ormai
"broken", e riuscire a compilarlo senza la minima segnalazione.
L'obbligo di una segnalazione dipende da se la violazione è fatta ad
un "constraint" o no dello Standard. In questo caso non ci troviamo in
uno di questi "constraint" quindi il compilatore è libero di non produrre
warnings, anche quando si tratta di UB, ovvero che ormai il programma
è da buttare.
 
-- 
Vincenzo Mercuri

 a compilare.
 
 
???
 
l'unica modifica che ho introdotto è stata la dichiarazione (oltre a non 
usare lo static, ovvio)
 
$ cat noncompila.c
#include <stdio.h>
 
void a(void);
 
void a(void) { printf("hello!\n"); }
int main(void) { a(); return 0; }
$ make noncompila
cc -Werror -Wall -Wextra -Wold-style-definition -Wmissing-declarations -
Wredundant-decls -Wmissing-noreturn -Wshadow -Wpointer-arith -Wcast-align 
-Wwrite-strings -Winline -Wformat-nonliteral -Wformat-security -Wswitch-
enum -Wswitch-default -Winit-self -Wmissing-include-dirs -Wundef -
Waggregate-return -Wmissing-format-attribute -Wnested-externs -std=c99 -
pedantic    noncompila.c   -o noncompila
$ ./noncompila 
hello!
$
 
 
 
-- 
By ZeD

 $ cat noncompila.c
 
 
simpatico.. ma se dico che A non compila, non puoi rispondermi dicendo
che A + B compila..
 
 
-- 
Vincenzo Mercuri

         strcat("games/", line);
 
Spero sia solo un errore di copia ed incolla, ma questa istruzione
e' sbagliata: stai concatenando chissadove il contenuto di line
("games/" e' un puntatore ad una stringa costante, non ad un array).
 
HTH
 
C:\>iao Angelo