Newsgroup: it.comp.lang.c
Titolo: Che errore e'?

Sto cercando di compilare questo programma ma il linker mi da un
errore strano... Sto usando Dev-c++ 4.9.7.0 (l'ultima versione
comunque)
L'errore che mi da il linker e' questo:
 
[Linker error] undefined reference to `__gxx_personality_v0'
E qui c'e' invece il listato del programma. Non capisco proprio da
dove possa venire quell'errore... Grazie degli aiuti.
<CODE>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILENAME "input.txt"
/* Nuova struttura per memorizzare ogni parola insieme alla linea a
cui 
appartiene ogni parola */
typedef struct s_word {
	char *sword;
	struct s_word *next;
	int line;
} word;
word *createWord(char *, int); /* Crea un elemento della lista con le
parole */
word *insertTail(word *, word *); /* Inserisce in coda alla lista */
word *getWord(FILE *, int *); /* Costruisce la lista */
void printLines(int, word *); /* stampa */
int main() {
	int n, nlines = 1, startline;
	FILE *fPtr = NULL;
	word *top = NULL;
	puts("Inserisci il numero n come ultime righe che vuoi
stampare del file");
	scanf("%d", &n);
	if ((fPtr = fopen(FILENAME,"r")) != NULL) {
		top = getWord(fPtr, &nlines);
		fclose(fPtr);
		startline = nlines-n+1;   /* Calcola il punto in cui
deve partire
		                            per stampare la lista */
		printLines(startline, top);
	} else printf("File inesistente");
	return 0;
}
word *createWord(char *s, int nline) {
	word *elem;
 
	/* Se non riesce ad allocare lo spazio necessario ritornare
NULL
	 Se riesce ad allocare lo spazio allora assegnare al campo
sword il 
     valore della stringa da inserire, inizializzare next a NULL e
impostare
     line con il rispettivo valore passato e quindi ritornare
l'elemento*/
	if (((elem = (word *)malloc(sizeof(word))) != NULL) &&
	((elem->sword = (char *)malloc(sizeof(char)*(strlen(s)+1))) !=
NULL)) {
		elem->sword = s;
		elem->next = NULL;
		elem->line = nline;
		return elem;
	}
	return NULL;
}
word *insertTail(word *tail, word *elem) {
	tail->next = elem;
	tail = tail->next;
	return tail;
}
word *getWord(FILE *fPtr, int *nline) {
    char s[20], car;
    word *elem, *top, *tail;
 
    /* Esegui per la prima volta l'acquisizione dalla lista per
ottenere
    la testa */
    fscanf(fPtr, "%s%c", s, &car);
    elem = createWord(s, *nline);
    top = elem;
    tail = elem;
    insertTail(tail, elem);
 
    /* Se il carattere acquisito dopo la stringa e' un \n incrementare
di 1
    il contatore delle linee */
    while(!feof(fPtr) && s) {
        if (car == '\n') (*nline)++;
        fscanf(fPtr, "%s%c", s, &car);
        elem = createWord(s, *nline);
        tail = elem;
        insertTail(tail, elem);
    } 
    return top;
}
void printLines(int startline, word *top) {
  /* se startline dovesse essere negativo sono state richieste troppe
linee */
    if (startline > 0) {
        while (top) {
        /* scorri tutta la lista e stampa solo gli elementi il cui
campo
        line e' uguale al campo startline, in caso startline sia
minore del
        campo line dell'elemento incrementare di 1 startline e andare
a capo 
        stampando l'elemento */
                if (startline == top->line)
                                printf("%s ", top->sword);
                else if (startline < top->line) {
                                printf("\n%s ", top->sword);
                                startline++;
                }
                top = top->next;
        }
    } else printf("Il file selezionato ha meno righe di quelle
richieste");
}
</CODE>
-- 
try: troll = "Brain"
except TypeError, data: 
   troll.plonk()
Co-Responsabile Hardware Information & Technology 
http://hit.edengames.net

[Linker error] undefined reference to `__gxx_personality_v0'
Capito da cosa e' dovuto... avevo l'estensione maiuscola quindi lo considerava
C++... Modificando l'estensione in .c tutto va a posto. Pero' non riesco a farlo
fungere ora mi do da fare col debugger... Se qualcuno trova l'errore prima di me
me lo dice per favore? grazie 1000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FILENAME "input.txt"
/* Nuova struttura per memorizzare ogni parola insieme alla linea a cui 
appartiene ogni parola */
typedef struct s_word {
	char *sword;
	struct s_word *next;
	int line;
} word;
word *createWord(char *, int); /* Crea un elemento della lista con le parole */
word *insertTail(word *, word *); /* Inserisce in coda alla lista */
word *getWord(FILE *, int *); /* Costruisce la lista */
void printLines(int, word *); /* stampa */
 
