ubuntuusers.de

C-Programmierung fscanf Fehler

Status: Gelöst | Ubuntu-Version: Ubuntu 9.04 (Jaunty Jackalope)
Antworten |

the_clapper

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

Hallo, ich benötige ein Programm, welches aus einer Datei mit festem Format Zahlen einliest. Habe google bemüht und danke fscanf ist die Funktion, die ich brauche. Da ich c-Neuling bin habe ich es mit einem einfachen Testprogramm probieren wollen, aber bisher habe ich folgendes Problem. Das Programm:

#include <stdio.h>
int main(void)
{

int x;

FILE *datei;

datei = fopen("100.txt", "r");
if(NULL == datei)
      {
         printf("Fehler beim Öffnen");
      }

fscanf(datei, "%d", x);

printf("x = %d \n", x);

fclose(datei);

return 0;

}

liefert beim kompilieren mit gcc folgende Warnung:

a.c: In Funktion »main«:
a.c:15: Warnung: format »%d« erwartet Typ »int *«, aber Argument 3 hat Typ »int«

Und das Programm liefert, wenn ich es ausführe folgenden Fehler:

Segmentation fault

Ich denke, wenn ich die Fehlermeldung verstünde, wäre mir schon geholfen. Kann mir jemand erklären, wovor gewarnt wird?

In der Datei 100.txt steht in der ersten Zeile ohne Leerzeichen davor "100" (ohne die Anführungszeichen.

Sid_Burn

Anmeldungsdatum:
23. Oktober 2004

Beiträge: 2159

the clapper schrieb:

a.c: In Funktion »main«:
a.c:15: Warnung: format »%d« erwartet Typ »int *«, aber Argument 3 hat Typ »int«

Ich denke, wenn ich die Fehlermeldung verstünde, wäre mir schon geholfen. Kann mir jemand erklären, wovor gewarnt wird?

C erwartet einen Zeiger(Pointer) auf einen int. Das sagt der Stern aus, der steht für Zeiger. Du hast aber direkt ein int übergeben. Mit einem & vor einer Variable bekommt man die Adresse einer Variablen. Daher musst du wohl eher soetwas schreiben.

fscanf(datei, "%d", &x);

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Zudem läuft Dein Programm nach einem möglichen Fehler einfach weiter, ich würde das Aaslesen daher in einen else-Zweig packen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void)
{
    int x;
    FILE *datei;
    datei = fopen("100.txt", "r");
    if(NULL == datei) {
        printf("Fehler beim Öffnen");
    } else {
        fscanf(datei, "%d", &x);
        printf("x = %d \n", x);
        fclose(datei);
    }
    return 0;
}

Dann noch zwei Fragen:

  • Muss es denn C sein?

  • Wie ist das Format denn definiert? Ist das eine Vorgabe oder ist das Format frei wählbar? Wenn ja, dann solltest Du auf ein Standard Format setzen, für das es fertige Parser gibt.

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

erstmal vielen Dank. Jetzt funktioniert mein Beispiel und ich denke ich habe auch in etwa verstanden, was der Fehler war.

Also der Kontext ist folgender:

Ich habe Dateien in der Form:

Ganzzahl Ganzzahl Fließkommazahl

Es sind Punkte, die in eine PostGreSQL Datenbank gespeichert werden sollen.

Im ersten Schritt wollte ich mir einer Eingabe-Datei für psql schreiben, die ich dann per

psql -d "dbname" -f "input-file"

einlade. Habe das per Hand getestet, dafür aber jetzt das C-Programm.

Im zweiten Schritt würde ich gerne die Eingabe-Datei umgehen und direkt in die Datenbank speichern. Da alleine die reinen Punkte-Dateien mehrere hundert MB groß sind dürften die Eingabe-Dateien für psql noch viel größer werden und somit unhandlich. Ich habe allerdings noch keine Ahnung, ob es möglich ist direkt aus einem kleinen Programm in die Datenbank zu schreiben.

Die Programmiersprache ist egal, solange unter Ubuntu/Debian einfach zu "erreichen". C, C++ oder Fortran wären ideal. Perl oder Java weniger, aber zur Not ginge das auch. Ich freue mich über jede Anregung.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Also da würde ich mal dieses Python Script vorschlagen:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import postgresql
import sys


def get_values(filename):
    """
    Generator function which parses a file with the given filename and yields
    data values for each line.
    """
    funcs = [int, int, float]
    with open(filename, "r") as infile:
        for line in infile:
            tokens = line.strip().split()
            yield [func(value) for func, value in zip(funcs, tokens)]


def main():
    db = postgresql.open("pq://username:password@localhost/postgres")
    store_values = db.prepare("INSERT INTO whatever VALUES ($1, $2, $3)")
    with db.xact():
        store_values.load_rows(get_values(sys.argv[1]))


