• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

C - Unterschiedlich viele Werte aus Datei-Zeilen lesen bis newline

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
Hallo,

mal eine grundlegende Frage zu C, vielleicht steht ich dabei auch nur etwas auf dem Schlauch:
Wie kann man sinnvoll den folgenden Inhalt aus einer Textdatei auslesen und die Werte aufsplitten?

Hier der Beispielinhalt:
[src=text]2 // Anzahl der Testcases (immer nur die erste Zeile)
100 // Credit
3 // Item count
5 75 25 // Products
200 // C
7 // I
150 24 79 50 88 345 3 // P
// und so weiter[/src]

Momentan mache ich es wie folgt.
Kurze Anmerkung, da der Code nicht wirklich kommentiert ist - mittels "fgetc" ein Zeichen (readIn) auslesen und auf einen char Array (readData) auf Position (writePos) schreiben - kommt ein Space oder Newline, wird an writePos ein Null-Terminiert gesetzt und mittels "atoi" bzw. "strtoul" (für vorzeichenlose Integer) die Werte als Zahl aus (readData) aus- bzw. eingelesen. (mode) dient dazu zwischen (C)redit, (I)tem count oder (P)roducts umzuschalten.

Das funktioniert auch, nur Frage ich mich ob ich es nicht unnötig komplex anstelle wenn ich Zeichenweise vorgehen.

Ich hatte schon mal "fscanf" versucht zu verwenden, aber da die Zeilen unterschiedlich viele Attribute haben, weiß ich nicht wie ich es damit parsen kann. Geht das überhaupt damit?
Oder wäre "fgets" die bessere Alternative um X Zeichen einzulesen ? Wenn man die Position eines Spaces kennt bei einer Aufzählung von Produkt-Preisen?

Hier mal mein Code dazu*:

* so etwas wie storeData kann ignoriert werden, das ist nur der Speicherort für die Werte.

[src=c] FILE* inputFile = fopen(inputFilePath, "r");
char readIn = '\0';
char readData[32] = "\0";
int writePos = 0;
int mode = 0;
unsigned int lines = 0;

unsigned int index = 0;
unsigned int position = 0;
storeData *current = NULL;
storeData *previous = NULL;
storeData *first = NULL;

char *end; // used for strtoul for unsigned product prices

while (!feof(inputFile)) {

readIn = fgetc(inputFile);
if (readIn == ' ') {
readData[writePos] = '\0';

if (mode == 2) {
current->products[index] = strtoul(readData, &end, 10);
//printf("index: %d, %d\n", (index+1), current->products[index]);
++index;
}

readData[0] = '\0';
writePos = 0;

} else if (readIn == '\n') {

if (lines == 0) {
// Ignore the first line
readData[writePos] = '\0';
writePos = 0;

++lines;
continue;
}

readData[writePos] = '\0';
writePos = 0;

if (mode == 2) {
current->products[index] = strtoul(readData, &end, 10);
//printf("index: %d, %d\n", (index+1), current->products[index]);
}

++mode;

if (mode >= 4) {
mode = 1;
}

if (mode == 1) {
if (current != NULL) {
previous = current;
}

current = (storeData*) calloc(1, sizeof(storeData));

if (first == NULL) {
first = current;
}

current->first = first;
current->previous = previous;
current->next = NULL;
current->credit = 0;
current->items = 0;
current->index = position;

if (previous != NULL) {
previous->next = current;
}

++position;
}

switch (mode) {
case 1:
// [C]redit
current->credit = atoi(readData);
break;
case 2:
// tem count and product storage
current->items = atoi(readData);
current->products = (unsigned int*) calloc(current->items, sizeof(unsigned int));
index = 0;
break;
default:
break;
}

++lines;
} else {
readData[writePos] = readIn;
++writePos;
}
}[/src]
 
Zuletzt bearbeitet:

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #3
Doch, das hilft schon weiter. :)

Da getline aber scheinbar nur unter Linux(?) verfügbar ist, habe ich anstelle dessen fgets() verwendet, funktioniert aber mit strtok() obwohl ein Newline Character und kein gefordertes Space am Ende ist, war mir unter anderem nach Lesen einer Referenz zu dem Befehl nicht klar.

Sieht dann ungefähr so aus, ist nur ein anderes Beispiel wo es darum geht Wörter statt Strings in einer Zeile auszulesen, daher auch keine Konvertierung dabei und nur der "relevante" Abschnitt und Variablen.

[src=c]
FILE* inputFile = fopen(inputFilePath, "r");
if (inputFile == NULL) {
printf("Input file doesnt exist.\n");
return 1;
}

fseek(inputFile, 0, SEEK_END);
long int bufferLength = ftell(inputFile);
rewind(inputFile);

unsigned int lines = 0;
char lineData[bufferLength];
char *textItem;

while (!feof(inputFile)) {
fgets(lineData, bufferLength, inputFile);

if (feof(inputFile)) {
break;
}

if (lines == 0) {
++lines;
continue;
}

textItem = strtok(lineData, " ");
while (textItem != NULL) {
printf("Line #%d, word: %s\n", lines, textItem);
textItem = strtok(NULL, " ");
}

++lines;
continue;
}

free(textItem);
fclose(inputFile);[/src]


Eine Anmerkung allerdings zu strtok - das man diesen mit strtok(NULL, " ") aufrufen muß um die Suche nach dem nächsten Trennzeichen zu machen, find ich ganz schön verwirrend und nicht wirklich logisch. In dem C11 Standard scheint das mit "strtok_s()" ja nicht mehr ganz so magisch abzulaufen, find ich bedeutend besser gelöst... auch wenn da auch wieder der "NULL" call genutzt wird, wenigstens kann man den Status speichern. Nun ja...

Irgendwie war das gerade auch ein Problem die while-Schleife nicht schöner schreiben zu können, also das Testen auf Null und Initialisieren im Schleifenkopf ;)


Aber danke nochmal für den Hinweis auf die Funktionen :)
 

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
Das würde mich doch etwas wundern wenn getline Linux spezifisch ist. Includest du auch <stdio.h>?
 

Timon3

Team ModMii

Registriert
17 Juli 2013
Beiträge
499
@theSplit: getline ist nicht nur unter Linux verfügbar, sondern ein Teil des POSIX-Standards. Als solcher wird er nur von Betriebssystemen unterstützt, die zumindest teils POSIX-konform sind, was eigentlich ziemlich viele sind. Windows hatte zeitweise auch ein POSIX-Subsystem, was aber mit Windows 8 als deprecated markiert wurde und mit Windows 10 abgeschafft, also kann man das nicht mehr voraussetzen bzw. benutzen.
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.573
  • Thread Starter Thread Starter
  • #6
@GameChamp98:

Okay, jetzt wird mir einiges klarer. :T Mir war jetzt nicht wirklich ersichtlich das zum Beispiel POSIX (.1-2008) und C99/C11 komplett differenzierte Standards sind...

Um dieses zu verdeutlichen wovon mir der Background gefehlt hat:

Zu getline():
CONFORMING TO
Both getline() and getdelim() were originally GNU extensions. They were standardized in POSIX.1-2008.

Im Gegenzug zu fgets():
CONFORMING TO
POSIX.1-2001, POSIX.1-2008, C89, C99.

Wenn man das nämlich so gegenüberstellt, macht es unter anderem auch für mich Sinn. :)

Auch ein sehr guter Hinweis, gleich dadurch noch was anderes dazugelernt. :cool:
 
Oben