int main() {
	int n, nlines = 1, startline;
	FILE *fPtr = NULL;
	word *top = NULL;
	printf("Inserisci il numero n come ultime righe che vuoi stampare del





    tail = insertTail(tail, elem);
 
    /* Se il carattere acquisito dopo la stringa e' un \n incrementare di 1
    il contatore delle linee */
    while(!feof(fPtr) && s) {
        if (car == '\n') (*nline)++;
        fscanf(fPtr, "%s%c", s, &car);
        elem = createWord(s, *nline);
        tail = insertTail(tail, elem);
    } 
    return top;
}
void printLines(int startline, word *top) {
 
  /* se startline dovesse essere negativo sono state richieste troppe linee */
    if (startline > 0) {
        while (top) {
        /* scorri tutta la lista e stampa solo gli elementi il cui campo
        line e' uguale al campo startline, in caso startline sia minore del
        campo line dell'elemento incrementare di 1 startline e andare a capo 
        stampando l'elemento */
                if (startline == top->line)
                                printf("%s ", top->sword);
                else if (startline < top->line) {
                                printf("\n%s ", top->sword);
                                startline++;
                }
                top = top->next;
        }
    } else printf("Il file selezionato ha meno righe di quelle richieste");
}


}
Questa funzione e' sbagliata e va fatta cosi': 
word *insertTail(word *tail, word *elem) {
	tail->next = elem;
   	tail = elem;
    	return tail;
}
Ora riesco ad arrivare alla fase di stampa ma a quella fase ottengo caratteri
illeggibili...


 } word;
Mi spieghi cosa serve "s_word" ?
quando usi il typedef il nome della struttura dovrebbe essere solo dopo la
chiusura della graffa (dove tu hai messo word)?

 }
