Frage

Ich habe einige ANSI-C-Code, den ich auf meinem Mac entwickelt, aber als ich versuchte es auf unserer Schule Linux-Server laufen bekomme ich eine segfault.

Die spezifische Zeile, die mir Probleme verursacht ist ein getc aus einer Datei Zeigern.

Die Datei existiert.

Hier ist die Methode in Frage:

// inits lists with all data in fp file pointer
// returns # of lines read
int init_intlists(FILE *fp, INTLIST *lists[]) {
    int c, ctr;

    ctr = 0;

    // need to use a linked list to store current number
    // for non 1-digit numbers...
    INTLIST *cur_num = NULL;
    int cur_num_len = 0;
    while ((c = getc(fp)) != EOF){
        if(c != '\n' && c != ' '){
            c = c - 48;
            if(cur_num == NULL){
                cur_num = init_intlist(c);
            } else {
                list_append(cur_num, &c);
            }
            cur_num_len++;
        } else if(c == ' ' || c == '\n'){
            // we reached a space, meaning we finished
            // reading a contiguous block of digits
            // now we need to figure out what we actually read...
            int num = 0;
            INTLIST *ptr;
            ptr = cur_num;
            while(cur_num_len != 0){
                cur_num_len--;
                num += pow(10, cur_num_len) * ptr->datum;
                ptr = ptr->next;
            }    

            if(lists[ctr] == NULL){
                // init new list
                lists[ctr] = init_intlist(num);
            } else {
                // append to existing
                list_append(lists[ctr], &num);
            }

            // clear cur_num to read the next one
            cur_num_len = 0;
            list_delete(cur_num);
            cur_num = NULL;
        }

        if(c == '\n') {
            // newline reached - increment to fill in next list
            ctr++;
        }
    }    

    return ctr;
}

Der Aufruf von init_intlists, die die segfault verursacht beginnt so:

    FILE *fp = (FILE *)malloc(sizeof(FILE));
    FILE *base_vector_fp = (FILE *)malloc(sizeof(FILE));

    parse_args(argc, argv, fp, base_vector_fp);

    if(fp == NULL || base_vector_fp == NULL){
        fprintf(stderr, "Critical error, could not load input files\n");
        return 1;
    }

    INTLIST *lines[MAX_LINES] = {};
    INTLIST *base_vectors[MAX_LINES] = {};

    int lines_read = init_intlists(fp, lines);

und parse_args wie folgt aussieht:

FILE *load_file(char *filename) {
    FILE *fp;

    fp = fopen(filename, "r");

    if(fp == NULL){
        fprintf(stderr, "File %s does not seem to exist.\n", filename);
        return NULL;
    }

    // XXX Does this memory leak?
    // fp is never fclose()'d
    return fp;
}

void parse_args(int argc, char *argv[], FILE *fp, FILE *base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        free(fp);
        free(base_vector_fp);
        fp = NULL;
        base_vector_fp = NULL;
        exit(1);
    }

    char *filename = argv[1];
    *fp = *load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = *load_file(base_vector_filename);
}

Also, wenn ich den Aufruf auf meinem Mac versuche, funktioniert es völlig in Ordnung, und es liest die Datei in, wie es sollte, und ich bin in der Lage darauf zu arbeiten und die richtigen Antworten für meine Aufgabe erhalten.

Allerdings, wenn ich es auf Linux versuchen laufen, erhalte ich eine segfault wenn er versucht, in der getc Unterprogramm init_intlists.

Ich habe festgestellt, dass die Dateien, die ich für die Eingabe liefern existieren und die Welt lesbar (umask 755). Ich habe versucht, sowohl absolut als auch relativ Pfade. Ich habe auch mehrere verschiedene Eingabedateien versucht.

Ich habe versucht, gcc 4.2 und gcc 3.4 auf dem Linux-Server verwenden und erzeugt eine ausführbare Binärdatei, die eine segfault mit beliebigen Eingabedateien verursachen werden.

Hier ist die Versionsinformationen zwischen den beiden unterschiedlichen Versionen von gcc:

Mac OS X:

