Neonof
Mitglied
Hallo, folgendes Problem:
Ich habe mir vorgenommen, für ein Spiel ein kleines Tool zu schreiben. Dazu werden einige xml-Dateien ausgelesen und nach bestimmten Kriterien gefiltert. Zumindest bin ich bisher nur bis zum Einlesen der ersten Datei gekommen. Nun habe ich diesen Fehler, den ich einfach nicht verstehen will. Beim Einlesen nutze ich Schleifen mit fgetc() um die einzelnen Elemente zu erfassen, wobei als Abbruchbedingung beispielsweise gilt: (!feof(fp) && (fgetc(fp) != delim)). Dabei stellt delim das Zeichen dar, bis zu dem eingelesen werden soll. Soweit funktioniert auch alles schön und gut - bestimmt 100 Einträge lang. Ich habe nun also Schritt für Schritt den Debugger dabei begleitet, wie er den Code durchgeht und dabei mittels fgetpos() beobachtet, wo in die Datei der Filepointer zeigt. Dabei ist mir aufgefallen, dass fgetc() ab dem fehlerhaften Eintrag zwar die Zeichen liefert, den Pointer aber nicht mehr versetzt. Krücken zu bauen, in dem vor und nach der Verwendung von fgetc() mittels fgetpos() und fsetpos() die Position korrigiert wird funktioniert zwar relativ, aber das Wahre ist es auch nicht und an einigen Stellen hilft das auch nicht.
Ist die Funktion irgendwie unsicher und gibt es eine Alternative?
Ich habe in einem anderen Forum von einem Zusammenhang von setvbuf() mit fgetc() gelesen. Die Sache mit dem Buffering kenne ich noch nicht. Ich bin ja "noch neu in C". Aber ich kann mir eigentlich auch nicht vorstellen, dass sich diese Einstellungen ohne offensichtlichen Grund mitten beim Durchlauf des Programms ändern sollten. Einen dieser Befehle verwendet habe ich ja auch nicht.
Zu der verwendeten Software:
inzwischen CodeLite mit MinGW (TDM-GCC-64)
Windows 10 x64
Hier sind jetzt noch einige Krücken und Zeilen drinne, die dazu da waren, den Fehler zu finden. Bei der Version mit den Krücken, die den Fehler eigentlich komplett umgehen sollten, kommt es noch zu anderen merkwürdigen Fehlern. Da beendet er die Funktion readplayerline() mit return 1 und bricht die while-Schleife, in apiloadplayers(), von der sie als Abbruchbedingung aufgerufen wurde dennoch ab.
Ich denke eigentlich, dass dieses undefinierte Verhalten alles den selben Grund haben wird. Auf jeden Fall würde ich gerne mal verstehen, wie soetwas zustande kommt.
Vielen Dank schon einmal für die Hilfe
Ich habe mir vorgenommen, für ein Spiel ein kleines Tool zu schreiben. Dazu werden einige xml-Dateien ausgelesen und nach bestimmten Kriterien gefiltert. Zumindest bin ich bisher nur bis zum Einlesen der ersten Datei gekommen. Nun habe ich diesen Fehler, den ich einfach nicht verstehen will. Beim Einlesen nutze ich Schleifen mit fgetc() um die einzelnen Elemente zu erfassen, wobei als Abbruchbedingung beispielsweise gilt: (!feof(fp) && (fgetc(fp) != delim)). Dabei stellt delim das Zeichen dar, bis zu dem eingelesen werden soll. Soweit funktioniert auch alles schön und gut - bestimmt 100 Einträge lang. Ich habe nun also Schritt für Schritt den Debugger dabei begleitet, wie er den Code durchgeht und dabei mittels fgetpos() beobachtet, wo in die Datei der Filepointer zeigt. Dabei ist mir aufgefallen, dass fgetc() ab dem fehlerhaften Eintrag zwar die Zeichen liefert, den Pointer aber nicht mehr versetzt. Krücken zu bauen, in dem vor und nach der Verwendung von fgetc() mittels fgetpos() und fsetpos() die Position korrigiert wird funktioniert zwar relativ, aber das Wahre ist es auch nicht und an einigen Stellen hilft das auch nicht.
Ist die Funktion irgendwie unsicher und gibt es eine Alternative?
Ich habe in einem anderen Forum von einem Zusammenhang von setvbuf() mit fgetc() gelesen. Die Sache mit dem Buffering kenne ich noch nicht. Ich bin ja "noch neu in C". Aber ich kann mir eigentlich auch nicht vorstellen, dass sich diese Einstellungen ohne offensichtlichen Grund mitten beim Durchlauf des Programms ändern sollten. Einen dieser Befehle verwendet habe ich ja auch nicht.
Zu der verwendeten Software:
inzwischen CodeLite mit MinGW (TDM-GCC-64)
Windows 10 x64
Hier sind jetzt noch einige Krücken und Zeilen drinne, die dazu da waren, den Fehler zu finden. Bei der Version mit den Krücken, die den Fehler eigentlich komplett umgehen sollten, kommt es noch zu anderen merkwürdigen Fehlern. Da beendet er die Funktion readplayerline() mit return 1 und bricht die while-Schleife, in apiloadplayers(), von der sie als Abbruchbedingung aufgerufen wurde dennoch ab.
Ich denke eigentlich, dass dieses undefinierte Verhalten alles den selben Grund haben wird. Auf jeden Fall würde ich gerne mal verstehen, wie soetwas zustande kommt.
Vielen Dank schon einmal für die Hilfe

