Laden...

Definition eines Arrays von Arrays

Erstellt von This vor 15 Jahren Letzter Beitrag vor 15 Jahren 2.532 Views
Thema geschlossen
T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren
Definition eines Arrays von Arrays

Hallo,

niemal hab ich mit einer Sprache soviele PRobleme gehabt wie mit C#.

Was ich möchte ist folgendes:

Ein Array mit Datensätzen folgender Struktur:

Datensatz


Feld 1 = float[1];
Feld 2 = float[100];
Feld 3 = float[100];

Damit ordnet man für jeden Wert von Feld 1 bis zu 10000 Werte aus Feldern 2 und 3 zu.

Macht man das so:

float [][] ar = new float [3][];
ar[0]=new float[1];
ar[1]=new float[100];
ar[2]=new float[200];

Ist das Problem nicht gelöst, es wurde nur 1 einziger Datensatz ar definiert, ich will aber ar auch als array mit einigen hundert Datensätzen.

Definiert man das als Class,

public void Class abc
{
   float[] feld1 = new float[1];
   float[] feld2 = new float[100];
   float[] feld3 = new float[100],
}

kann man mit

abc[] arr = new abc[200]

zwar genau die gewünschte Struktur erzeugen, aber der Compiler läßt bei der Anweisung:

abc[0].feld1[0]=1.0 ;

keinen Schreibzugriff zu wegen "Sicherheitsstufe". Wozu dann die Deklaration, wenn man nicht schreiben darf???

Allmählich verzweifele ich an C#, weil man immer an den Formalien scheitert und dazu keinen einzigen Beispielcode findet.

Weiß jemand die Lösung für das Problem?

This

J
257 Beiträge seit 2008
vor 15 Jahren

Hallo,
beim oberen Teil ist mir ehrlich gesagt nicht klar, was du machen willst.

Das du aufgrund der Sicherheitsstufe nicht auf die Felder der Klasse zugreifen kannst, liegt wohl daran, dass sie implizit private sind. Schreib mal ein public, oder zumindest internal davor, dann sollte es gehen.

Gruß

946 Beiträge seit 2008
vor 15 Jahren

Hallo

Ich würde eine Eigenschaft draus machen.

Ausserdem:

float [][] ar = new float [3][];  

Wenn du aus einer anderen Sprache kommst, sei dir noch der unterschied zwischen [,] und [][] bewusst.
Wenn du ein normales 2-Dimensionales Array willst, ist [,] besser geeignet, eventuell sogar die Bitmap-Klasse (falls du sowas willst).

mfg
SeeQuark

T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren

Hallo,
beim oberen Teil ist mir ehrlich gesagt nicht klar, was du machen willst.

Das du aufgrund der Sicherheitsstufe nicht auf die Felder der Klasse zugreifen kannst, liegt wohl daran, dass sie implizit private sind. Schreib mal ein public, oder zumindest internal davor, dann sollte es gehen.

Gruß

Ja danke erstmal für den Wink.

Hab das jetzt soweit:

        public class Koordinaten
        {
            internal float[] z = new float[1];
            internal float[] x = new float[100];
            internal float[] y = new float[100];
        }

und in MAIN:

 Koordinaten[] krd = new Koordinaten[200];  

Das wäre die Struktur, die ich brauche. Kann allerdings immer noch nicht Werte zuweisen, z. B. so:

              for (int i=0; i<200; i++)
            {
                krd[i].z[0]=0;
                for (int feld = 0; feld < 100; feld++)
                {
                    krd[i].x[feld] = 1;
                    krd[i].y[feld] = 1;
                }
            }


Weil der Compiler meint:

Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt."
Erstellen Sie eine Objektinstanz mit dem Schlüsselwort "new"
Überprüfen Sie, ob das Objekt NULL ist, bevor sie die Methode aufrufen.

Ich dachte, ich hätte das mit der Anweisung:

    Koordinaten[] krd = new Koordinaten[200];

soeben erledigt.

Das Objekt NULL kenne ich nicht, ich dachte das heißt in C# null, und nicht NULL, und würde auf eine Referenz hindeuten. Ich will aber ja Werte übergeben. Kann man in diese Felder keine Wertzuweisungen machen? Dafür sind die doch float. ...???

Wie gesagt, mit C# habe ich die größten gedanklichen Probleme aller Zeiten.

This

946 Beiträge seit 2008
vor 15 Jahren

Hallo

und in MAIN:

Klassen kapseln Daten und haben auch eine eigene Logik.

Schau, ob du das nicht irgendwie in die Klasse reinkriegst.

