Struct ändern



  • Ich wollte gerne ein POINT-Array zurechtschneiden. Im Array gibt es POINTs bei denen x und y = 0 ist, die sollen da raus. Als Beispiel

    Index    Status
     [0]      o.k.
     [1]     X/Y = 0
     [2]      o.k.
     [3]      o.k.
     [4]     X/Y = 0
     [5]      o.k.
     [6]      o.k.
     [7]      o.k.
     [8]      o.k.
     [9]      o.k.
    

    Ich dachte daran per memcpy die Daten zu verschieben, allerdings funktioniert das nicht so ganz:

    if ((*pt)[i].x <= 1 || (*pt)[i].y <= 1) {
    	memmove (&(*pt)[i], &(*pt)[i + 1], ((countPts - i - 1) * sizeof (POINT)));
    

    (*pt) nehme ich zum Überprüfen, weil das ganze in einer Funktion ist und an diese Funktion wird eben die Adresse zum POINT-Struct geliefert, weswegen ich dann ja den Pointer nutzen muss. Jetzt ist aber mein erster Versuch, aus einem Array etwas rauszunehmen, in dem ich die nachfolgenden Daten einfach rüberkopiere. Die Idee war, wenn i == 1 oder 4 ist (nach dem Beispiel oben), dass dann ab i (also 1 oder 4) die Daten ab i + 1 (also 2 oder 5) rüber geschoben werden. Insgesamt sollen dann alle Elemente (countPts * sizeof (POINT)) minus der bereits geprüften Elemente ((countPts - i) * sizeof) minus eins bewegt werden (- 1, weil ich bei 10 Elementen bei Index 1/4 ja noch 8/5 potentiell gültige POINTS habe also 10 - 1/4 = 9/6 - 1 = 8/5 * sizeof).
    Wenn ich das so mache, stürzt das Programm zwar nicht ab, aber am Index 1/4 sind immer noch die 0-Werte 😞
    Das Array wird auch erst in der Funktion befüllt, also per malloc wird Speicher angefordert und dann befüllt und dann versuche ich die 0-Werte rauszufiltern (geht leider vorher nicht, weil ich den Point von einer Windows-Funktion befüllen lassen muss).

    Wäre über Hilfe dankbar, gerne auch mit Erklärung!


  • Mod

    Kannst du ein vollständiges Minimalbeispiel liefern? Wenn ich in Gedanken alles Fehlende so ergänze, wie es richtig wäre, dann funktioniert in meinem Kopf alles korrekt. Aber das sind auch verdächtig viele Pointerindirektionen in deinem Programm, es ist sehr gut vorstellbar, dass du dabei oder anderswo etwas falsch machst.



  • void checkPOINT (POINT **point) {
    	int num = 10;
    	*point = (POINT *) malloc (num * sizeof (POINT));
    	(*point)[0].x = (*point)[0].y = 10;
    	(*point)[1].x = (*point)[1].y = 0;
    	(*point)[2].x = (*point)[2].y = 20;
    	(*point)[3].x = (*point)[3].y = 30;
    	(*point)[4].x = (*point)[4].y = 0;
    	(*point)[5].x = (*point)[5].y = 40;
    	(*point)[6].x = (*point)[6].y = 50;
    	(*point)[7].x = (*point)[7].y = 0;
    	(*point)[8].x = (*point)[8].y = 70;
    	(*point)[9].x = (*point)[9].y = 80;
    
    	for (int i = 0; i < num; i++) {
    		if ((*point)[i].x <= 1 || (*point)[i].y <= 1) {
    			memmove (&(*point)[i], &(*point)[i + 1], ((10 - i - 1) * sizeof (POINT)));
    			num--;
    		}
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	POINT *paperSizes = NULL;
    	checkPOINT (&paperSizes);
    
    	wprintf (L"\n\n");
    	for (int i = 0; i < 8; i++)
    		wprintf (L"%i %i\n", paperSizes[i].x, paperSizes[i].y);
    
    	return 0;
    }
    

    Das habe ich gerade mal in einer extra Konsolendatei getestet und funktioniert auch. In meinem richtigen Programm stützt das so (mittlerweile) immer ab (habs eins zu eins kopiert). Minimalbeispiel ist da schlecht für ...

    Aber so ist ungefähr der Aufbau:

    dlg.cpp <-- checkPOINT () --- function.cpp
    

    checkPOINT ist in function.cpp definiert. In dlg.cpp wird die Funktion aus einer anderen Funktion heraus aufgerufen, in der wiederum der POINT-Pointer zu Hause ist. Der ist auch auf static, also ohne memmove ist mit den Daten darin alles gut, bis auf die nullen. Der POINT-Pointer wird auch nur in der Funktion benutzt, die checkPOINT aufruft ...



  • habe es doch noch auf ein minimales bekommen wo es immer noch abstürzt:

    #include "stdafx.h"
    #include <Windows.h>
    
    int getPaperSize (wchar_t *str_printerName, wchar_t *str_printerPort, POINT **pt_paperSizes)
    {
    	unsigned short epserr = 0;
    
    	int numPaperSizes = DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERSIZE, NULL, NULL);
    	if (numPaperSizes == -1)
    		return -1;
    
    	*pt_paperSizes = (POINT *) malloc (numPaperSizes * sizeof (POINT));
    
    	int returnVal = DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERSIZE, (LPWSTR) *pt_paperSizes, NULL);
    	if ((returnVal == -1)) {
    		free (*pt_paperSizes);
    		*pt_paperSizes = NULL;
    
    		return -1;
    	}
    
    	for (int i = 0; i < returnVal; i++) {
    
    		if ((*pt_paperSizes)[i].x <= 1 || (*pt_paperSizes)[i].y <= 1) {
    			memmove (&(*pt_paperSizes)[i], &(*pt_paperSizes)[i + 1], ((10 - i - 1) * sizeof (POINT)));
    			returnVal--;
    		}
    	}
    
    	return epserr;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	POINT *paperSizes = NULL;
    	getPaperSize (L"Fax\0", L"\0", &paperSizes);
    
    	wprintf (L"\n\n");
    	for (int i = 0; i < 8; i++)
    		wprintf (L"%i %i\n", paperSizes[i].x, paperSizes[i].y);
    
    	free (paperSizes);
    
    	return 0;
    }
    


  • for (int i = 0; i < returnVal; i++) { 
    
            if ((*pt_paperSizes)[i].x <= 1 || (*pt_paperSizes)[i].y <= 1) { 
                memmove (&(*pt_paperSizes)[i], &(*pt_paperSizes)[i + 1], ((returnVal - i - 1) * sizeof (POINT))); //Muss "returnVal" sein statt "10", sonst kommt was negatives raus
                i--; //Das aktuelle Element muss wiederholt werden, da es jetzt ein neuer Punkt ist
    			returnVal--;
            } 
        } 
    
        return returnVal; //Richtigen Wert zurückgeben?
    


  • Das erklärt schonmal, warum es auf einmal doch abgestürzt ist. Böses copy/paste ... Da erkläre ich das oben so schön und haue statt der Gesamtanzahl die blöde zehn rein 🙄
    Das mit dem akutellen i war wohl dann der Grund, warum nichts richtig gelöscht wurde! Also danke vielmals!!



  • int EnumerateSupportedPapers (HWND combobox, wchar_t *str_printerName, wchar_t *str_printerPort, POINT **pt_paperSizes, PAPERNAME *arr_paperNames, int count_paperNames)
    {
    	unsigned short epserr = EPSERR_NOERROR;
    	SendMessage (combobox, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0);
    
    	int numPapers = DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERS, NULL, NULL);
    	int numPaperNames = DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERNAMES, NULL, NULL);
    	int numPaperSizes = DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERSIZE, NULL, NULL);
    	if (numPapers == -1 || numPaperNames == -1 || numPaperSizes == -1)
    		return EPSERR_FAILEDTOENUMPAPERS;
    
    	unsigned short *dw_papers = (unsigned short*) malloc (numPapers * sizeof (unsigned short));
    	wchar_t *str_paperNames = (wchar_t*) malloc (64 * numPaperNames * sizeof (wchar_t));
    	*pt_paperSizes = (POINT *) malloc (numPaperSizes * sizeof (POINT));
    
    	if ((DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERS, (LPWSTR) dw_papers, NULL) == -1) ||
    		(DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERNAMES, str_paperNames, NULL) == -1) ||
    		(DeviceCapabilities (str_printerName, str_printerPort, DC_PAPERSIZE, (LPWSTR) *pt_paperSizes, NULL) == -1)) {
    		free (dw_papers);
    		free (str_paperNames);
    		free (*pt_paperSizes);
    		*pt_paperSizes = NULL;
    
    		return EPSERR_FAILEDTOENUMPAPERS;
    	}
    
    	wchar_t str_currentName[64 + 1];
    	str_currentName[64] = L'\0';
    
    	SendMessage (combobox, CB_ADDSTRING, (WPARAM) 0, (LPARAM) L"Benutzerdefiniert...");
    	for (int i = 0, paperSizeIndex = 0; i < numPaperSizes; i++) {
    		bool b_paperFound = false;
    
    		if ((*pt_paperSizes)[paperSizeIndex].x <= 1 || (*pt_paperSizes)[paperSizeIndex].y <= 1) {
    			memmove (&(*pt_paperSizes)[paperSizeIndex], &(*pt_paperSizes)[paperSizeIndex + 1], ((numPaperSizes - paperSizeIndex - 1) * sizeof (POINT)));
    			continue;
    		}
    
    		for (int x = 0; x < count_paperNames; x++) {
    			if ((&arr_paperNames[x])->id == dw_papers[i]) {
    				unsigned long retValue = SendMessage (combobox, CB_ADDSTRING, (WPARAM) 0, (LPARAM) (&arr_paperNames[x])->strName);
    				if (retValue == CB_ERR || retValue == CB_ERRSPACE)
    					epserr = EPSERR_FAILEDTOLISTPAPERS;
    
    				b_paperFound = true;
    			}
    		}
    
    		if (!b_paperFound) {
    			memcpy (str_currentName, str_paperNames + (i * 64), 64 * sizeof (wchar_t));
    
    			unsigned long retValue = SendMessage (combobox, CB_ADDSTRING, (WPARAM) 0, (LPARAM) str_currentName);
    			if (retValue == CB_ERR || retValue == CB_ERRSPACE)
    				epserr = EPSERR_FAILEDTOLISTPAPERS;
    		}
    
    		paperSizeIndex++;
    	}
    
    	free (dw_papers);
    	free (str_paperNames);
    
    	return epserr;
    }
    

    Habe es über ein extra Index für die POINTs programmiert, weil ich in der Schleife noch andere Sachen machen muss. Falls das jemand sehen will habe ich den ganzen Code mit reingepackt 😃

    Danke an Euch für die Hilfe hätte sonst bestimmt Sonntag noch dran gesessen ^^


  • Mod

    Nur um ganz sicher zu gehen: Dir ist klar, dass sofern die Reihenfolge der Elemente keine Rolle spielen sollte, das ganze auch wesentlich weniger aufwendig für den Computer ginge? Das häufige Verschieben ist nämlich recht teuer. Und ganz unabhängig von der Relevanz der Reihenfolge: Wenn man öfters Löschungen in der Mitte eines Arrays hat, lohnt es sich nachzudenken, ob ein Array überhaupt die richtige Datenstruktur ist.



  • leider kann man die größe der papierformate nachträglich bzw. nur für ein spezielles format nicht ermitteln (ich weiß wenigstens nicht wie), sodass ich das anders nicht gelöst bekommen habe gedanklich ... also ich kann wenn ich die größe von din a6 haben will nirgends eine funktion aufrufen um die sicher zu ermitteln. das läuft dann immer über strings und die sind bei jedem drucker anders, aber DC_PAPERS und DC_PAPERSIZE stimmen vom index her überein (auch laut msdn), so dass ich immer nur den index der auswahl in der combobox ermitteln muss und dann im POINT array nachgucken kann, welche größe das ist.
    DeviceCapabilities gibt beim ermitteln der papiergröße immer ein POINT array zurück, also müsste ich das wenn dann umwandeln und da nur ganz wenig gelöscht werden müssen pro aufruf finde ich das in ordnung. es sind vielleicht mal zwei von 50 oder so ... wenn da irgendwie trotzdem eine andere lösung besser ist lasse ich mich gerne darauf ein 👍



  • Und gerade getestet: ob mit oder ohne memmove: GetTickCount sagt 16ms von anfang bis ende der funktion ... ist also in dem fall wohl wirklich egal ... bisher habe ich auch nur bei Fax werte gesehen, die == 0 sind und daher ist das wohl eine ziemliche ausnahme ... alle anderen drucker haben keine 0 werte die ich aufgelistet habe



  • GetTickCount ist recht ungenau. Verwende lieber den Performance-Timer.



  • Solange die Funktion nicht extrem oft aufgerufen wird ist die Performance doch eh schnurz. Das sind ein paar Bytes die im RAM kopiert werden, da ist es sinnvoller dass der Code übersichtlich ist.


Log in to reply