Struct Array an Funktion übergeben. wie dort ansprechen error:Der ausdruck muss einen klassentyp aufweisen
-
Folgendes Problem:
In der Aufgabenstellung steht wir sollen mit hilfe von qsort Punkte im Dreidimensionalen Raum aufsteigend nach dem Abstand vom ursprung sortieren.
Gegebenvoid qsort (void* base, size_t num, size_t size, int (*compar) (const void*, const void*)); struct PunktT { double x; double y; double z; };Also habe ich mein Programm geschrieben und schaffe es jetzt nicht in der Funktion int Vergleich(const double* a, const void* b) meine x,y und z koordinaten anzusprechen. denn ich möchte 2 vektoren vergleichen (vektor = wurzel(x²+y²+z²))
#include<iostream> using namespace std; int Vergleich(const void* a, const void* b) { //quadrieren und wurzel fehlt noch // fehler liegt hier a.x geht nicht (Der ausdruck muss einen klassentyp aufweisen) if ((*(double*)a.x + *(double*)a.y + *(double*)a.z)<(*(double*)b.x + *(double*)b.y + *(double*)b.z)) return -1; //else if () return 1; //else return 0; } int main() { struct PunktT { double x; double y; double z; }; PunktT* p = new PunktT[2]; p[0].x = 1.0; p[0].y = 2.0; p[0].z = 2.0; p[1].x = 1.0; p[1].y = 1.0; p[1].z = 1.0; qsort(p,3,sizeof(double),Vergleich); for (int i = 0; i < 2; i++) cout<< &p[i] << "\n"; return 0; }in der vorlesung hatte wir folgendes beispiel
int vergleich(const void* a, const void* b) { if (*(int*)a < *(int*)b) return -1; else if (*(int*)a > *(int*)b) return 1; else return 0; } int main() { int a[] = {20, 18, 19, 16, 17, 10, 12, 9}; qsort(a, 8, sizeof(int), vergleich); }
-
Vergiss es. Dein Lehrer hat keine verdammte Ahnung von C++. Der Code ist eine Katastrophe.
PunktT* p = new PunktT[2];Wieso vom Freispeicher? Ein Stack-Array macht hier hundertmal mehr Sinn.
void qsort (void* base, size_t num, size_t size, int (*compar) (const void*, const void*));Ich bin fast vom Stuhl gefallen. Was zum Teufel ist das? Das kann nicht dein Ernst sein?

Da besteht auch kein Erklärungsbedarf. Es gibt keinen, aber auch wirklich KEINEN Grund das mit den unglaublich unsicheren, umständlichen und gefährlichen void-Pointern zu lösen. Einfach direkt eineconst-Referenz aufPunktT.Die Namenswahl ist auch komisch. Ein Raumvektor hat keine Länge; was du meinst ist ein Richtungsvektor.
Hier ist ein richtiges Beispiel:
#include <iostream> #include <cmath> #include <algorithm> #include <iterator> template<typename Element_T> struct Vector3 { typedef Element_T element_t; element_t x,y,z; element_t length() const { return std::sqrt( x*x + y*y + z*z ); } element_t squared_length() const { return x*x + y*y + z*z; } friend std::ostream& operator<<( std::ostream& os, Vector3 const& v ) { return os << v.x << ' ' << v.y << ' ' << v.z; } }; typedef Vector3<float> Vector3f; template<typename T> struct lengthCompare { bool operator()( Vector3<T> const& lhs, Vector3<T> const& rhs ) const { return lhs.squared_length() < rhs.squared_length(); } }; int main() { Vector3f v[] = { {1, 1, 1}, {2, 0.5, 5}, {1, 0.9, 1.1} }; std::sort( std::begin(v), std::end(v), lengthCompare<float>() ); std::copy( std::begin(v), std::end(v), std::ostream_iterator<Vector3f>(std::cout, "\n") ); }
-
Sone schrieb:
void qsort (void* base, size_t num, size_t size, int (*compar) (const void*, const void*));Ich bin fast vom Stuhl gefallen. Was zum Teufel ist das?
C.
Auch interessant: C + std::cout + new, hatte ich bisher auch noch nicht gesehen.@TE:
In der Vergleichsfunktion musst du die beiden const void Paremeter nach PunktT casten, erst dann kannst du auf die Werte zugreifen. Der Cast der Membervariablen nach double ist dann nicht mehr notwendig.
-
C.
Ketzerei!
-
void qsort (void* base, size_t num, size_t size, int (*compar) (const void*, const void*));Ich bin fast vom Stuhl gefallen. Was zum Teufel ist das? Das kann nicht dein Ernst sein?

Da besteht auch kein Erklärungsbedarf. Es gibt keinen, aber auch wirklich KEINEN Grund das mit den unglaublich unsicheren, umständlichen und gefährlichen void-Pointern zu lösen.Dies ist keine Vorgabe des Lehrers, sondern qsort wird von C++ mitgelifert. genauso wie ich ja auch
intin
int zahlnutze.
@Nathan
Also in der Funktion nicht double sondern PunktT angeben. Bin grad auf der Arbeit ud kann es nicht probieren.//const void* kann ich nicht ändern, das will qsort so haben. int Vergleich(const void* a, const void* b) { if ((*(PunktT*)a.x + *(PunktT*)a.y + *(PunktT*)a.z)<(*(PunktT*)b.x + *(PunktT*)b.y + *(PunktT*)b.z)) return -1; //else if () return 1; //else return 0; }
-
Gut, dann ist es in der C-Standardbibliothek. Nicht besser. Das würde man in C++ nie damit machen machen.
-
Und dann -> verwenden, nicht . .
Dies ist keine Vorgabe des Lehrers, sondern qsort wird von C++ mitgelifert
Jein. qsort ist Bestandteil der C-Standardbibliothek. In C++ nutzt man std::sort.
Dies ist keine Vorgabe des Lehrers, sondern qsort wird von C++ mitgelifert. genauso wie ich ja auch
intin
int zahlnutze.
Das sind verschiedene Dinge!
int ist ein Schlüsselwort in C++, qsort wird von der Standardbibliothek bereitgestellt, dazu muss aber der Header cstdlib inkludiert werden. Das ist ein Unterschied.
-
Mir ist das Wort Standardbibliothek nicht eingefallen, deswegen der Vergleich mit int.
Ich würde es auch anders realisieren, aber wenn da steht wir sollen qsort und struct so nutzen, dann geht es nicht anders.
So habe nen online-compiler gefunden, wenn ich double duch PunktT ersetze das klappt nicht.
So ganz verstanden habe ich das mit dem casten nach nicht Nathan.
-
int Vergleich(const void* a, const void* b) { PunktT *a_punkt = reinterpret_cast<PunktT *>(a); // mache aus a einen PunktT PunktT *b_punkt = reinterpret_cast<PunktT *>(b); // mache irgendetwas mit den Werten if (a_punkt->x > b_punkt->x && ...) ... }
-
Sone schrieb:
element_t length() const { return std::pow( x*x + y*y + z*z, 1./3 ); }Auch für Punkte im dreidimensionalen Raum gehört hier die Quadratwurzel hin.
Davon ab ist es für die Aufgabe unnötig, die Wurzel zu ziehen, da die quadrierten Abstände die gleiche Größenrelation haben. Gerade wenn man viele Punkte sortieren will, macht das einen signifikanten Geschwindigkeitsunterschied.
-
Nathan schrieb:
int Vergleich(const void* a, const void* b) { PunktT *a_punkt = reinterpret_cast<PunktT *>(a); // mache aus a einen PunktT PunktT *b_punkt = reinterpret_cast<PunktT *>(b); // mache irgendetwas mit den Werten if (a_punkt->x > b_punkt->x && ...) ... }reinterpret_cast entfernt kein const, für desen Entfernung gibt es keinen Grund und reinterpret_cast ist auch die falsche Form.
double sqr(double x) { return x * x; } double sqrlength(const Punkt& p) { return sqr(p.x) + sqr(p.y) + sqr(p.z); } int Vergleich(const void* a, const void* b) { double sqrlength_a = sqrlength(*static_cast<const PunktT*>(a)); double sqrlength_b = sqrlength(*static_cast<const PunktT*>(b)); return sqrlength_a < sqrlength_b ? -1 : sqrlength_a > sqrlength_b; }
-
camper schrieb:
reinterpret_cast entfernt kein const, für desen Entfernung gibt es keinen Grund und reinterpret_cast ist auch die falsche Form.
Mir ist gar nicht aufgefallen, dass die Parameter const void waren.

Wann verwendet man denn reinterpret_cast? Ich dachte immer, das kommt zum Zuge wenn man einen Speicherbereich neu interpretieren muss, wie hier wo man rohen Speicher als Strukt interpretieren muss. Oder irre ich mich?
-
Nathan schrieb:
Wann verwendet man denn reinterpret_cast? Ich dachte immer, das kommt zum Zuge wenn man einen Speicherbereich neu interpretieren muss, wie hier wo man rohen Speicher als Strukt interpretieren muss. Oder irre ich mich?
Ja, Pointer auf andere Typen zu casten ist der Zweck. Man sagt dem Compiler also "das sieht für dich aus wie X, aber du sollst es wie Y behandeln". Das ist aber etwas anderes als const_cast, welcher sagt "das sieht aus als wäre es konstant, aber behandele es, als wäre es nicht so" (oder umgekehrt).
-
OK, also wäre in diesem Fall ein reinterpret_cast<const PunktT> richtig?
Warum verwendet camper dann static_cast?
-
ananas schrieb:
Sone schrieb:
element_t length() const { return std::pow( x*x + y*y + z*z, 1./3 ); }Auch für Punkte im dreidimensionalen Raum gehört hier die Quadratwurzel hin.
Ups, hast Recht.
Davon ab ist es für die Aufgabe unnötig, die Wurzel zu ziehen, da die quadrierten Abstände die gleiche Größenrelation haben. Gerade wenn man viele Punkte sortieren will, macht das einen signifikanten Geschwindigkeitsunterschied.
Ja, da hast du auch Recht.
-
So,damit mein code bis zuhause niht verschindet.
#include<iostream> #include <stdlib.h> using namespace std; struct PunktT { double x; double y; double z; }; int Vergleich(const void* ap, const void* bp) { //quadrieren und wurzel fehlt noch // fehler liegt hier a.x geht nicht (Der ausdruck muss einen klassentyp aufweisen) PunktT *a = (PunktT *)ap; PunktT *b = (PunktT *)bp; // mache irgendetwas mit den Werten if (a->x+a->y+a->z > b->x+b->y+b->z) return -1; else if (b->x+b->y+b->z > a->x+a->y+a->z) return 1; else return 0; } int main() { PunktT* p = new PunktT[2]; p[0].x = 1.0; p[0].y = 1.0; p[0].z = 1.0; p[1].x = 2.0; p[1].y = 2.0; p[1].z = 1.0; qsort(p,3,sizeof(double),Vergleich); for (int i = 0; i < 2; i++) cout<<p[i].x<<","<<p[i].y<<","<<p[i].z<<"\n"; return 0; }
-
Nathan schrieb:
OK, also wäre in diesem Fall ein reinterpret_cast<const PunktT> richtig?
Warum verwendet camper dann static_cast?Weil man von void* auf andere Zeigertypen mittels eines static_casts kommt. Ein void* zeigt schließlich auf keinen Typen, sondern ist eine Art allgemeiner Zeiger. Da wird nichts uminterpretiert, sondern überhaupt erst interpretiert.
-
OK, danke.