C:
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#define READ_STRING_MAX_CHARACTERS 100
char readString[READ_STRING_MAX_CHARACTERS], delim[] = {34, 0}, *token;
FILE *fp = NULL;
fpos_t pos1, pos2;
/* Statustype:
* 0 Normal
* 1 a Administrator
* 2 o Vogelfreier (temporär)
* 4 v Urlaubsmodus
* 8 b gesperrt
* 16 i Inaktiv
* 32 I Inaktiv (30)
* */
struct sAPIplayers
{
int id;
char* name;
int alliance;
int status;
struct sAPIplayers* next;
} *APIplayersTemp = NULL;
struct sAPIplayersHead
{
char* xmlVersion;
char* encoding;
char* serverId;
time_t timestamp;
char* nNsSL;
char* xmlnsxsi;
struct sAPIplayers* next;
} *APIplayers = NULL;
char* strnewcpy(char*_str_src) {
size_t len = strlen(_str_src);
char *newstr = (char*)malloc(len + 1);
if (newstr == NULL) return NULL;
strncpy(newstr, _str_src, len);
newstr[len] = '\0';
return newstr;
}
void frtc(char *dest, int lim, char delim)
// liest einen String bis zu delim ein
{
char temp;
int count = 0;
while (!feof(fp) && (count++ < lim))
{
fgetpos(fp, &pos1);
temp = fgetc(fp);
fgetpos(fp, &pos2);
if (pos1 == pos2) fseek(fp, 1, SEEK_CUR);
if (temp == delim) break;
*dest++ = temp;
}
*dest = 0;
}
int jo(char delim)
// schaltet die Position in der Datei hinter das nächste Vorkommen von delim
{
fgetpos(fp, &pos1);
while (!feof(fp) && (fgetc(fp) != delim))
{
fgetpos(fp, &pos2);
if (pos1 == pos2) fseek(fp, 1, SEEK_CUR);
}
fgetpos(fp, &pos2);
if (pos1 == pos2) fseek(fp, 1, SEEK_CUR);
if (feof(fp)) return EOF;
return 0;
}
int readplayerline()
{
// neuen Speicherbereich reservieren
APIplayersTemp = APIplayersTemp->next = (struct sAPIplayers*) malloc(sizeof(struct sAPIplayers));
// Daten einlesen
// id einlesen
jo(34);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
sscanf(readString, "%d", &APIplayersTemp->id);
// name einlesen
jo(34);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
APIplayersTemp->name = strnewcpy(readString);
fseek(fp, 1, SEEK_CUR);
// status einlesen
APIplayersTemp->status = 0;
fgetpos(fp, &pos1);
if (fgetc(fp) == 's')
{
fgetpos(fp, &pos2);
if (pos2 == pos1) fseek(fp, 1, SEEK_CUR);
jo(34);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
char* token = readString;
while (*token != 0)
{
if (*token == 'a') APIplayersTemp->status = 1;
if (*token == 'o') APIplayersTemp->status += 2;
if (*token == 'v') APIplayersTemp->status += 4;
if (*token == 'b') APIplayersTemp->status += 8;
if (*token == 'i') APIplayersTemp->status += 16;
if (*token++ == 'I') APIplayersTemp->status += 32;
}
fseek(fp, 1, SEEK_CUR);
} else fsetpos(fp, &pos1);
// alliance einlesen
APIplayersTemp->alliance = 0;
fgetpos(fp, &pos1);
if (fgetc(fp) == 'a')
{
fgetpos(fp, &pos2);
if (pos2 == pos1) fseek(fp, 1, SEEK_CUR);
jo(34);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
sscanf(readString, "%d", &APIplayersTemp->alliance);
fseek(fp, 2, SEEK_CUR);
} else {
fgetpos(fp, &pos2);
if (pos2 == pos1) fseek(fp, 1, SEEK_CUR);
}
APIplayersTemp->next = NULL;
printf("Spieler geladen: ID: %7d\tName: %s\n", APIplayersTemp->id, APIplayersTemp->name);
fseek(fp, 1, SEEK_CUR);
char a = fgetc(fp);
printf("%c\n", a);
if (a == 'p') return 1;
return 0;
}
fpos_t fpos()
// zeigt mit der Watches-Funktion von CodeLite die derzeitige Position in der Datei
{
fpos_t pos;
fgetpos(fp, &pos);
return pos;
}
int apiloadplayers()
{
// Datei öffnen
fp = fopen("players.xml", "r");
if (fp == NULL)
{
printf("Fehler: ""players.xml"" wurde nicht gefunden!\n");
return -1;
}
// Speicher für den Header reservieren
APIplayers = (struct sAPIplayersHead*) malloc(sizeof(struct sAPIplayersHead));
// Header einlesen
fgets(readString, READ_STRING_MAX_CHARACTERS, fp);
strtok(readString, delim);
APIplayers->xmlVersion = strnewcpy(strtok(NULL, delim));
strtok(NULL, delim);
APIplayers->encoding = strnewcpy(strtok(NULL, delim));
fseek(fp, 21, SEEK_CUR);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
APIplayers->xmlnsxsi = strnewcpy(readString);
fseek(fp, 32, SEEK_CUR);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
APIplayers->nNsSL = strnewcpy(readString);
fseek(fp, 12, SEEK_CUR);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
sscanf(readString, "%lli", &APIplayers->timestamp);
fseek(fp, 11, SEEK_CUR);
frtc(readString, READ_STRING_MAX_CHARACTERS, 34);
APIplayers->serverId = strnewcpy(readString);
// player einlesen
APIplayersTemp = APIplayers;
while (readplayerline()) ;
printf("""players.xml"" erfolgreich geladen!\n");
fclose(fp);
return 0;
}
int main()
{
apiloadplayers();
getchar();
return 0;
}
Anhänge
Zuletzt bearbeitet: