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
-
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
-
@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?
-
Du musst dich entscheiden ob du innerhalb
auswahl_eins
das Array als ein eindimensionales oder zweidimensionales anfassen willst. Bei letzterem muss dieHoehe
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 ArraysSpielfeld
sind wiederum Arrays, nämlich die einzelnen Spalten (mitHoehe
viel Elementen). (Es gibt also inSpielfeld
Breite
Arrays mitHoehe
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.
-
@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 aberstd::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!
-
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).