Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Hilfe bei Adressverwaltungsprogramm

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 <
010
16.07.2010, 18:57 Uhr
0xdeadbeef
Gott
(Operator)


Naja, solange die einzelnen Felder eh immer die gleiche Länge haben, kann man zumindest Adresse so umstellen, dass ein großer Teil der Speicherverwaltung entfällt:

C++:
struct Adresse
{
    char name   [80];
    // Sonderzeichen in Bezeichnern besser vermeiden,
    // das frisst nicht jeder Compiler.
    char strasse[80];
    char stadt  [80];
};


Natürlich musst du dann aber trotzdem noch darauf achten, dass du nicht über das Ende des Buffers hinausschreibst. Das bedeutet insbesondere: kein gets mehr, und kein strcpy, wenn du nicht sicher bist, dass die Eingabedaten in den Ausgabebuffer passen. In der C-Bibliothek gibt es fgets und strncpy, die die Länge des Buffers berücksichtigen; das wäre ein direkter Ersatz. In der C++-Standardbibliothek bieten sich std::istream::getline und std::copy an, aber wenn du schon std::strings ablehnst...
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 16.07.2010 um 18:58 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
23.07.2010, 15:14 Uhr
ganandoor56



Hallo,

ich würde würde gerne erstmal nach dem Guide arbeiten. Ansonsten werde ich bestimmt durcheinander kommen. Aber das mit dem std::xy verstehe ich allmählich. Aber ich weiß jetzt nicht den gravierenden Unterschied von dem und "using namespaße std;".

Aber ich habe immer noch Probleme mit der Aufgabe.
Mein momentaner Code:

C++:
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <string.h>
using namespace std;

struct Adresse
{
    char *name;
    char *straße;
    char *stadt;
};

Adresse* useradressen = new Adresse[1];

int i;
int eingabe = 0, eingabe1 = 0, eingabe2 = 0;
char* name = new char [40];
char auswahl;
int j = 1;