zu deinem Problem: [FAQ] NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt
In Kurzform: Du musst erst noch krd_ einen Wert zuweisen (new Koordinaten();)

mfg
SeeQuark

365 Beiträge seit 2007
vor 15 Jahren
        public class Koordinaten  
        {  
            internal float[] z = new float[1];  
            internal float[] x = new float[100];  
            internal float[] y = new float[100];  
        }  
  
Koordinaten[] krd = new Koordinaten[200];  

Dir ist schon klar das du 200 * ein Objekt Koordinaten erstellst was
jeweils folgende Struktur besitzt:


            internal float[] z = new float[1];
            internal float[] x = new float[100];
            internal float[] y = new float[100];

Vielleicht müsstest du einen Konstruktor für deine Klasse anlegen welche die Arrays
mit den entsprechenden Größen initialisiert.
In etwa so:


public class Koordinaten
{
internal float[] z = new float[1];
internal float[] x = new float[100];
internal float[] y = new float[100];

    public Koordinaten()
    {
        this.z = new float[1];
        this.x = new float[100];
        this.y = new float[100];
    }
}

Damit gehst du sicher das deine Arrays innerhalb deiner Klasse immer
initalisiert werden.

Greetz da kubi.

P.S.:
Vielleicht solltest du uns erläutern wofür du genau diese Struktur brauchst,
eventuell schlägst du einen nicht so praktischen Weg ein und erkennst es nur nicht.
Passiert mir auch oft genug das Ich mich auf etwas versteife,
dafür aber schon eine fertige Lösung unseres Redmonder Vereins bereitsteht. 😁

Edit:

Ich würde eine Eigenschaft draus machen.

Bin auch ein Verfechter der Properties/Eigenschaften, diese lösen
diese Problem jedoch nicht, sondern verwirren eher den Fragestellenden.

946 Beiträge seit 2008
vor 15 Jahren

Hallo kubi

Du initialisierst du Arrays doppelt 😁

Entweder Konstruktor oder bei der Definition.
Im Endeffekt läuft das aber auf das Selbe heraus

@This: Ich würde nur eine Point3D-Struct machen und diese in der Klasse Koordinaten unterbringen. So etwas gibt es aber schon zu Tausendem.

mfg
SeeQuark

365 Beiträge seit 2007
vor 15 Jahren

Hallo kubi

Du initialisierst du Arrays doppelt großes Grinsen

Hehe, habs net ausprobiert, sah mir nur danach aus 😉

T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren

In Kurzform: Du musst erst noch krd_ einen Wert zuweisen (new Koordinaten();)

Ja so geht es. Danke!

Kapieren tu ich das aber nicht.

Warum die Blöcke jetzt einzeln in Betrieb nehmen mit krd_=new Koordinaten() innerhalb des Blocks eine Speicherreservierung für jedes einzelne Element??

Wo liegt der Sinn davon? Mit new Koordinaten[200] müßte doch eigentlich der gesamte Block für 200 Elemente (auf dem Heap) schon längst reserviert sein?

Und C# müßte anhand der Length der elemente doch wissen, wie es den Zeiger weiterrücken soll????

Also C# ist teilweise so völlig verschieden von C oder C++, da hab ich den Dreh noch nicht gefunden, in welche Richtung man überhaupt denken soll.

Danke jedenfalls für die Hilfe.

This

365 Beiträge seit 2007
vor 15 Jahren

Also so funktioniert es bei mir:


            Koordinaten[] krd = new Koordinaten[200];

            for (int i = 0; i < krd.Length; i++)
            {
                krd[i] = new Koordinaten();
            }

            krd[0].x[0] = (long)120.345;

Greetz da kubi.

Mit new Koordinaten[200] wurde doch schon der ganze Speicher reserviert, oder? Oder wurde da nur ein Zeiger definiert auf den Startbereich?

Ich denk mal, es wurde einfach nur ein Array mit 200 Startbereichen für ein Objekt Koordinate erzeugt.
Jedoch nicht jeweils ein instanziertes Objekt Koordinaten, sondern nur der sogenannter Zeiger dafür.
Das 'new' steht also nur für das Array, jedoch nicht für die Objekte die enthalten sind.
Klingt für mich jedenfalls logisch, je länger Ich darüber nachdenke 😁

Edit:


for (int i=0; i<200; i++)
{
krd[i].z[0]=0;
for (int feld = 0; feld < 100; feld++)
{
krd[i].x[feld] = 1;
krd[i].y[feld] = 1;
}
}