K
-- 
Home: 
http://kronoz.cjb.net
La differenza fra l'intelligenza e la stupidita`?
All'intelligenza c'e` un limite.

 }
Adesso ti  basta inserire  la funzione  in un loop  che ne  controlla il
valore  di ritorno:  se  e` NULL  hai finito  di  leggere. Ogni riga  la
inserisci nella lista,  tenendo il conto di quante  righe leggi. Detto N
il numero di righe lette ed M  il numero di righe da mostrare, alla fine
dovrai solo scorre la lista, saltando i primi N - M elementi.
Una nota sull'inserimento in coda: io farei cosi`:
void add_tail(list_t **head, list_t **tail, list_t *l) {
        if (*head == NULL) {
                *head = *tail = l;
                return;
        }
 
        (*tail)->next = l;
        *tail = l;
}
list_t *leggi_tutto(file) {
        list_t *head = NULL, *tail = NULL, *p;
        ...
        p = getline(file);
        add_tail(&head, &tail, p);
        ....
        return head;
}
In questo modo  sposti la logica di gestione della  lista nel posto dove
deve stare (nelle funzioni di manipolazione della lista).
Un  ultima cosa:  questo  metodo puo`  essere estremamente  dispendioso.
Supponi di dover leggere una file di 1000 righe (numeri che fanno girare
la testa!)  e di doverne  stampare 10. Avrai allocato 990  strutture per
nulla  (90% dello  spazio  allocato e`  sprecato). Sarebbe meglio  usare
un  buffer  circolare,  con  dimensione  pari  al  numero  di  righe  da
visualizzare. Lascio al lettore l'implementazione (suvvia, fai ingneria!
non spaventerai per cosi` poco ;)).
[1] In linea di massima, diciamo in plain x86.
ciao
Kronos
PS: createWord non l'ho testata, ma dovrebbe andare
-- 
Home: 
http://kronoz.cjb.net
Il dottore mi ha detto di smettere di fare cene intime per quattro.
A meno che non ci siamo altre tre persone.

PS: createWord non l'ho testata, ma dovrebbe andare
Ti ringrazio veramente tanto. Ora mi ci vorranno un po' di ore (sicuramente meno
di quelle che ho dedicato al debug di questa cacchio di applicazione) per capire
tutte le modifiche che mi hai fatto...
Purtroppo pero' alcune modifiche mi tocca scartarle e ti spiego il perche'... Il
testo del problema dice che devo:
*leggere dal file: input.txt
*caricare in una struttura appropriata il contenuto del file sapendo che ogni
*parola e' lunga al massimo 20 caratteri (so che avrei dovuto mettere 21 nel
buffer ma tanto avevo un testo che sicuramente aveva parole piu' corte, non
sapendo quanto sara' lunga la linea mi e' difficile usare la fgets...)
*stampare a video le ultime n righe
Ecco perche' utilizzo un metodo cosi' dispendioso... Fosse stato diverso, avrei
semplicemente creato, come hai detto tu, la struttura e dopo aver fatto 2
iterazioni nel file mi sarei fermato subito dopo il \n che delimita la prima
riga da cui devo stampare. Da li' inizio a caricare nella struttura e poi
stampo. A dir la verita' pero' il metodo piu' bello sarebbe quello di usare un
solo elemento della struttura senza puntatore a next e balle varie e stampare
ogni parola del file che ci passa dentro, pero' dubito che mi venga accettato...
In realta' non sono neanche obbligato a fare questo esercizio perche' ormai
l'esame di lab di info1 l'ho gia' dato e ho preso il massimo (l'hanno regalato
un po' a tutti diciamo).
Mi sa che la colpa di questo programma non riuscito e' proprio una giornata
storta... Ad ogni modo non conoscevo tutte quelle funzioni di C... non e' che lo
insegnino proprio bene all'UNI, se voglio impararlo mi sa che mi conviene fare
da solo...
Per quanto riguarda il segmentation fault... anche io mi sono accorto di quello,
ho deciso di riscriverlo e ora mi si blocca tutto quando eseguo questo: 
oldtail->next = newTail;   /* su questa linea da seg fault */
return newTail;
se vuoi ti riposto il codice, magari in mail privata, ma non vorrei disturbarti
troppo.
Per finire... 
Tra i tuoi listati c'e' anche questa riga:
size_t line_len = 0, len;
che tipo e' size_t?
PS: Mi ha detto un amico comune che fai anche tu il politecnico di milano :),
magari ogni tanto ci si incotra se vuoi  eh eh.


chiusura della graffa (dove tu hai messo word)?
Perche' con typedef dico che assegno un sinonimo alla struttura pero' il nome
della struttura lo si mette comunque per chiarezza e per fare in modo di poterla
richiamare all'interno della struttura stessa prima di averle dato il sinonimo.
Se noti al'interno della struct c'e' un dato di tipo: struct s_word *


E` la stessa cosa, la funzione e` corretta ma funziona per caso...
No no... non funziona proprio purtroppo :(((
Perche' funziona per caso?


 milano :), magari ogni tanto ci si incotra se vuoi  eh eh.
Si puo` fare, magari dopo gli esami.
Kronos
-- 
Home: 
http://kronoz.cjb.net
Runtime error 6D at f000:a12f : user incompetente

 Perche' funziona per caso?