if __name__ == "__main__":
    main()

Neben der Standard Lib wird nur noch dieser PostgreSQL-Connector benötigt. Da ich keine Postgres-DB hier hatte, konnte ich den DB-Teil nicht testen. Laut Doku sollte das aber so funktionieren. Du musst halt in Zeile 21 die Verbindungsdaten anapssen und in Zeile 22 den Tabellennamen.

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

Vielen Dank. Ich werde das gleich heute Abend noch testen. Wo hast Du das her? Oder hast Du es etwa gerade selbst geschrieben?

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

the clapper schrieb:

Vielen Dank. Ich werde das gleich heute Abend noch testen. Wo hast Du das her? Oder hast Du es etwa gerade selbst geschrieben?

Natürlich letzteres 😉 Als kleine Fingerübung quasi ☺ Wenn Du es relativ schnell testest, bin ich noch online falls etwas mit der DB nicht funzt. Den Teil konnte ich ja leider nicht testen.

Ach ja, die Daten-Datei musst Du als Parameter beim Aufruf übergeben. Hatte ich nicht dazugeschrieben ☺

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

Ich stehe etwas auf dem Schlauch, wäre sehr nett, wenn Du mir noch weiter helfen könntest. Folgendes habe ich gemacht.

1) Python 3.1 installiert 2) Den von Dir empfohlenen "Konnektor" py-postgresql-1.0.1 installiert über

sudo python3.1 ./setup.py install

Jetzt Dein Script abspeichern, aber als was? Als .py Datei? Und dann den Aufruf wie?

./script.py -dateiname

? Habe bisher noch nichts mit Python zu tun gehabt.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Also ich hab es mit Python 2.6.5 entwickelt! K.A. ob es auch mit Python 3.x läuft.

Der Aufruf muss ohne das "-" erfolgen - ist ja keine Option.

1
./script.py datei_name

Du musst es natürlich auch noch mit chmod ausführbar machen, oder das ganze mit python aufurfen:

1
python script.py datei_name

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

Der Konnektor hat bei der Installation gemeckert und nach 3.1 oder höher verlangt.

Ich erhalte folgenden Fehler

Traceback (most recent call last):
  File "./script.py", line 4, in <module>
    import postgresql
ImportError: No module named postgresql

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

the clapper schrieb:

Der Konnektor hat bei der Installation gemeckert und nach 3.1 oder höher verlangt.

Ah... ok

Ich erhalte folgenden Fehler

Traceback (most recent call last):
  File "./script.py", line 4, in <module>
    import postgresql
ImportError: No module named postgresql

Das bedeutet, dass Python das Modul nicht finden kann.

Ich habe folgende Vermutung: Wenn Du unter ubuntu arbeitest, dann hast Du ja nebenher noch python 2.6 installiert. /usr/bin/env wird auf dieses verweisen, welches logischerweise das Modul nicht kennt. (Module liegen bei Python immer in einem Verzeichnis namens site-packages, welches sich direkt auf eine Interpreter-Version bezieht)

Hier steht dazu was: http://wiki.ubuntuusers.de/Python#Python-3

Also ändere den She-bang oben eben um:

1
2
3
#!/usr/bin/python3
# oder evtl auch so
#!/usr/bin/env python3

Musst Du mal probieren ☺

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

mit

#!/usr/bin/python3.1

läuft es es. Sehr gut, danke schön. Allerdings habe ich beim INSERT INTO irgendwo einen Syntax-Fehler. Den werde ich wohl so schnell nicht beheben können, da ich meine Aufzeichnungen, in denen der richtige Befehl steht, leider nicht hier habe. Werde es morgen früh probieren und Dir dann Rückmeldung geben. Vielen Danke nochmal.

edit: nachdem ich den Datenbank-Namen angepasst habe arbeitet er jetzt. Ist leider ein sehr langsamer Test-Server. Schätze mal das wird noch einige Minuten dauern...

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

the clapper schrieb:

edit: habe den Befehl noch im Kopf gehabt:

INSERT INTO punkte (spalte) VALUES (ST_makePoint(5.5,5.5,5.5));

funktioniert leider nicht. ST_makePoint kommt aus postGis, einer Erwieterung für PostrgreSQL.

Tja... was heißt denn "funktioniert" nicht? Wie äußert sich das?

the_clapper

(Themenstarter)

Anmeldungsdatum:
3. Juli 2009

Beiträge: 134

Danke. Alles bestens! Da war ich mit post&edit etwas voreilig. Nochmals vielen, vielen Dank. Du hast mir wirklich einiges an Recherche gespart.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

the clapper schrieb:

Danke. Alles bestens! Da war ich mit post&edit etwas voreilig. Nochmals vielen, vielen Dank. Du hast mir wirklich einiges an Recherche gespart.

Also funzt es? ☺

Antworten |