Benutze keine feste Zahl wie 200 sondern die Referenz auf eine Objekt - Größe/Länge,
wie z.B. krd.Length.
Somit bist du sicher falls du einmal das Verlangen verspürst deinen Bereich zu vergrößern oder zu verkleinern.

946 Beiträge seit 2008
vor 15 Jahren

Hallo this

Um dich noch komplett zu verwirren: In C# gibt es keine "Zeiger" in dem klassischen Sinne.

for (int i = 0; i < krd.Length; i++)

Wa wird nur ein int-Wert hochgezählt.

Und C# müßte anhand der Length der elemente doch wissen, wie es den Zeiger weiterrücken soll????

Hehe. Der Integer wird von 0 bis krd.Length hochgezählt. Der ist eine ganz normale Zahl.

Mit new Koordinaten[200] wurde doch schon der ganze Speicher reserviert, oder?

Der Speicher schon. Oder zumindest genug Platz für die Referenz. Das Objekt wurde aber noch nicht erstellt.

mfg
SeeQuark

T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren

Ja danke, liebe Leute.

Das Problem ist von der praktischen Hand gelöst, es läuft jetzt.

Nur kapieren tu ich mal wieder nix. Ist wohl noch die alte Denke drin, OOP braucht neue Denke, OOP ist im Gehirnkasten definitiv noch nicht implementiert.

This

365 Beiträge seit 2007
vor 15 Jahren

Hrhrhr,
was meinst wie oft Ich vor Code - Beispielen stehe und denke:
"Was wollen die von mir?!"
Muhahaha ... aber hey, das ist unteranderem ein Grund warum Ich Entwickler geworden bin. 👍

T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren

In C# gibt es keine "Zeiger" in dem klassischen Sinne.

Das kann nicht sein.

Wie will die Laufzeitumgebung denn das Objekt referenzieren?

In C ist es so:

Mit dem myarray_ zeigt der Pointer von der Laufzeitumgebung drauf. Das ist zu 100 Prozent in C# auch der Fall.

Nur daß man in C eben seinen eigenen Zeiger draufstellen kann, das geht in C# so nicht (und daß das nicht geht, auch nicht die schlechteste Idee).

Aber im Prinzip muß jedes Objekt durch einen Zeiger referenziert werden. Zeiger=Pointer=SpeicherbereichStartAdresse.

Wie ich das mitbekommen habe, liegen diese Referenzen im Stack.

Also wir haben Heap, Stack und einen reservierten Bereich vom Stack, wo die Referenzen auf den Heap liegen. Womöglich ist das eine dynamisch verwaltete Tabelle.

So hab ich das bis jetzt ungefähr mitbekommen.

This

365 Beiträge seit 2007
vor 15 Jahren

Nur daß man in C eben seinen eigenen Zeiger draufstellen kann, das geht in C# so nicht (und daß das nicht geht, auch nicht die schlechteste Idee).

Das will Ich meinen das dies eine gute Idee ist .....

Lese oft genug darüber das man einen Speicherbereich überschreitet,
weil es halt in anderen Sprachen möglich ist und man sich damit Ärger einheimst.

Natürlich ist so eine Funktion auch nicht vorteilslos,
wenn man auf Speicherbereiche zugreifen kann wie man will.
Jedoch wenden das oft User an die die Thematik nicht verstehen und somit mehr
kaputt machen als gewinnen 8)

1.361 Beiträge seit 2007
vor 15 Jahren

Hi This.

Wo liegt der Sinn davon? Mit new Koordinaten[200] müßte doch eigentlich der gesamte Block für 200 Elemente (auf dem Heap) schon längst reserviert sein?

Koordinaten ist bei dir eine Klasse. Also ein Verweistyp (Referenztyp).
Und diese liegen immer auf dem Heap. Demzufolge (wie du schon richtig erkannt hast) benutzt .NET da intern immer einen Zeiger auf solche Objekte.

Und auch den Koordinaten[200]-Array besteht sozusagen nicht direkt aus den Koordinaten, sondern aus Referenzen darauf (quasi Zeiger). Sprich, aus Integer-werten.
Wenn du nun das Array mit new erzeugst dann bekommst du (intern von malloc) Speicher auf dem Heap für insgesamt 200 int32-Werte (auf nem 32Bit System).

Diese sind (da Referenzen/Zeiger) standardmäßig mit null initialisiert.

Und deshalb musst du nun in einer Schleife erst noch jedes einzelne Koordinaten-Objekt erzeugen und die krd_-Referenz darauf setzen (also den Zeiger festlegen).

(Oder aber du hättest Koordinaten als struct implementiert. Dann wäre es "inplace" im Speicher vorhanden. Aber sonst ist in C# eben implizit alles Referenz.)

T
This Themenstarter:in
51 Beiträge seit 2009
vor 15 Jahren

Hi This.

Und auch den Koordinaten[200]-Array besteht sozusagen nicht direkt aus den Koordinaten, sondern aus Referenzen darauf (quasi Zeiger). Sprich, aus Integer-werten.
Wenn du nun das Array mit new erzeugst dann bekommst du (intern von malloc) Speicher auf dem Heap für insgesamt 200 int32-Werte (auf nem 32Bit System).

Diese sind (da Referenzen/Zeiger) standardmäßig mit null initialisiert.

Und deshalb musst du nun in einer Schleife erst noch jedes einzelne Koordinaten-Objekt erzeugen und die krd_-Referenz darauf setzen (also den Zeiger festlegen).

(Oder aber du hättest Koordinaten als struct implementiert. Dann wäre es "inplace" im Speicher vorhanden. Aber sonst ist in C# eben implizit alles Referenz.)

Jetzt hab ich das ungefähr begriffen, was da abgeht.

Ja, eigentlich hätte ich eine struct benötigt, in C hätte ich die auch genauso implementiert, habe aber vernommen, daß der Typ struct nicht in die OOP Umgebung paßt, und das daher vermieden, damit man nicht in C denkt und in C# programmiert (sowas kann nicht zielführend sein).

Also man bekommt mit Classname[] objektname= new Classname[200] nicht Speicherplatz für 200 Elemente, wie ich gedacht hätte, sondern lediglich 200 Zeiger, die auf null gesetzt sind, und selbst nur den Speicher von 200 int verbrauchen.

Aha! Darunter kann ich mir was vorstellen.

Und wenn man das weiß, kann man sich auch vorstellen, wozu das Sinn machen sollte: Nämlich, daß man trotz der statischen Definition von [200] den Speicher erst kriegt, wenn man ihn zur Laufzeit braucht.

Es geht also darum, den Speicherbedarf so ökonomisch zu handhaben wie möglich.

Eigentlich nicht schlecht der Gedanke.

Nur, darauf muß man erstmal kommen!

Also vielen Dank für die vielen Hinweise, die waren auch wirklich nötig! Von selbst wäre ich nicht drauf gekommen.

This

O
778 Beiträge seit 2007
vor 15 Jahren

Wenn du gerade von Speicherbedarfökonomie redest: Einfach die Koordinaten als structs zu definieren ist nicht wirklich der Weisheit letzter Schluss, dir sollte das volle Ausmaß dieser Vorgehensweise bewusst sein. Auszugsweise:

  • Bei einer Übergabe des Objekts (z.B. als Parameter) wird nicht der Zeiger übergeben, sondern das komplette struct (gut, das besteht so wie es jetzt implementiert ist hauptsächlich nur aus drei Zeigern auf die Arrays)
    Das heißt auch, dass du immer nur quasi mit lokalen Kopien arbeitest, die du dann zurückschreiben musst, Aufrufe wie
System.Drawing.Size s = control.Size;
s.Height = 30;

sind deswegen komplett blödsinnig, es sei denn man schreibt das struct-Objekt zurück (control.Size = s in dem Fall)

  • Vererbung ist ausgeschlossen, du solltest dir also gut überlegen wie es mit Wiederverwendung aussieht

Übrigens wegen dem NULL und null: Die CLR hat doch keine Ahnung, dass du mit C# arbeitest, du könntest genausogut mit VB.NET programmiert gearbeitet haben, und da heißt die leere Referenz Nothing. Das kann ab und an mal passieren, das die selben Sachen unterschiedliche Namen haben (zB auch int vs Int32 vs Integer (VB.NET), string vs String).

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo This,

Also vielen Dank für die vielen Hinweise, die waren auch wirklich nötig!

nein, war sie definitiv nicht. Das sind absolute Grundlagen und wir erwarten, dass du sie dir selbst aneignest. Das kannst du ganz einfach in dem du gründlich ein C# Buch durcharbeitest. Dieser Thread ist ein einziger großer Verstoß gegen [Hinweis] Wie poste ich richtig? Punkt 1.1.1 (==> Thread geschlossen) und auch wenn die Leute in diesem Fall so nett waren, dir alles einzeln vorzubeten, erwarten wir von dir, dass sowas nicht noch einmal vorkommt. Ich hoffe, wir haben uns verstanden.

herbivore

Thema geschlossen