[c] Dateiliste sortieren, mehrdimensionale Felder über malloc?

Wu-mc hat gesagt.:
Okay ich hab grad mal kurz rein geschaut, das kann ich vergessen. Ist viel zu aufwendig das ganze in C++ um zu schreiben.

Wieso? Was hättest alles umschreiben müssen?

PS: Es gibt einen Button unten rechts, damit kannst du deine Posts editieren. 4-fach Post ist schon ein bischen viel...
 
Also das auslesen hab ich jetzt so gelöst:

Code:
BOOL BackOfficeTBZuordnungLoad ()
{
    TCHAR		  szPath[MAX_PATH]; 
	TCHAR		  szLine[MAX_CHAR_SATZ];
	TCHAR		  * temp;
	FILE		  * fFile;
	int			  iIndex;
    
	// Aktuellen Pfad ermitteln
    if( !GetModuleFileName( NULL, szPath, MAX_PATH - 1))
        return FALSE;

	temp = _tcsrchr(szPath,'\\');
	if (temp == NULL)
	{
		return FALSE;
	}
	else
	{
		temp++;
		* temp = '\0';
	}

	// Setupdatei öffnen
	_tcsncat (szPath, TEXT ("TBZuordnung.txt"), min (16, MAX_PATH - _tcslen(szPath) / sizeof(TCHAR)));
	fFile = _tfopen (szPath, TEXT ("r"));

	if (!fFile)
		return FALSE;

	// Datensätze zählen
	iCount = 0;
	while (_fgetts (szLine, MAX_CHAR_SATZ, fFile)) iCount++;

	pszZuordnung = (TCHAR *) malloc (iCount * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR) * sizeof(TCHAR));

	rewind (fFile);

	for (iIndex = 0; iIndex < iCount; iIndex++)
	{
		_fgetts (szLine, MAX_CHAR_SATZ, fFile);
		_tcsncpy (pszZuordnung + (iIndex * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR)),
				  szLine, MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR);
	}

	bChange = FALSE;

	fclose (fFile);

	return TRUE;
}

und so die Abfrage für Terminal ID und Box Nr:

Code:
TCHAR * BackOfficeTBZuordnungGetTid (int iElement)
{
	// Wenn Daten geändert dann neu laden
	if (bChange)
		BackOfficeTBZuordnungLoad ();

	return (pszZuordnung + (iElement * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR)));
}

TCHAR * BackOfficeTBZuordnungGetBnr (int iElement)
{
	// Wenn Daten geändert dann neu laden
	if (bChange)
		BackOfficeTBZuordnungLoad ();

	return (pszZuordnung + (iElement * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR))
			+ MAX_CHAR_TERMINAL_ID);
}

und so wird ein Element hinzu gefügt:

Code:
BOOL BackOfficeTBZuordnungAdd (TCHAR * pszElement)
{
	// Änderungen anzeigen
	bChange = TRUE;

	// Anzahl hochzählen
	iCount++;

	// Array erweitern
	pszZuordnung = (TCHAR *) realloc (pszZuordnung, iCount * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR) * sizeof(TCHAR));

	// Neues Element einfügen
	_tcsncpy (pszZuordnung + ((iCount - 1) * (MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR)), 
		      pszElement, MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR);

	// Neues Array speichern
	return (BackOfficeTBZuordnungSave());
}

Hoffe der Code ist soweit Fehlerfrei. Vielen Dank an alle die Geholfen haben!
Und Sorry für die Mehrfachposts, werds mir merken.
 
Hi.
Wu-mc hat gesagt.:
Code:
	temp = _tcsrchr(szPath,'\\');
Unter Windows kann auch ein einfacher Schrägstrich statt eines umgekehrten Schrägstriches als Verzeichnisseparator verwendet werden. Damit beides funktioniert ist es günstig alle Backslash durch einen Slash zu ersetzen (oder umgekehrt). Außerdem könntest du wenn ein Schrägstrich am Ende fehlt diesen auch einfach noch hinzufügen anstatt abzubrechen.
Wu-mc hat gesagt.:
Code:
	_tcsncat (szPath, TEXT ("TBZuordnung.txt"), min (16, MAX_PATH - _tcslen(szPath) / sizeof(TCHAR)));
