# C: Datentausch bei enum und struct



## stift (27 April 2011)

hey, ich hab ein kleines projekt in C zu schreiben, komme aber überhaupt nicht weiter. Vielleicht hat von euch einer ne idee. 
Folgendes: 
Ich habe eine Enum am anfang definiert, welche in eine Struct eingebunden ist. Nun möchte ich zwei Werte über pointer miteinander tauschen. Dabei ist ein Datentyp teil der Enum, der andere ist Int. Kann ich die beiden datentypen irgenwie casten?


```
typedef enum {...} AUFZ;

typedef struct Table
{[INDENT]char ....
int Ergebnis
AUFZ Aufzählung 
[/INDENT]}

main(void)
AUFZ *pTemp
AUFZ *pAlt
AUFZ *pNeu

pAlt = &Table[i].Aufzählung
pNeu = &Table[i].Ergebnis 
(Hier ist das Problem; wenn ich den Pointer pNeu anders, also nich über geschenke definiere, dann habe ich das problem später, bei:)

pTemp = *pAlt;
*pAlt = *pNeu;
*pNeu = pTemp;
...
```
Hat einer ne idee? ich  bin seit zwei abenden am verzweifeln x)


----------



## Jochen Kühner (27 April 2011)

Also willst du einen int in enum casten?

Vielleicht hilft dir ein union weiter? http://de.wikibooks.org/wiki/C-Programmierung:_Komplexe_Datentypen#Unions

Edit: glaub das ist blödsinn was ich hier geschriben habe, blick nicht ganz was du machen willst!


----------



## Thomas_v2.1 (27 April 2011)

Irgendwie ist dein Beispiel-Code etwas konfus...
Aber mal angenommen du hast irgendwo nochmal Table als Array definiert und das typedef hat dann einen anderen Namen, könnte folgender Cast funktionieren:

```
pNeu = (AUFZ*)&Table[i].Ergebnis;
```
Es hängt aber vom Compiler und C-Standard ab, ob das Ergebnis dann definiert ist.


----------



## stift (2 Mai 2011)

ja, genau; 
thomas hat mein problem schon verstanden. 
einen array hab ich definiert - dummerweise aber vergessen ins forum reinzutippen - sorry

den fehler hab ich allerdings immer noch. 
ich hab die beiden pointer folgendermaßen definiert: 

```
pAlt = &Array[i].Gegenstand;
pNeu = (AUFZ*)&Array[i].iErgebnis;
```
Beim Tauschvorgang stürzt mein compiler allerdings jedes mal ab. 

```
*pTemp = *pAlt;
        *pAlt = *pNeu;
        *pNeu = *pTemp;
```


----------



## Rainer Hönle (2 Mai 2011)

Die Größe eines int muss nicht gleich der Größe einer enum sein. Dies kann natürlich zu einem Problem führen. Außerdem sehe ich nirgends, wo der Speicher allokiert wird. Ist dies in ausreichender Größe getan worden?
Was bedeutet "Compiler stürzt ab"? Welche Fehlermeldung gibt er aus? Erzeugt er einen BSOD? Oder läuft die Anwendung nicht? Gibt es in der Entwicklungsumgebung einen Ausnahmefehler?


----------



## Thomas_v2.1 (2 Mai 2011)

Zeig doch bitte mal einen compilierbaren Programmcode, und nicht immer solche Programmschnippsel die kein Compiler frisst.

Aber ich denke mal du hast da noch ein Problem mit den Zeigern:

```
AUFZ *pTemp; /* Variable für einen Zeiger auf den Typ AUFZ */
AUFZ *pAlt;  /* Variable für einen Zeiger auf den Typ AUFZ */
AUFZ *pNeu;  /* Variable für einen Zeiger auf den Typ AUFZ */
```
Damit legst du Variablen für einen Zeiger auf den Datentyp AUFZ an.

```
pAlt = &Array[i].Gegenstand;
pNeu = (AUFZ*)&Array[i].iErgebnis;
```

pAlt zeigt jetzt auf Array_.Gegenstand.
pNeu zeigt jetzt auf Array.iErgebnis.



		Code:
	

*pTemp = *pAlt;

Und hier versuchst du, der Variablen auf die pTemp zeigt den Wert zuzuweisen auf den pAlt zeigt. Und worauf zeigt pTemp?
Ich sehe zumindest keine Zuweisung.

Wenn du den Zeiger pTemp vorher nicht auf eine gültige Speicherstelle zeigen lässt, zeigt pTemp auf einen zufälligen (und aller Wahrscheinlichkeit nach) nicht gültigen Wert. Beim Zugriff auf diese Speicherstelle bekommst du unter einem Betriebssystem einen Speicherzugriffsfehler, bei einem Mikrocontroller ohne Betriebssystem zerschießt du dir deinen Speicher._


----------



## stift (2 Mai 2011)

danke schon mal euch beiden. 
den speicher habe ich noch nirgends allokiert. ich habe von malloc zwar mal was gelesen, habe allerdings nicht verstandent, was ich damit anfangen kann. 

ptemp soll eine zwischenvariable sein, da ich möchte, dass die inhalte von palt und pneu getauscht werden. 

das ganze is ne heimarbeit, für die uni. aber ich will ehrlich gesagt nicht, dass ihr mir was ausbessert und die sache läuft. 
wär cool, wenn ihr mir tipps geben könntet, damit ich nen ansatz habe und bisschen weiter komme aber dabei auch was lerne. 
damit habt ihr mir ja vor drei jahren in der sps-technik wahnsinnig viel beigebracht. 

Ziel der aufgabe ist, dass zwei studenten ihr geschenk tauschen. 
ein wichtelprogramm 
folgenden code habe ich geschrieben: 


```
/* Heimarbeit 5-3 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

 typedef enum {HOERBUCH,LEGOAUTO,DVD,BOOMERANG,JOJO,SPIELKARTEN} GESCHENKE;
    
typedef struct Table
{
    char szName[20];
    int iErgebnis;
    GESCHENKE Gegenstand;
};


main(void)
{
    struct Table Student[6];
    int i;
    char szGeschenk[12];
    GESCHENKE *pTemp=NULL;
    GESCHENKE *pAlt=NULL;
    GESCHENKE *pNeu=NULL;

    //Schleife der Namens- und Geschenkeingabe
    for(i=0; i<=1; i++)
    {
    printf("Bitte geben Sie den Namen des %i. Studenten ein:\n", i+1);
    scanf("%s", &Student[i].szName);

    printf("Bitte geben Sie das Geschenk des %i. Studenten ein:\n", i+1);
    scanf("%i", &Student[i].Gegenstand);
    }

    //Schleife zur Würfelergenisseingabe und Aufruf der Schleife zum Tauschvorgang
    for(i=0; i<=1; i++)
    {
        printf("%s wuerfelt: ", Student[i].szName);
        scanf("%i", &Student[i].iErgebnis);

        //Schleife zur Überprüfung korrekter Würfelergebnisse
        while (Student[i].iErgebnis<=0 || Student[i].iErgebnis>=7)
        {
            printf("Falscheingabe: Bitte noch einmal wuerfeln!\n");
            printf("%s wuerfelt: ", Student[i].szName);
            scanf("%i", &Student[i].iErgebnis);
        }

        //Tauschvorgang
        pAlt = &Student[i].Gegenstand;
        pNeu = (GESCHENKE*)&Student[i].iErgebnis-1;

        *pTemp = *pAlt;
        *pAlt = *pNeu;
        *pNeu = *pTemp;
        /////////////////////////////////////////////////////////////////////////////////
        
    }

    for(i=0; i<=1; i++)
    {
        switch (Student[i].Gegenstand){
            case 0: 
                strcpy(szGeschenk, "HOERBUCH");
                break;
            case 1:
                strcpy(szGeschenk, "LEGOAUTO");
                break;
            case 2:            
                strcpy(szGeschenk, "DVD");
                break;
            case 3:
                strcpy(szGeschenk, "BOOMERANG");
                break;
            case 4:
                strcpy(szGeschenk, "JOJO");
                break;
            case 5: 
                strcpy(szGeschenk, "SPIELKARTEN");
                break;
        }
        
        printf("%s: %s \n", Student[i].szName, szGeschenk);
    }

    return(0);
}
```


----------



## Thomas_v2.1 (2 Mai 2011)

Seltsames Programm ;-)

Aber schau die meinen Hinweise mit dem nicht initialisiertem pTemp an.
Das ist ein Grund warum es kracht.

In dein neues Programm hast du noch einen weiteren Fehler eingebaut:

```
pNeu = (GESCHENKE*)&Student[i].iErgebnis-1;
```
Was soll die -1 bewirken?
So wie du es dort geschrieben hast, wird der Zeiger pNeu auf die Adresse der Variablen "Student_.iErgebnis" minus 1 gesetzt.
Mal angenommen die Variable Student.iErgebnis liegt im Speicher an Byteadresse 1000. dann zeigt pNeu auf Speicherstelle 999. Und da willst du sicherlich nicht drauf zugreifen ;-)

Warum überhaupt der Umweg über Zeiger und keine direkte Zuweisung?_


----------



## stift (2 Mai 2011)

im anhang ein bild, wie das programm schlussendlich funktionieren soll. ich hab das ganze auch bereits hinbekommen, allerdings nicht über call by reference. und das ist teil der aufgabenstellung.


----------



## Thomas_v2.1 (2 Mai 2011)

stift schrieb:


> im anhang ein bild, wie das programm schlussendlich funktionieren soll. ich hab das ganze auch bereits hinbekommen, allerdings nicht über call by reference. und das ist teil der aufgabenstellung.



Mit Pointern zu arbeiten würde da aber nur Sinn ergeben, wenn man den Geschenketausch in eine eigene Funktion verlegen würde.

Als Anregung vielleicht so:

```
void geschenketausch(GESCHENKE *gesch, int *erg)
{
...
}
```

oder noch allgemeiner:

```
void geschenketausch(Table *student1, Table *student2)
{
...
}
```

Dann benötigt man auch diese Hilfsvariable als Zwischenspeicher, die aber kein Zeiger ist. Denn der Zeiger selber kann keinen Wert speichern sondern nur eine Adresse (Zeiger).


----------



## stift (2 Mai 2011)

soo, die anwendung läuft endlich. 

```
/* Heimarbeit 5-3 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

 typedef enum {HOERBUCH,LEGOAUTO,DVD,BOOMERANG,JOJO,SPIELKARTEN} GESCHENKE;
    
typedef struct Table
{
    char szName[20];
    int iErgebnis;
    GESCHENKE Gegenstand;
};
void Geschenktausch(GESCHENKE *Student1, GESCHENKE *Student2)
{
    GESCHENKE iTemp;
    iTemp = *Student1;
    *Student1 = *Student2;
    *Student2 = iTemp;
};


main(void)
{
    struct Table Student[6];
    int i;
    char szGeschenk[12];
    GESCHENKE *pAlt=NULL;
    GESCHENKE *pNeu=NULL;

    //Schleife der Namens- und Geschenkeingabe
    for(i=0; i<=5; i++)
    {
    printf("Bitte geben Sie den Namen des %i. Studenten ein:\n", i+1);
    scanf("%s", &Student[i].szName);

    printf("Bitte geben Sie das Geschenk des %i. Studenten ein:\n", i+1);
    scanf("%i", &Student[i].Gegenstand);
    }

    //Schleife zur Würfelergenisseingabe und Aufruf der Schleife zum Tauschvorgang
    for(i=0; i<=5; i++)
    {
        printf("%s wuerfelt: ", Student[i].szName);
        scanf("%i", &Student[i].iErgebnis);
        Student[i].iErgebnis= Student[i].iErgebnis-1;

        //Schleife zur Überprüfung korrekter Würfelergebnisse
        while (Student[i].iErgebnis<0 || Student[i].iErgebnis>5)
        {
            printf("Falscheingabe: Bitte noch einmal wuerfeln!\n");
            printf("%s wuerfelt: ", Student[i].szName);
            scanf("%i", &Student[i].iErgebnis);
            Student[i].iErgebnis= Student[i].iErgebnis-1;
        }

        //Tauschvorgang
        if (Student[i].iErgebnis == i)
             goto keinTausch;
        else
        Geschenktausch(&Student[i].Gegenstand, &Student[Student[i].iErgebnis].Gegenstand);
        keinTausch:;
    }

    for(i=0; i<=5; i++)
    {
        switch (Student[i].Gegenstand){
            case 0: 
                strcpy(szGeschenk, "HOERBUCH");
                break;
            case 1:
                strcpy(szGeschenk, "LEGOAUTO");
                break;
            case 2:            
                strcpy(szGeschenk, "DVD");
                break;
            case 3:
                strcpy(szGeschenk, "BOOMERANG");
                break;
            case 4:
                strcpy(szGeschenk, "JOJO");
                break;
            case 5: 
                strcpy(szGeschenk, "SPIELKARTEN");
                break;
        }
        
        printf("%s: %s \n", Student[i].szName, szGeschenk);
    }

    return(0);
}
```