me@dinosaurhunter ~> gcc -v
Using built-in specs.
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5465~16/src/configure --disable-checking -enable-werror --prefix=/usr --mandir=/share/man --enable-languages=c,objc,c++,obj-c++ --program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ --with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib --build=i686-apple-darwin9 --with-arch=apple --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5465)

Linux:

me@janus:~/assignment_1$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.2.4 (Ubuntu 4.2.4-1ubuntu4)

Ich rufe den Compiler die gleiche Makefile sowohl auf OS X und Linux verwenden. Das Ende Aufruf von gcc aufwickelt, die wie folgt aus:

gcc  -Wall -g  -c src/common_file_io.c src/main.c src/intlist.c
gcc  -Wall -g  common_file_io.o main.o intlist.o -lreadline -lm  -o bin/myprogram 

Irgendwelche Ideen? Ich bin zu einem vollständigen Verlust, wie mein Professor ist.

War es hilfreich?

Lösung

Die anderen Antworten sind richtig - behandeln eine FILE * als opaken Griff, die Sie kopieren herum, versuchen Sie nicht, den Inhalt zu kopieren. Insbesondere können Sie Ihren Code wie folgt festzusetzen:

den Anruf löschen malloc wenn Sie fp und base_vector_fp initialisieren:

FILE *fp = NULL;
FILE *base_vector_fp = NULL;

Führen Sie einen Zeiger auf diese Zeiger auf parse_args, so dass sie die Zeigerwerte aktualisieren können:

parse_args(argc, argv, &fp, &base_vector_fp);

Und parse_args ändern Sie die FILE * Objekte in dem Anrufer zu aktualisieren, anstatt zu versuchen, und arbeiten mit den FILE Objekte:

void parse_args(int argc, char *argv[], FILE **fp, FILE **base_vector_fp) {
    char *prog = argv[0];
    if (argc != 3){
        fprintf(stderr, "Wrong number of arguments supplied.\nUse: %s <data_filename>     <base_vector_filename>\n", prog);
        exit(1);
    }

    char *filename = argv[1];
    *fp = load_file(filename);

    char *base_vector_filename = argv[2];
    *base_vector_fp = load_file(base_vector_filename);
}

Andere Tipps

Sie sollen nicht Ihre eigenen FILE Objekte zuzuordnen, sie sind in der Regel undurchsichtige Objekte von libc verwaltet. free() sie auch nicht, das ist, durch fclose(3) getan. Obwohl theoretisch könnten Sie eine zugewiesen und eine Struktur assign tun, und es haben arbeiten, wäre es besser, nicht um die Bibliothek zu kämpfen und gleich um die Referenz zu übergeben, wie alle anderen auch. Die Bibliothek kann oder nicht Zustand halten, die nicht in der Dateistruktur ist, und im Innern spähen oder die gesamte Struktur dereferencing ist ausreichend schlechter Stil, dass der implementors eigentlich davon ausgehen, dass Sie es nie tun.

Wenn Sie eine FILE * zurückkehren Sie es entweder als Rückzeigerwert verwenden können, wie Sie in einem Fall haben oder einen Doppel indirekten Zeiger benutzen. FILE *fp; f(&fp);

Hmm, ich habe gerade bemerkt, dass C99 gibt tatsächlich diese in 7.19.13 :

  

6 Die Adresse des FILE-Objekt verwendet   zu steuern, kann ein Strom sein,   von Bedeutung; eine Kopie eines FILE-Objekt   muss nicht anstelle des Aufschlags   Original.

Damit sie Mitteilung dienen, dass ein FILE * wirklich nur ein Magic Cookie sein kann.

Sie sollten das Ergebnis offopen()into aFILEobject nicht kopieren, und in der Tat, sollten Sie überhaupt notmallocaFILEobject. Sie sollten immer thefopen()control Objekt useFILEto zuordnen.

TheFILEobject ist undurchsichtig, und wahrlich, es enthält viel, die Sterblichen verborgen ist. Die Implementierung ist frei, alle möglichen Dinge in sie zu setzen, wie Zeiger auf andere Kontrollstrukturen, etc.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top