Array vom Typ struct an Funktion in anderem .cpp File übergeben



  • Hi Leute,

    ich mache gerade ein paar Übungsaufgaben aus einem Buch und bin auf folgendes Problem gestoßen. Ich habe in meiner main.cpp eine Struktur angelegt und mit dieser ein zweidimensionales Array erzeugt. Nun möchte ich dieses Array vom typ struct eben an eine ausgelagerte Funktion übergeben (per Pointer), die sich in einem anderen .cpp File befindet. Ich vermute in der main.cpp Datei kann ich da einfach über den Namen des Arrays und den Addressoperator gehen. Allerdings weiß ich nicht wie das in der anderen Datei und dem zugehörigen Header aussehen soll. Ich kann in beiden logischerweiße nicht angeben, dass als Argument etwas vom Datentyp meiner Struktur übergeben wird, da das Programm diese ja nur in der main kennt.
    Muss ich die Struktur um das zu lösen zwingend global Deklarieren oder geht das auch anderst? Um es etwas nachvollziehbarer zu machen hier ein Ausschnitt aus dem Code:

    ...
    int main()
    {
    	int Auswahl=0, i=0, j=0;
    
    	const int Breite = 5;
    	const int Hoehe = 5;
    
    	struct feld
    	{
    		bool status; // 0 = Unbesetzt, 1 = Besetzt
    		char name[10];
    	};
    
    	struct feld Spielfeld[Breite][Hoehe];
    
    	// Grundzustand des Spielfeldes herstellen
    	for(i=0; i<Hoehe; i++)
    	{
    		for(j=0; j<Breite; j++)
    		{
    			Spielfeld[i][j].status = false;
    			strcpy(Spielfeld[i][j].name, "Leer");
    		}
    	}
    
    	menue(&Auswahl);
    
    	if(Auswahl == 1)
    	{
    		auswahl_eins(&Spielfeld);     //??? Funktionsaufruf so OK? ???
    	}
    
    	if(Auswahl == 2)
    ...
    

    Und das zugehörige .cpp File der Funktio:

    ...
    #include<iostream>
    #include "auswahl_eins.h"
    
    using namespace std;
    
    void auswahl_eins(Spielfeld)      //????? Inhalt der Klammer  ????? 
    {
    	return;
    }
    ...
    

    Mfg


  • Mod

    Edit: Alles falsch.



  • Arcoth schrieb:

    Die Funktion kann offensichtlich nichts mit den Membern der Klasse anfangen da sie die Klasse selbst nicht kennen kann. Möglich wäre ein Funktionstemplate dass sich auf keinen festen Typ beschränkt und einfach erwartet dass bestimmte Member vorhanden sind.

    template <typename T, std::size_t Breite, std::size_t Hoehe>
    void auswahl_eins(T (&arr)[Breite][Hoehe])
    {
        // […]
    }
    
    // main.cpp - Aufruf
    auswahl_eins(Spielfeld);
    

    Wirklich? Du kommst erst mit sowas und dann erst mit der offensichtlichen Lösung zum Kentnissstand des TE?

    EDIT: ja ja, ninja edit nach ninja edit 😛


  • Mod

    @Tim: Ist ja schon korrigiert.

    ja ja, ninja edit nach ninja edit 😛

    Übereifer bringt nunmal Patzer und Unstrukturiertheit mit sich 😉

    Edit: Der Rest war natürlich auch falsch, Zeiger auf zweidimensionale Arrays macht man anders.



  • Ein C++ Buch, das dir strcpy und struct feld Spielfeld ... beibringt, solltest du ganz schnell im Altpapiercontainer entsorgen.



  • Danke für die Antworten 🙂
    Ich habe mich (da ich C++ erst im nächsten Semester habe und in dem Bereich sehr wenig Erfahrung hab) für die Header Lösung entschieden. Das ist das erste mal, dass ich eine Struktur im Header deklariere, deshalb frag ich besser nochmal nach...würde das dann ca. so aussehen:

    #ifndef AUSWAHL_EINS_H_
    #define AUSWAHL_EINS_H_
    
    void auswahl_eins(struct feld*);
    
    struct feld
    {
    	bool status; // 0 = Unbesetzt, 1 = Besetzt
    	char name[10];
    };
    
    #endif
    

    Aufruf in main:

    if(Auswahl == 1)
    {
    	auswahl_eins(&Spielfeld[Breite][Hoehe]);
    }
    

    Irgendwie krieg ich nämlich immernoch nen Error...Er unterstreicht (In Visual Studio 2010) das & Im Argument vom Funktionsaufruf in main und sagt mir "Error: Das Argument vom Typ ""feld*"" ist mit dem Parameter vom Typ ""feld*"" inkompatibel." 😕

    @manni66
    Das ist nicht die Buchlösung oder so ähnlich sondern auf meinem Mist gewachsen, ich probiere nur ein bisschen aus (bin kein Berufsprogrammierer oder so, will nur besser werden 😉 ). Aber in diesem Zusammenhang würde mich natürlich direkt interressieren was daran schlecht ist / stört? Bei dem "struct feld Spielfeld" vermute ich, dass dich die alte C-Schreibweise stört, anstelle von C++? ->Dem bin ich mir bewusst.
    Was ist an strcpy nicht gut?


  • Mod

    Du musst dich entscheiden ob du innerhalb auswahl_eins das Array als ein eindimensionales oder zweidimensionales anfassen willst. Bei letzterem muss die Hoehe bekannt sein:

    void auswahl_eins( feld ptr[5][5] ); // magische Konstanten wie diese sind zu vermeiden.
    
    // bzw. äquivalent dazu, da Arrays als Funktionsparameter zu Zeigern zerfallen:
    // void auswahl_eins( feld (*ptr)[5] );
    
    //Aufruf:
    auswahl_eins(Spielfeld);
    

    Der Adressoperator ist nicht nötig da Arrays automatisch zu Zeigern auf ihre Elemente zerfallen.
    Die Elemente des Arrays Spielfeld sind wiederum Arrays, nämlich die einzelnen Spalten (mit Hoehe viel Elementen). (Es gibt also in Spielfeld Breite Arrays mit Hoehe Elementen).

    So ist das eigentlich suboptimal, da die Größe des Arrays, bzw. Hoehe , zur Compile-Zeit und global bekannt sein muss. Normalerweise simuliert man zweidimensionale Arrays durch ein eindimensionales Array, aber die Variante in der das Array eindimensional betrachtet wird lasse ich vorerst weg, da du sie höchstwahrscheinlich sowieso nicht brauchen und/oder nutzen wirst.


  • Mod

    @Skyfall: Jetzt willst du im Nachhinein doch eindimensional arbeiten?

    auswahl_eins(&Spielfeld[Breite][Hoehe]);
    

    Muss abgeändert werden zu

    auswahl_eins(&Spielfeld[0][0]);
    

    Er unterstreicht (In Visual Studio 2010) das & Im Argument vom Funktionsaufruf in main und sagt mir "Error: Das Argument vom Typ ""feld*"" ist mit dem Parameter vom Typ ""feld*"" inkompatibel."

    Was Intellisense (so wird der Mechanismus genannt der dir alles unterstreicht) sagt ist vorerst unwichtig, wichtiger sind die Fehler beim kompilieren.

    Was ist an strcpy nicht gut?

    Nichts an strcpy ist primär schlecht, in C++ nutzt man für Kopien aber std::copy bzw. std::copy_n . strcpy signalisiert dass man mit C-Strings arbeitet, was man i.d.R. nicht tun sollte. Außerdem überprüft es nicht die Länge und kann so unbemerkt zu schweren Fehlern führen. strncpy sollte, wenn überhaupt, verwendet werden.

    Für Strings nimmt man im Übrigen die Klasse std::string . Viele Operationen werden damit erheblich vereinfacht. Eine grobe Einführung gibt es hier.

    Bei dem "struct feld Spielfeld" vermute ich, dass dich die alte C-Schreibweise stört, anstelle von C++? ->Dem bin ich mir bewusst.

    Warum verwendest du sie dann?



  • Also ich habe jetzt ein bisschen gegoogelt und mir folgendes zu mehrdimensionalen Arrays durchgelesen: http://openbook.galileocomputing.de/c_von_a_bis_z/011_c_arrays_009.htm#mj556ba85ff5cddc85b2f38765b20c2288

    Ganz unten ist der Abschnitt zu merhdimensionalen Arrays, in dem der Autor genau das was ich mache auch als Programmbeispiel aufführt:

    /* md_array3.c */
    #include <stdio.h>
    #include <stdlib.h>
    #define DIM1 5
    #define DIM2 5
    
    void function(int feld[][DIM2], int dim1) {
       int i, j;
    
       for(i = 0; i < dim1; i++) {
          for(j = 0; j < DIM2; j++) {
             printf("%d; ", feld[i][j]);
          }
          printf("\n");
       }
       printf("\n");
    }
    
    int main(void) {
       int val[DIM1][DIM2];
       int i, j;
    
       for(i = 0; i < DIM1; i++)
          for(j = 0; j < DIM2; j++)
             val[i][j] = i+j;
    
       function(val, DIM1);
       return EXIT_SUCCESS;
    }
    

    @Arcoth:
    Ich merke schon du kennst dich aus, da hier das selbe geschildert wird:
    "Da eine aufgerufene Funktion keinen Speicher für ein Array bereitstellt, muss die gesamte Größe des Arrays (erste Dimension) nicht angegeben werden – weshalb hier die (Dimension) Zeile weggefallen ist. Allerdings müssen die weiteren Dimensionen (zweite, dritte etc.), wie im Beispiel mit SPALTE, immer mit angegeben werden." 🙂 👍

    Nun versuche ich das auf mein Programm anzuwenden aber bekomme beim kompilieren immer den verfluchten Error C2664 -.-
    Der aktuelle Stand ist folgender:

    Aufruf (main.cpp):

    if(Auswahl == 1)
    {
    	auswahl_eins(Spielfeld, Hoehe, Breite);
    }
    

    --> Wie du zuvor vorgeschlagen hast (und wies auch auf der Seite steht) nun ohne Addressoperator.

    Funktionsdefinition (auswahl_eins.cpp):

    void auswahl_eins(struct feld Spielfeld[][4], int Hoehe, int Breite)
    {
    }
    

    Header (auswahl_eins.h):

    #ifndef AUSWAHL_EINS_H_
    #define AUSWAHL_EINS_H_
    
    struct feld
    {
    	bool status; // 0 = Unbesetzt, 1 = Besetzt
    	char name[10];
    };
    
    void auswahl_eins(struct feld, int, int);
    
    #endif
    

    Sorry, dass das hier so ausartet. Ich bin auf jedenfall für jede Hilfe dankbar 👍



  • Skyfall91 schrieb:

    Aber in diesem Zusammenhang würde mich natürlich direkt interressieren was daran schlecht ist / stört? Bei dem "struct feld Spielfeld" vermute ich, dass dich die alte C-Schreibweise stört, anstelle von C++? ->Dem bin ich mir bewusst.

    Es ist sinnlos und vermittelt den Eindruck, dass du nicht weißt was du tust.

    Was ist an strcpy nicht gut?

    Die Programmabstürze. Niemand bekommt das 100prozentig hin!


  • Mod

    Sorry, dass das hier so ausartet.

    Hier artet nichts aus.

    void auswahl_eins(struct feld, int, int);
    

    Du musst in der Deklaration dieselben Parameter angeben wie in der Definition.

    Warum nimmst du die Hoehe als dritten Parameter wenn diese bereits im Typ des ersten enthalten ist (4)? Außerdem ist die Hoehe in deinem ersten Beispiel doch 5?



  • Außerdem ist die Hoehe in deinem ersten Beispiel doch 5?

    Das hab ich nachträglich geändert, hab ich vergessen zu editieren sry

    Du musst in der Deklaration dieselben Parameter angeben wie in der Definition.

    Ich dachte im Header brauch ich nur die Datentypen, keine Namen? Diese haben nämlich übereingestimmt. Wie auch immer, ich habe das ganze jetzt kopiert und bei Deklaration und Definition das allerselbe stehen und der oben genannte Error kommt leider immernoch 😕

    Hier die komplette Fehlerbeschreibung:
    "Error C2664: 'auswahl_eins': Konvertierung des Paramters 1 von 'main::feld[4][4]' in 'feld[4] nicht möglich"
    Zusätzlich kommt noch:
    "IntelliSense: Das Argument vom Typ ""feld()[4]"" ist mit dem Parameter vom Typ ""feld()[4]"" inkompatibel."

    Beide Fehler werden vom Compiler genau beim Aufruf der Funktion in main.cpp geortet.



  • Vorschlag zur Güte:

    #include <string>
    
    struct Feld
    {
       bool Status;
       std::string Name;
    
       Feld() :
          Status( false ),
          Name( "leer" )
       {
       } 
    };
    
    struct SpielFeld
    {
       Feld Felder[5][5];
    };
    
    void f( SpielFeld& sf )
    {
    }
    

    Sieht natürlich etwas doof aus, weil SpielFeld nur ein Attribut hat, löst aber die ganze Dimensionsgehampel des Arrays. Die Initialisierung im Konstruktor macht auch die Schleife überflüssig (und den Code robuster).


Log in to reply