void main (void)
{
for(i = 0; i < j; i++)
{
    useradressen[i].name    = new char[80];
    useradressen[i].straße  = new char[80];
    useradressen[i].stadt   = new char[80];
}
for ( i = 0; i < j; i++ )
{
strcpy(useradressen[i].name, "");
strcpy(useradressen[i].straße, "");
strcpy(useradressen[i].stadt, "");
}
do
{
cout << "Drücken Sie '1'Adresse einzugeben, '2'anschauen, '3'Daten zu ändern, '4'Daten löschen, '5'alle Adressen anzeigen, '6'suchen:" << endl;
cin >> eingabe;

if (eingabe == 1)
{
    for ( i = 0; i < j; i++)
        {
            j = j + 1;
            if (strcmp (useradressen[i].name, "") == 0)
            {    
                cout << i << " ist noch leer. " << endl;

                getchar();
                cout << "Bitte geben Sie ihren Namen ein:" << endl;
                gets (useradressen[i].name);

                cout << "Bitte geben Sie ihre Straße ein:" << endl;
                gets (useradressen[i].straße);

                cout << "Bitte geben Sie ihr Wohnort ein:" << endl;
                gets (useradressen[i].stadt);

                cout << "Deine Adresse lautet:" << endl;
                cout << useradressen[i].name    << endl;
                cout << useradressen[i].straße  << endl;
                cout << useradressen[i].stadt   << endl;
                break;

            }        
        }
}
}


Ich weiß einfach nicht wie ich den Speicher für die nächsten Adresssätze erhöhen soll.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
23.07.2010, 16:00 Uhr
0xdeadbeef
Gott
(Operator)


Neuen Speicher anfordern, Inhalt des alten in den neuen kopieren, alten Speicher freigeben. Die naivste Möglichkeit hier wäre

C++:
// neuen Speicher anfordern
Adresse *ua_neu = new Adressen[j + 1];

// alten Speicher in neuen kopieren
std::copy(useradressen, useradressen + j, ua_neu);

// Alten Speicher freigeben, Zeiger umhängen
delete[] useradressen;
useradressen = ua_neu;
++j;


...wobei das natürlich höchst ineffizient ist. Wenn man so etwas tatsächlich von Hand macht, hält man sich üblicherweise neben der Größe des belegten Inhalts noch vor, wie viel Speicher man noch übrig hat und alloziiert blockweise mehr Speicher - dann muss man sehr viel seltener hin- und herkopieren.

Übrigens geht das so einfach nur mit einfachen Datentypen. Spätestens, wenn deine Klasse nicht Assignable oder Default-Constructible ist, musst du auf placement-new und std::uninitialized_copy zurückgreifen, was dann richtig haarig wird (insbesondere mit Exceptions). Üblicherweise überlässt man das ganze deswegen std::vector (oder einem anderen Container).
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
27.07.2010, 10:47 Uhr
ganandoor56



Hallo Oxdeadbeef,

ich danke dir für deine Hilfe!
Ich muss schon sagen, dass das Thema Zeiger recht schwer ist. Ich hoffe, dass ich da durch komme.

Jedenfalls sieht mein Code momentan so aus:

C++:
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <string.h>
using namespace std;

struct Adresse
{
    char *name;
    char *straße;
    char *stadt;
};

Adresse* useradressen = new Adresse[1];

int i;
int eingabe = 0, eingabe1 = 0, eingabe2 = 0;
char* name = new char [40];
char auswahl;
int j = 1;

void main (void)
{
for(i = 0; i < j; i++)
{
    useradressen[i].name    = new char[80];
    useradressen[i].straße  = new char[80];
    useradressen[i].stadt   = new char[80];
}
for ( i = 0; i < j; i++ )
{
    strcpy(useradressen[i].name, "");
    strcpy(useradressen[i].straße, "");
    strcpy(useradressen[i].stadt, "");
}

do
{
cout << "Drücken Sie '1'Adresse einzugeben, '2'anschauen, '3'Daten zu ändern, '4'Daten löschen, '5'alle Adressen anzeigen, '6'suchen:" << endl;
cin >> eingabe;

if (eingabe == 1)
{
    for ( i = 0; i < j; i++)
        {    
            if (strcmp (useradressen[i].name, "") == 0)
            {    
                cout << i << " ist noch leer. " << endl;

                getchar();
                cout << "Bitte geben Sie ihren Namen ein:" << endl;
                gets (useradressen[i].name);

                cout << "Bitte geben Sie ihre Straße ein:" << endl;
                gets (useradressen[i].straße);

                cout << "Bitte geben Sie ihr Wohnort ein:" << endl;
                gets (useradressen[i].stadt);

                cout << "Deine Adresse lautet:" << endl;
                cout << useradressen[i].name    << endl;
                cout << useradressen[i].straße  << endl;
                cout << useradressen[i].stadt   << endl;
                
                Adresse* ua_neu = new Adresse[j+1];
                for (i = 0; i < j+1; i++)
                {
                    ua_neu[i].name = new char[80];
                    ua_neu[i].straße = new char[80];
                    ua_neu[i].stadt = new char[80];
                }
                for (i = 0; i < j+1; i++)
                {    
                    strcpy(ua_neu[i].name, "");
                    strcpy(ua_neu[i].straße, "");
                    strcpy(ua_neu[i].stadt, "");
                }
                std::copy(useradressen, useradressen + j, ua_neu);
                delete[]useradressen;
                useradressen = ua_neu;
                j++;
                break;
            }
        }
}

//Ausgabe
else if ( eingabe == 5 )
{
    for( i = 0; i < j; i++ )
    {
        cout << ">>" << i << endl;
        cout << useradressen[i].name << endl;
        cout << useradressen[i].straße << endl;
        cout << useradressen[i].stadt << endl;
        }
}
}


Leider habe ich jetzt das Problem, dass wenn ich alle eingegebenen Adresse ausgeben möchte kommt da immer eine leere Adresse dazu. Liegt es vielleicht daran, dass ich die Variable j mit 1 versehen habe?


Freundliche Grüße, Fin
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
27.07.2010, 13:26 Uhr
0xdeadbeef
Gott
(Operator)


Au weia, das leckt so jede Menge Speicher.

Also, Zeiger sind im Grunde ziemlich simpel - ein Zeiger zeigt. Man kann ihn irgendwohin zeigen lassen und nachkucken was da steht, wo er hin zeigt (und in der Umgebung). Was dir hier Knüppel zwischen die Beine wirft, ist Speicherverwaltung.

Was du mit new anforderst, musst du mit delete wieder freigeben. Was du mit new[] anforderst, musst du mit delete[] wieder freigeben. Du solltest also höllisch aufpassen, dass du keinen Speicher verlierst. Hier:

C++:
                Adresse* ua_neu = new Adresse[j+1];
                for (i = 0; i < j+1; i++)
                {
                    ua_neu[i].name = new char[80];
                    ua_neu[i].straße = new char[80];
                    ua_neu[i].stadt = new char[80];
                }
                for (i = 0; i < j+1; i++)
                {    
                    strcpy(ua_neu[i].name, "");
                    strcpy(ua_neu[i].straße, "");
                    strcpy(ua_neu[i].stadt, "");
                }
                std::copy(useradressen, useradressen + j, ua_neu);
                delete[]useradressen;
                useradressen = ua_neu;
                j++;


verlierst du eine Menge Speicher, weil du erst Speicheradressen in ua_neu speicherst und sie dann sofort wieder mit den alten aus useradressen überschreibst. Das einzige, was davon bleibt, ist ua_neu[j]. So könnte man es machen:

C++:
                Adresse* ua_neu = new Adresse[j+1];

                std::copy(useradressen, useradressen + j, ua_neu);
                delete[] useradressen;
                useradressen = ua_neu;

                ua_neu[j].name = new char[80];
                ua_neu[j].straße = new char[80];
                ua_neu[j].stadt = new char[80];
                strcpy(ua_neu[j].name, "");
                strcpy(ua_neu[j].straße, "");
                strcpy(ua_neu[j].stadt, "");

                j++;


...und du musst natürlich am Ende den Inhalt und useradressen auch freigeben. Habt ihr Konstruktoren und Destruktoren schon behandelt? Damit könnte man das nämlich deutlich besser organisieren.

Übrigens:

C++:
void main(void)


hauen dir die meisten C++-Compiler um die Ohren (die Form ist im Standard explizit verboten - main muss int zurückgeben). Soweit ich weiß, akzeptiert das heute nur noch MSVC aus Gründen der Abwärtskompatibilität mit Vorstandardcompilern. Ich weiß nicht, woher du diese Form hast, aber gewöhn sie dir ganz schnell wieder ab und such dir eine bessere (neuere) Lernquelle.

Der Hintergrund dabei ist, dass der Rückgabewert eines Programms von der umgebenden Shell ausgewertet werden kann. Ein Shellskript kann etwa etwas derartiges enthalten:

C++:
if programm; then
  echo "Alles gut!"
else
  echo "Ja scheiße, was mach ich jetzt?"
fi


bzw. eine Batch-Datei

C++:
programm
if errorlevel 0 goto allesgut
  echo "Ja scheiße, was mach ich jetzt?"
goto ende
:allesgut
  echo "Alles gut!"
:ende


Per Konvention bedeutet ein Rückgabewert von 0, dass alles gut gelaufen ist, alles andere wird als Fehlercode verstanden. Deshalb gibt es für main auch die Sonderregelung, dass, wenn kein return-Statement durchlaufen wird, 0 zurückgegeben wird. Das gilt aber nur für main! Nicht, dass du dich nachher für andere int-Funktionen darauf verlässt.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 <     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: