Programm



  • So, Hier die Version, die die Werte aus einer Textdatei datei.txt einliest:
    (Auf das Abfangen eventueller Fehler habe ich mal verzichtet.)

    #include <string>
    #include <iostream>
    #include <fstream>
    using namespace std;
    
    struct SElem
    {
    string Artikelnummer;
    string Lagernummer;
    }*Elemente;
    
    int main()
    {
    	ifstream dat_ein;
    	dat_ein.open("datei.txt",ios_base::in);
    	int Anzahl;
    	dat_ein >> Anzahl;
    	Elemente = new SElem[Anzahl];
    
    	for(int loop=0;loop<Anzahl;loop++)
    	{
    		dat_ein >> Elemente[loop].Artikelnummer;
    		dat_ein >> Elemente[loop].Lagernummer;
    	}
    
    	dat_ein.close();
    
    	string ArtNum;
    	bool found = false;
    	cout << "Artikelnummer: ";cin >> ArtNum;
    	cout << "Lagernummer: ";
    
    	for(int loop=0;loop<Anzahl;loop++)
    	{
    		if(Elemente[loop].Artikelnummer==ArtNum)
    		{
    			cout << Elemente[loop].Lagernummer;
    			found = true;
    			break;
    		}
    	}
    	if(found==false)cout << "(nicht gefunden)" << endl;
    	cin.get();
        delete[] Elemente;
    	return 0;
    }
    

    Der Inhalt der Datei:

    3
    105-10-2467.5	2117
    108-48-4757.8	3456
    140-47-4564.2	4567
    

    Die erste Zahl in der Textdatei zeigt dem Programm, wie viele Datensätze in der Datei enthalten sind. Danach kommen die Daten: Erst die Artikelnummer, dann die Lagernummer.

    MfG, Jochen


  • Mod

    Noch besser wäre es natürlich, wenn in der Textdatei gar nicht drinstehen muss, wieviele Datensätze es gibt. Das wäre nämlich ein extrem unpraktisches Dateiformat, wenn man beim zufügen von Datensätzen an zwei Stellen etwas ändern muss. Und noch schlimmer wäre es, wenn man Datensätze entfernt aber vergisst die erste Zeile zu ändern.

    Wie das genau geht, überlasse ich mal interessierten Lesern als Übung. Ist ganz einfach.



  • Hi Jochen. Habe ein ähnliches Prog. Aber wo speicher ich die datei.txt mit den infos ab? Muss ich nicht irgendwo einen Pfad angeben?

    MFG



  • Hallo,
    Die Datei datei.txt muss sich in dem selben Ordner befinden wie das Programm. Sollte sich die Datei sonstwo befinden, muss man natürlich noch einen Pfad mit angeben.

    MfG, Jochen



  • So, hier ist noch das Programm, das von SeppJ bevorzugt werden würde:

    #include <string>
    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    
    struct SElem
    {
    string Artikelnummer;
    string Lagernummer;
    };
    
    int main()
    {
    	ifstream dat_ein;
    	dat_ein.open("datei.txt",ios_base::in);
    
    	vector<SElem> Elemente;
    
    	while(!dat_ein.eof())
    	{
    		SElem tmp;
    		dat_ein >> tmp.Artikelnummer;
    		dat_ein >> tmp.Lagernummer;
    		Elemente.push_back(tmp);
    	}
    
    	int Anzahl = Elemente.size();
    
    	dat_ein.close();
    
    	string ArtNum;
    	bool found = false;
    	cout << "Artikelnummer: ";cin >> ArtNum;
    	cout << "Lagernummer: ";
    
    	for(int loop=0;loop<Anzahl;loop++)
    	{
    		if(Elemente[loop].Artikelnummer==ArtNum)
    		{
    			cout << Elemente[loop].Lagernummer;
    			found = true;
    			break;
    		}
    	}
    	if(found==false)cout << "(nicht gefunden)" << endl;
    	cin.get();
    	for(int loop=0;loop<Anzahl;loop++)Elemente.erase(0);
    	return 0;
    }
    

    Der Inhalt der Datei müsste jetzt so aussehen:
    (So wie vorher, nur ohne die errste Zeile)

    105-10-2467.5	2117
    108-48-4757.8	3456
    140-47-4564.2	4567
    

    Stimmt, die Lösung ist schöner. Ich weiss zwar nicht, wie vector intern arbeitet, aber führt das nicht zu einer starken Heapfragmentierung, wenn immer Speicher für ein weiteres Element reserviert werden muss, wenn ein neues Element hinzugefügt wird?

    MfG, Jochen



  • Ich weiss zwar nicht, wie vector intern arbeitet

    http://www.sgi.com/tech/stl/Vector.html

    [3] When it is necessary to increase capacity(), vector usually increases it by a factor of two. It is crucial that the amount of growth is proportional to the current capacity(), rather than a fixed constant: in the former case inserting a series of elements into a vector is a linear time operation, and in the latter case it is quadratic.

    Und ueber Fragmentierung rede ich erst, wenn viel Speicher benoetigt wird. Desweiteren kann das Suchen auch beim Einlesen der Elemente stattfinden, dann spart man sich das Array. Auch das manuelle Loeschen der Elemente am Ende ist ueberfluessig, das passiert automatisch, wenn der Destruktor von std::vector aufgerufen wird. Ich weiss jetzt nicht genau, was erase macht, aber wenn von vorn geloescht wird, dann muss der restliche Inhalt staendig um eins nach vorne kopiert werden. Besser man beginnt hinten ...



  • Stimmt, das mit dem löschen ist nicht ganz so optimal. Noch einfacher ist es, wenn man gleich den Destruktor "manuell" aufruft. Oder sehe ich da etwas falsch?


  • Mod

    Jochen S. schrieb:

    Stimmt, das mit dem löschen ist nicht ganz so optimal. Noch einfacher ist es, wenn man gleich den Destruktor "manuell" aufruft. Oder sehe ich da etwas falsch?

    Faustregel: Man ruft NIEMALS Destruktoren manuell auf. Destruktoren werden automatisch aufgerufen, wenn der Programmfluss den Gültigkeitsbereich eines Objekts verlässt.



  • Jochen S. schrieb:

    Noch einfacher ist es, wenn man gleich den Destruktor "manuell" aufruft.

    Das will ich sehen! :p



  • _matze schrieb:

    Jochen S. schrieb:

    Noch einfacher ist es, wenn man gleich den Destruktor "manuell" aufruft.

    Das will ich sehen! :p

    Probiers aus. Es ruft den Destruktor auf, aber das Objekt ist weiterhin zugänglich.

    class MyClass
    {
    public:
    	MyClass() { std::cout << "Objekt erstellt" << std::endl ; }
    	~MyClass() { std::cout << "Objekt gelöscht" << std::endl ; }
    	void DoSomething() { std::cout << "Objekt ruft DoSomething() auf" << std::endl ; }
    };
    
    int main ( )
    {
    	MyClass Obj ;
    	Obj.~MyClass();
    	Obj.DoSomething() ;
    }
    


  • Gut, bei solch einer Klasse mag das ja funktionieren. Wenn du aber irgendwo Speicher reservierst (was ja auch vector tut) und diesem im Destruktor freigibst, kannst du nicht mehr ohne weiteres mit den Objekt arbeiten. Und knivil sagte, dass der Speicher im Destruktor von vector freigegben wird:

    knivil schrieb:

    Auch das manuelle Loeschen der Elemente am Ende ist ueberfluessig, das passiert automatisch, wenn der Destruktor von std::vector aufgerufen wird.

    Da dachte ich, dass man ja auch den Destruktor manuell aufrufen könne. In dem Fall würde also tatsächlich der Speicher freigegeben. Ein Weiterarbeiten mit dem Objekt wäre in dem Falle nicht mehr möglich.



  • Jochen S. schrieb:

    Ein Weiterarbeiten mit dem Objekt wäre in dem Falle nicht mehr möglich.

    Doch, aber mit undefiniertem Verhalten zur Laufzeit. Und das ist ja das Schlimme. pumuckl hat völlig Recht. Ausser bei seltenen Spezialfällen, wenn man auch Placement New verwendet, ruft man nie Destruktoren manuell auf. Entweder wird das Objekt über delete oder automatisch zerstört.

    Falls man vorzeitig den Speicher freigeben möchte, was meistens keine gute Idee ist, kann man immer noch den swap() -Trick anwenden:

    std::vector().swap(my_vector);
    

    Übrigens: Äusserst kreativer Threadtitel. 🤡



  • servus jungs. 👍

    ich muss zugeben ich bin sprachlos, und irgendwie ist das mir auch ein wenig zu hoch geworden 😞 ich kenn micht nicht mehr aus.
    Würde dieses Programm gern lauffähig machen. beim ausführen bekomme ich immer diese Fehlermeldung:

    Kompilierung läuft...
    Lagersystem.cpp
    C:\Dokumente und Einstellungen\Markus\Desktop\Lagersystem\Lagersystem.cpp(48) : error C2374: 'loop' : Neudefinition; Mehrfachinitialisierung
    C:\Dokumente und Einstellungen\Markus\Desktop\Lagersystem\Lagersystem.cpp(37) : Siehe Deklaration von 'loop'
    Fehler beim Ausführen von cl.exe.
    EInlaufkurven.obj - 1 Fehler, 0 Warnung(en)

    bin ratlos!!!!!!!!!!!!!
    Hab ich aber das Prinzip schon richtig geschnallt, dass die 2 Lösung besser auf Änderungen in der Liste reagiert. dh. wenn zb. eine neue art.nummer + Lagernummer hinzukommt,könnte ich die einfach dahinter anreihen.
    Beim nächsten ausführen wird diese Zahl mit ins prog integriert.!!!!!??????

    Gruss



  • Zeig doch mal, wie dein aktueller Code aussieht. Das ist ein eher kleiner Fehler, den du da bekommst.



  • Hallo,
    Hast Du etwas an dem Quelltext geändert? Bei mir lässt sich das Programm ohne Fehler kompilieren. Ich weiss ja nicht, welchen Compiler du benutzt, aber eigentlich dürfte es keinen Compiler geben, der den Code nicht kompiliert.
    Was du tun könntest, wäre folgendes:
    Du deklarierst loop gleich am Anfang von main() :

    int main()
    {
    int loop;
    // ... 
    }
    

    In den For-Schleifen müsstest du dann immer anstatt int loop = ... einfach nur loop = ... schreiben. Aber für konkrete Vorschläge müsste ich Einsicht in den Quelltext haben.

    MfG, Jochen



  • habs jetzt mal so gemacht wie dus im vorherigen beitrag geschrieben hast:

    #include <string>
    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;

    struct SElem
    {
    string Artikelnummer;
    string Lagernummer;
    };

    int main()
    {
    int loop;
    ifstream dat_ein;
    dat_ein.open("datei.txt",ios_base::in);

    vector<SElem> Elemente;

    while(!dat_ein.eof())
    {
    SElem tmp;
    dat_ein >> tmp.Artikelnummer;
    dat_ein >> tmp.Lagernummer;
    Elemente.push_back(tmp);
    }

    int Anzahl = Elemente.size();

    dat_ein.close();

    string ArtNum;
    bool found = false;
    cout << "Artikelnummer: ";cin >> ArtNum;
    cout << "Lagernummer: ";

    for(loop=0;loop<Anzahl;loop++)
    {
    if(Elemente[loop].Artikelnummer==ArtNum)
    {
    cout << Elemente[loop].Lagernummer;
    found = true;
    break;
    }
    }
    if(found==false)cout << "(nicht gefunden)" << endl;
    cin.get();
    for(loop=0;loop<Anzahl;loop++)Elemente.erase(0);
    return 0;
    }

    Das kompilieren funktioniert ohne fehler. beim anschließenden ausführen erscheint folgende fehlermeldung.

    --------------------Konfiguration: test - Win32 Debug--------------------
    Kompilierung läuft...
    test.cpp
    C:\Dokumente und Einstellungen\Markus\Desktop\test\test.cpp(48) : error C2374: 'loop' : Neudefinition; Mehrfachinitialisierung
    C:\Dokumente und Einstellungen\Markus\Desktop\test\test.cpp(37) : Siehe Deklaration von 'loop'
    Fehler beim Ausführen von cl.exe.

    test.exe - 1 Fehler, 0 Warnung(en)



  • Also, ich hab jetzt mal den Quelltext kopiert. Liess sich porblemlos kompilieren. Was hast du denn für einen Compiler? Ich bin jetzt etwas ratlos, aber du könntest ja mal versuchen, für jede Schleife eine andere Schleifenvariable zu nehmen, also:

    erste Schleife: for(int loop1=0;...)
    zweite Schleife: for(int loop2=0;...)
    ...
    Nicht vergessen, dann auch in der Schleife die anderen Variablen zu nehmen.
    Mal sehen, vielleicht klappt es dann.
    Was du noch machen solltest:
    Entferne die Schleife zwischen cin.get(); und return 0; am Ende de Programms.
    Bei mir hängt sich das Prgramm in dieser Schleife immer auf.

    MfG, Jochen



  • jetzt funktionierts. Habs einfach nochmal ganz neu gemacht.Habe noch einige Fragen dazu:

    -Woher weiss denn das Programm das sich erste Spalte in der datei.txt sich auf die Artikelnummer bezieht.

    - was wäre wenn die Lagernummer auch buchstaben enthalten würde. Müsste ja irgendwo deklariert werden oder???

    -ist ein Einbezug mit einer anderen datei auch möglich. zb. excel datei??

    -wie würde sich das Programm ändern wenn ich zb. noch eine dritte oder sogar eine 4. Info dazuhaben möchte. zb. Anzahl und Artikelbeschreibung



  • So, ich versuche mal, deine Fragen zu beantworten.

    Zur ersten Frage:

    SElem tmp;
    dat_ein >> tmp.Artikelnummer;
    dat_ein >> tmp.Lagernummer;
    Elemente.push_back(tmp);
    

    Das Programm liest immer zwei strings hintereinander ein, die durch Leerzeichen, Tabulatoren, Zeilenumbrüche etc. getrennt sind. Den ersten string sieht das Programm dabei als Artikelnummer an, den zweiten als Lagernummer. Die beiden strings werden in die jeweiligen Elemente der Struktur gespeichert und in den vector Elemente aufgenommen. Dies wird solange gemacht, wie die Bedingung !dat_ein.eof() erfüllt ist. (Also solange, wie das Programm Datensätze findet.) Artikelnummern und Lagernummern wechseln sich in der Datei beginnend mit der Artikelnummer ab.

    Zur zweiten Frage:
    Du kannst in der Artikelnummer sowohl Zahlen als auch Buchstaben verwenden, da strings sowohl zahlen als auch Buchstaben enhalten können (Wäre ja sinnlos, wenn sie es nicht könnten). Eine Anpassung des Programms ist also nicht erforderlich. Allerdings musst du, wenn du Buchstaben verwendest, eventuell Groß/Kleinschreibung beachten.

    Zur dritten Frage:
    Da Excel-Dateien anders aufgebaut sind als die Textdateien, die dieses Programm erwartet, ist es mit diesem Programm nicht möglich, Excel-Dateien auszuwerten. Zu diesem Zweck müsste das Programm modifiziert werden.

    Zur vierten Frage:
    Du müsstest der Struktur SElem noch zwei weitere Elemente hinzufügen, sodass die Struktur in etwa so aussieht:

    struct SElem
    {
    string Artikelnummer;
    string Lagernummer;
    int Anzahl;
    string Beschreibung;
    };
    

    Der Code zum Einlesen der Datensätze müsste dann so aussehen:

    SElem tmp;
    dat_ein >> tmp.Artikelnummer;
    dat_ein >> tmp.Lagernummer;
    dat_ein >> tmp.Anzahl;
    getline(dat_ein,tmp.Beschreibung);
    Elemente.push_back(tmp);
    

    Auch die Ausgabe muss so angepasst werden, dass das Programm auch die neuen Informationen anzeigt.

    Hier nochmal das angepasste Programm:

    #include <string>
    #include <iostream>
    #include <fstream>
    #include <vector>
    using namespace std;
    
    struct SElem
    {
    string Artikelnummer;
    string Lagernummer;
    int Anzahl;
    string Beschreibung;
    };
    
    int main()
    {
    ifstream dat_ein;
    dat_ein.open("datei.txt",ios_base::in);
    
    vector<SElem> Elemente;
    
    while(!dat_ein.eof())
    {
    SElem tmp;
    dat_ein >> tmp.Artikelnummer;
    dat_ein >> tmp.Lagernummer;
    dat_ein >> tmp.Anzahl;
    getline(dat_ein,tmp.Beschreibung);
    Elemente.push_back(tmp);
    }
    
    int Anzahl = Elemente.size();
    
    dat_ein.close();
    
    string ArtNum;
    bool found = false;
    cout << "Artikelnummer: ";cin >> ArtNum;
    
    for(int loop1=0;loop1<Anzahl;loop1++)
    {
    if(Elemente[loop1].Artikelnummer==ArtNum)
    {
    cout << "Lagernummer\t: " << Elemente[loop1].Lagernummer << endl;
    cout << "Anzahl\t\t: "    << Elemente[loop1].Anzahl << endl;
    cout << "Lagernummer\t:" << Elemente[loop1].Beschreibung << endl;
    found = true;
    break;
    }
    }
    if(found==false)cout << "(Keine Informationen gefunden)" << endl;
    cin.get();
    return 0;
    }
    

    Der Inhalt von Datei.txt lautet nun:

    105-10-2467.5	2117   3 Dies ist eine Produktbeschreibung.
    108-48-4757.8	3456   7 Das ist auch eine Produktbeschreibung
    140-47-4564.2	4567   5 Das hier ist Produnkt nummer Drei
    

    Die Datei ist so aufgebaut:
    Artikelnummer1 Lagernummer1 Anzahl1 (Rest der Zeile Produktbeschreibung1)
    Artikelnummer2 Lagernummer2 Anzahl2 (Rest der Zeile Produktbeschreibung2)
    Artikelnummer3 Lagernummer3 Anzahl3 (Rest der Zeile Produktbeschreibung3)
    ...

    Ich hoffe, meine Erklärungen sind hilfreich.

    MfG, Jochen



  • FreakY<3Cpp schrieb:

    Mach aus dem double ein string.
    Dann meinst du, du hast 100 Artikelnummer und dazu passende Lagernummer, da würd ich wohl map empfehlen.
    Und dann noch etwas ganz schlaggebendes
    ES GIBT KEINE IF-SCHLEIFEN!!!

    doch gibt es
    und zwar werden solche konstruktionen if schleifen genannt:

    int main()
    {
    punkt:
       if ( 0 == 0 )
           goto punkt;
    }
    

    das prinzip sollte klar sein, ich weiss nicht obs syntaktisch richtig ist, hab goto nie gelernt (wieso auch xD)


Anmelden zum Antworten