Beh,  la  versione  alternativa  che  hai  postato  fa  la  stessa  cosa
dell'altra. Quindi se una funziona e l'altra no e` un caso, la fonte dei
problemi e` da qualche altra parte.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Il piu` bel momento dell'amore e` quando ci si illude che duri per 
sempre; il piu` brutto, quando ci si accorge che dura da troppo.

Si puo` fare, magari dopo gli esami.
oki :)
Ora ti scrivo il nuovo codice con la insertTail scritta da te (che pero' avevo
gia' fatto uguale io senza sortire effetti sigh... ahime..) Ancora non ho messo
le tue modifiche perche' preferisco capire dove sbaglio io, il programma in se
e' un fine secondario...
Il codice ora e' piu' pulito e molto meno commentato nonche' meno criptico.
Ora non mi da segmentation fault... Semplicemente non stampa nulla.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILENAME "input.txt"
typedef struct s_listNode {
    char *data;
    int line;
    struct s_listNode *next;
} listNode;
listNode *initList(FILE *, int *nlines);
listNode *initElem(char *, int);
void insertTail(listNode **, listNode **, listNode *);
void printLines(int, listNode *);
int main() {
    int n, start, nlines = 1;
    FILE *fPtr;
    listNode *top;
 
    printf("Inserisci quante delle ultime linee devo stampare\n");
    scanf("%d", &n);
    fPtr = fopen(FILENAME, "r");
 
    if (fPtr != NULL) {
        top = initList(fPtr, &nlines);
        fclose(fPtr);
        start = nlines-n+1;
        printLines(start, top);
    } else printf("Il file e' inesistente");
    return 0;
}
listNode *initList(FILE *fPtr, int *nlines) {
    listNode *elem, *top, *currelem, *last;
    char s[20], endw;
 
    fscanf(fPtr, "%s", s);
    fscanf(fPtr, "%c", &endw);
    elem = initElem(s, *nlines);
    if (endw == '\n') (*nlines)++;
    last = elem;
    top = elem;
 
    do {
        fscanf(fPtr, "%s", s);
        fscanf(fPtr, "%c", &endw);
        elem = initElem(s, *nlines);
        if (endw == '\n') (*nlines)++;
        insertTail(&top, &last, elem);
    } while (endw != EOF);
    return top;
}    
listNode *initElem(char *currword, int currline) {
    listNode *newElem;
    char *cPtr;
    newElem = (listNode *)malloc(sizeof(listNode));
    cPtr = (char *)malloc(sizeof(char)*(strlen(currword)+1));
    if (newElem != NULL && cPtr != NULL) {
        cPtr = currword;
        newElem->next = NULL;
        newElem->data = cPtr;
        newElem->line = currline;
    } else printf("Memoria insufficente");
    return newElem;
}
void insertTail(listNode **head, listNode **tail, listNode *newTail) {
        if (*head == NULL) {
                *head = *tail = newTail;
                return;
        }
 
        (*tail)->next = newTail;
        *tail = newTail;
}
void printLines(int start, listNode *currElem) {
    while (currElem) {
        if (currElem->line == start)
                printf("%s ", currElem->data);
        else if (currElem->line > start) {
                printf("\n%s ", currElem->data);
                start++;
        }
        currElem = currElem->next;


 }
Alla fine non liberi la memoria che hai allocato:
void cleanup(listNode *head) {
        listNode *p;
        p = head;
        while(p) {
                free(p->data);
                free(p);
                p = head->next;
                head = p;
        }
}
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Se non puoi convincerli, confondili.

         strcpy(cPtr, currword);
Supponi benissimo. Immagino di poter usare memcpy invece di strcpy giusto?
Oppure c'e' qualche problema per quanto riguarda la grandezza di currword e di
cPtr che potrebbero essere in effetti differenti?
Grazie 10000 per l'aiuto. Ho capito gli errori.



wrote:
Finalmente funziona. Grazie 1000 Kronos, sei appena cresciuto di 2000 punti
nella mia personale ranking list :).
In pratica sei in testa da solo eh eh.


 currword e di cPtr che potrebbero essere in effetti differenti?
In questo  caso il  problema non  sussiste, cPtr  e` stato  allocato per
contenere stringa contenuta in currword. In generale strcpy e strcat non
sono affatto sicure perche` non  controllano la dimensione del buffer di
destinazione. A meno  che non sia evidente  l'impossibilita` di overflow
(ie.  so  che la  lunghezza  massima  e`  fissata  by design  oppure  ho
controllato la lunghezza  della sorgente ed ho  allocato di conseguenza,
ecc) e` meglio usare strncpy() e strncat().
Sempre per questa ragione la scanf come la usi tu non e` sicura, sarebbe
meglio usare  come stringa di conversione  questa: "%19s", cosi` vengono
letti al massimo 19 caratteri (il ventesimo serve per il terminatore).
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Windows NT crashed.
I'm the Blue Screen of Death.
No one hears your screams.

Togli i cast.
Su qua non sono convito.
Perche' dovrei togliere i cast? So che magari e' piu' veloce o cose simili pero'
e' indubbiamente meno chiaro e puo' indurre in errore, tanto piu' che in C++ una
cosa cosi' non si puo' fare a meno di (appunto) un cast esplicito.
Ne stavamo discutendo proprio in aula di questo tra noi studenti.


letti al massimo 19 caratteri (il ventesimo serve per il terminatore).
Ma quante belle cose che si scoprono... 
Un appunto pero' vorrei farlo al C, e piu' in generale all'universita'... Ma
possibile che e' piu' il tempo che si passa ad evitare le beghe del linguaggio
che il resto? mi piacerebbe sapere come mai nello standard C89 sono state
incluse 3 o 4 istruzioni di print e 3 o 4 istruzioni di input. Una diversa
dall'altra e una piu' pericolosa dell'altra...


 Ne stavamo discutendo proprio in aula di questo tra noi studenti.
Deve essere una tradizione del poli ;)
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"Su cio` di cui non si puo` parlare e` bene tacere".
 Ludwig Wittgenstein

Deve essere una tradizione del poli ;)
Lo facevate anche voi? eh eh eh allora potrebbe veramente essere tradizione.


 parametri e ritorni un int.
Ma non č permesso in C99... l'int implicito non fa piů parte dello
standard... per quanto in giro i compilatori che supportano quest'ultimo
standard sono veramente pochi.
Saluti
R.I.
P.s.: non vuole essere una critica... č solo una precisazione in piů. :)