Warum teilst du die Länge durch die Anzahl der Bytes eines TCHAR? String Funktionen arbeiten immer auf Basis von Zeichen - nicht Bytes. D.h. _tcsncat wird maximal n Zeichen (egal wie groß die sind) in den Zielstring kopieren.

Die Berechnung mit min(16, ... ist übrigens ziemlich sinnfrei, denn wenn noch genug Platz im String ist, dann ist das Minimum 16 - d.h. _tcsncat kopiert max. 16 Zeichen in den Zielstring; die Funktion hätte aber auch so 16 Zeichen kopiert weil das genau die Anzahl der Zeichen im Quellstring ist. Allerdings wird immer noch ein Nullzeichen angehängt, d.h. du mußt MAX_PATH - _tcslen(szPath) - 1 rechnen um nicht über das Ende hinauszuschreiben.


Du könntest bei deinem flachen Array übrigens auch direkt die Array Notation benutzen um auf die Elemente zuzugreifen:
Code:
typedef TCHAR tFname[MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR];

tFname* pszZuordnung = (tFname*) malloc(iCount * sizeof(tFname));

_tcsncpy (pszZuordnung[5], szLine, MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR);
Da mußt du nicht immer so wild rumrechnen.

Die Methode an sich ist natürlich relativ sub-optimal, aber das weißt du sicher bereits.

Gruß
 
deepthroat hat gesagt.:
Hi.Unter Windows kann auch ein einfacher Schrägstrich statt eines umgekehrten Schrägstriches als Verzeichnisseparator verwendet werden. Damit beides funktioniert ist es günstig alle Backslash durch einen Slash zu ersetzen (oder umgekehrt). Außerdem könntest du wenn ein Schrägstrich am Ende fehlt diesen auch einfach noch hinzufügen anstatt abzubrechen.

Ja weiß ich mittlerweile, wollts aber lieber so lösen als alle Slashes die ich von irgendwelchen Funktionen bekomm umdrehen zu müssen.

deepthroat hat gesagt.:
Warum teilst du die Länge durch die Anzahl der Bytes eines TCHAR? String Funktionen arbeiten immer auf Basis von Zeichen - nicht Bytes. D.h. _tcsncat wird maximal n Zeichen (egal wie groß die sind) in den Zielstring kopieren.

Aus Unwissenheit! Ich hab mal in einem anderen Thema was über Unicode gefragt und keine Antwort bekommen, deswegen war ich mir jetzt nicht sicher. Habs hinterher dann mal in MSDN nachgeschlagen. Sind noch Codefragmente die ich am Anfang des Projekts geschrieben habe und wohl vergessen hab zu ändern.

deepthroat hat gesagt.:
Die Berechnung mit min(16, ... ist übrigens ziemlich sinnfrei, denn wenn noch genug Platz im String ist, dann ist das Minimum 16 - d.h. _tcsncat kopiert max. 16 Zeichen in den Zielstring; die Funktion hätte aber auch so 16 Zeichen kopiert weil das genau die Anzahl der Zeichen im Quellstring ist. Allerdings wird immer noch ein Nullzeichen angehängt, d.h. du mußt MAX_PATH - _tcslen(szPath) - 1 rechnen um nicht über das Ende hinauszuschreiben.

Naja hab halt versucht das von MSDN zu übernehmen, denn die meinen das es sogar sinnvoll wäre und hier verweist ja jeder immer auf MSDN, deswegen dachte ich ich löse das mal lieber so. Siehe Auszug aus MSDN:

Code:
#include <stdlib.h>

#define MAXSTRINGLEN(s) ( sizeof(s)/sizeof(s[0]) - 1 )

char string[40];

void BadAppend( char suffix[], int n )
{
   strncat( string, suffix, n );
}

void GoodAppend( char suffix[], size_t  n )
{
   strncat( string, suffix, __min( n, MAXSTRINGLEN(string)-strlen(string)) );
}

int main( void )
{
   printf( "string can hold up to %d characters\n", MAXSTRINGLEN(string) );

   strcpy( string, "This is the initial string!" );
   // concatenate up to 20 characters...
   BadAppend( "Extra text to add to the string...", 20 );
   printf( "After BadAppend :  %s (%d chars)\n", string, strlen(string) );

   strcpy( string, "This is the initial string!" );
   // concatenate up to 20 characters...
   GoodAppend( "Extra text to add to the string...", 20 );
   printf( "After GoodAppend:  %s (%d chars)\n", string, strlen(string) );
}

deepthroat hat gesagt.:
Du könntest bei deinem flachen Array übrigens auch direkt die Array Notation benutzen um auf die Elemente zuzugreifen:
Code:
typedef TCHAR tFname[MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR];

tFname* pszZuordnung = (tFname*) malloc(iCount * sizeof(tFname));

_tcsncpy (pszZuordnung[5], szLine, MAX_CHAR_TERMINAL_ID + MAX_CHAR_BOX_NR);
Da mußt du nicht immer so wild rumrechnen.

Vielen Dank für den Tipp. Wusste ich bisher nicht. Aber das mit dem Rumrechnen finde ich nicht so schlimm. Finde das mit der Pointer Geschichte mittlerweile recht einleuchtend.

deepthroat hat gesagt.:
Die Methode an sich ist natürlich relativ sub-optimal, aber das weißt du sicher bereits.

Ich weiß jetzt nicht genau was du meinst, kannst du es mir erklären?
 
Wu-mc hat gesagt.:
Naja hab halt versucht das von MSDN zu übernehmen, denn die meinen das es sogar sinnvoll wäre und hier verweist ja jeder immer auf MSDN, deswegen dachte ich ich löse das mal lieber so. Siehe Auszug aus MSDN:

Code:
#include <stdlib.h>

#define MAXSTRINGLEN(s) ( sizeof(s)/sizeof(s[0]) - 1 )

char string[40];

void GoodAppend( char suffix[], size_t  n )
{
   strncat( string, suffix, __min( n, MAXSTRINGLEN(string)-strlen(string)) );
}

int main( void )
{
   printf( "string can hold up to %d characters\n", MAXSTRINGLEN(string) );

   strcpy( string, "This is the initial string!" );
   // concatenate up to 20 characters...
   GoodAppend( "Extra text to add to the string...", 20 );
   printf( "After GoodAppend:  %s (%d chars)\n", string, strlen(string) );
}
Das ist hier natürlich schon sinnvoll da hier angegeben werden kann wieviel Zeichen max. vom Quellstring angehängt werden sollen. Wenn du den kompletten String anhängen willst, dann ist das min unnötig.

Wu-mc hat gesagt.:
Ich weiß jetzt nicht genau was du meinst, kannst du es mir erklären?
Naja, erstmal liest du die Datei natürlich zweimal. Dann benutzt du realloc und bei realloc muß unter Umständen die komplette Datenstruktur in einen neuen Speicherbereich kopiert werden.

Außerdem belegt jeder Dateiname - egal wie groß der nun wirklich ist - eine bestimmte Anzahl von Bytes. Du könntest besser das Array als auch die Einträge dynamisch anlegen:
Code:
TCHAR** pszZuordnung = (TCHAR**) malloc(size * sizeof(TCHAR*));

pszZuordnung[i] = (TCHAR*) malloc((_tcslen(pszElement) + 1) * sizeof(TCHAR));

_tcscpy (pszZuordnung[i], pszElement);
Dann ist jeder Eintrag im Array nur noch so groß wie nötig. (Du mußt dann beim Beenden allerdings jeden Eintrag einzeln freigeben)

Außerdem könntest du es so machen das du nicht für jeden einzelnen Eintrag reallozieren mußt, sondern immer gleich Platz für mehrere Elemente allozierst. Das Reallozieren ist normalerweise relativ "teuer".

Gruß
 
Zurück