ich habe es mit hilfe einer funktion gelöst, so wie du es angeregt hast. vielen dank. 
die zweite variante habe ich allerdings nicht hinbekommen, da ich schon wieder unverträgliche typen hatte, wegen der enum und der struct...
wie müsste ich da denn das ganze adressieren. hab es folgendermaßen versucht, wobei ich allerdings gleich in der zweiten zeile der funktion die genannten probleme hatte:

```
void Geschenktausch(struct Table*Student1, struct Table *Student2)
{
    int iTemp;
    iTemp = (*Table).Student1;
...
};
```

eine generelle frage habe ich allerdings noch. 
ich war immer der meinung, dass alle physikalischen adressen aus einer integer-zahl bestehen. warum habe ich dann immer diese probleme beim einsatz höherer datentypen? 
wenn ich einen pointer nutze, dann ist die adresse doch trotzdem eine ganzzahl, auch wenn ich dabei auf einen eigenen, höheren datentyp zugreife, oder?


----------



## Thomas_v2.1 (2 Mai 2011)

stift schrieb:


> die zweite variante habe ich allerdings nicht hinbekommen, da ich schon wieder unverträgliche typen hatte, wegen der enum und der struct...
> wie müsste ich da denn das ganze adressieren. hab es folgendermaßen versucht, wobei ich allerdings gleich in der zweiten zeile der funktion die genannten probleme hatte:
> 
> ```
> ...



Du musst auf das Strukturelement von Table passend zugreifen. Da der Zugriff auf Strukturen über Zeiger in C sehr häufig benötigt wird, hat man dafür den eigenen Operator -> eingeführt. Dann fällt der Dereferenzierungsoperator * weg.

Als Ansatz:

```
void Geschenktausch(struct Table*Student1, struct Table *Student2)
{
    GESCHENKE iTemp;
    iTemp = Student1->Gegenstand;
...
```



stift schrieb:


> eine generelle frage habe ich allerdings noch.
> ich war immer der meinung, dass alle physikalischen adressen aus einer integer-zahl bestehen. warum habe ich dann immer diese probleme beim einsatz höherer datentypen?
> wenn ich einen pointer nutze, dann ist die adresse doch trotzdem eine ganzzahl, auch wenn ich dabei auf einen eigenen, höheren datentyp zugreife, oder?



Der Compiler muss wissen auf welchen Datentyp der Zeiger zeigt. Ansonsten funktioniert die Pointerarithmetik nicht.
Z.B. wird ein int-Pointer
int *pInt;
mit pint++ um sizeof(int) hochgezählt, welches auf 32-Bit Rechnern meistens den Wert 4 hat.
Du könntest auch einen Zeiger auf deine Table anlegen.
Table *pTable;
Bei pTable++ wird dann der Zeiger um einen kompletten Struktursatz erhöht (20*sizeof(char) + sizeof(int) + sizeof(GESCHENKE)).


----------



## Thomas_v2.1 (2 Mai 2011)

Als Verfeinerung für deine switch-case Anweisung um die Geschenknamen auszugeben, kannst du einfacher folgendes machen:

```
const char *geschenknamen[7] = {"KEINS", "HOERBUCH", "LEGOAUTO", "DVD", "BOOMERANG", "JOJO", "SPIELKARTEN"};
```
Dann kannst du die Geschenknamen ohne switch-case direkt aus dem enum-index auslesen:

```
printf("Geschenk: %s", geschenknamen[Student[0].Gegenstand]);
```


----------



## stift (3 Mai 2011)

spitze, vielen dank für deine erklärungen. jetzt hab ich alles verstanden. 
auch das mit dem switch ist klasse. 

mir war die alte lösung auch zu umständlich, hab das letzte woche schon ma gegooglet und bin in irgend einem forum darauf gestoßen, dass es nicht möglich ist, das ganze ohne switch case zu machen 

nochmal danke


----------

