VB /Excel VBA: Array vergrößern

Hallo Wissende,

ist zwar ein Excel-Vba Problem, aber ich wollte es für hier in VB umschreiben und bekomme es nicht hin,die Ausgabe in zwei Listboxen zu leiten.

Es kommt "Typen unvertäglich bei „List1=a“.

In den Eigenschaften von List1 konnte ich nichts entdecken mit dem ich der Listbox sage, daß sie 3 Spalten hat. „Columns“ scheint was anderes zu sein laut Beschreibung.

Das wäre das eine Problem.

Das andere Problem ist, ich habe ein Array a(45000,2). Die mittlere Spalte (Index=1) soll nun durchsucht werden nach bestimmten Werten. Werden diese gefunden sollen an dieser Stelle mehrere „Zeilen“ in das Array eingefügt werden.
(Mit Zeilen meine ich 0-45000, mit Spalten 0-2, heißt offiziell sicher anders)

In meinem Beispiel habe ich nun das a-Array verkleinert als Exceltabelle in Tabelle1 aufgelistet.
Die o.g. Suche fehlt noch im Code, im Code gehe ich davon aus die Zahl „8“ wurde gesucht und gefunden, somit ist bekannt,daß die „8“ in a(2,1) steht.

Nun funktioniert der Code schon soweit, daß er wie geplant das array a in das neue Array b rüberschreibt und dabei die gewünschten „Zeilen“ einfügt, wie man in Tabelle2 sehen kann.

Nur, geht das nicht eleganter als alles einzeln rüberzukopieren?
Wieso kann ich anstatt
b(0,0)=a(0,0)
b(0,1)=a(0,1)
b(0,2)=a(0,2)
nicht schreiben
b(0)=a(0)
?

Oder wie mit einem Rutsch alles von a(0,0) bis a(2,2) nach b(0,0) bis b(2,2) schaukeln ?

Tabelle1
 │ A │ B │ C │
──┼────┼────┼────┤
1 │ 1 │ 2 │ 3 │
──┼────┼────┼────┤
2 │ 4 │ 5 │ 6 │
──┼────┼────┼────┤
3 │ 7 │ **8** │ 9 │
──┼────┼────┼────┤
4 │ 10 │ 11 │ 12 │
──┼────┼────┼────┤
5 │ 13 │ 14 │ 15 │
──┼────┼────┼────┤
6 │ 16 │ 17 │ 18 │
──┴────┴────┴────┘




Tabelle2
 │ E │ F │ G │
──┼────┼────┼────┤
1 │ 1 │ 2 │ 3 │
──┼────┼────┼────┤
2 │ 4 │ 5 │ 6 │
──┼────┼────┼────┤
3 │ 7 │ 8 │ 9 │
──┼────┼────┼────┤
4 │ 7 │ 8a │ 9 │ Zeile eingefügt
──┼────┼────┼────┤
5 │ 7 │ 8b │ 9 │ Zeile eingefügt
──┼────┼────┼────┤
6 │ 7 │ 8c │ 9 │ Zeile eingefügt
──┼────┼────┼────┤
7 │ 10 │ 11 │ 12 │
──┼────┼────┼────┤
8 │ 13 │ 14 │ 15 │
──┼────┼────┼────┤
9 │ 16 │ 17 │ 18 │
──┴────┴────┴────┘

Tabellendarstellung erreicht mit dem Code in FAQ:2363

Nachstehend ist der Code um den es geht.

Danke ^ Gruß
Reinhard

Private Sub Form\_Load()
Dim z, s, N
ReDim a(5, 2)
For z = 0 To 5
 For s = 0 To 2
 N = N + 1
 a(z, s) = N
 Next s
Next z
ReDim b(UBound(a, 1) + 3, 2)
For z = 0 To 2
 For s = 0 To 2
 b(z, s) = a(z, s)
 Next s
Next z
For z = 3 To 5
 For s = 0 To 2
 If s = 1 Then
 b(z, s) = a(2, s) & Chr(94 + z)
 Else
 b(z, s) = a(2, s)
 End If
 Next s
Next z
For z = 6 To 8
 For s = 0 To 2
 b(z, s) = a(z - 3, s)
 Next s
Next z
List1 = a
List2 = b
'Range("A1:C6") = a
'Range("E1:G9") = b
End Sub

Hallo Reinhard.

Wenn ich das nun alles richtig verstanden habe, könnte ich mir vorstellen, daß es am einfachsten ist, die Listbox zu durchsuchen und, wenn der Wert gefunden wurde, mit „AddItem“ der Listbox unterhalb der gefundenen Zeile neue Einträge zu verpassen. Sobald das erledigt ist, könntest Du das Array redimensionieren und den Inhalt der Listbox mit der Anweisung

 MeinArray() = Listbox1.Column()

in das Array übertragen.

Viele Grüße
Carsten

Wenn ich das nun alles richtig verstanden habe, könnte ich mir
vorstellen, daß es am einfachsten ist, die Listbox zu
durchsuchen und, wenn der Wert gefunden wurde, mit „AddItem“
der Listbox unterhalb der gefundenen Zeile neue Einträge zu
verpassen. Sobald das erledigt ist, könntest Du das Array
redimensionieren und den Inhalt der Listbox mit der
Anweisung

MeinArray() = Listbox1.Column()

in das Array übertragen.

Moin Carsten,

die Listbox (oder das Ergebnis in einen Excelzellbereich schreiben) soll ja erst ganz am Schluß geschehen.
Vorher will ich ja so direkt=schnell wie möglich ein Array durch Hinzufügen von Einträgen in ein anderes, größeres Array wandeln.

Angenommen ich habe ein eindimensionales Array a(1 to 10), das mit Werten gefüllt ist und ein lleres Array b(1 to 11).
Dieses a-Array durchsuche ich nun bis ich einen gesuchten Wert finde, angenommen es ist der 6te Wert, a(6).

Nun suche ich eine schnelle Variante, die mir a(1)-a(6) nach b(1)-b(6) kopiert, dann den neuen Wert in b(7) einfügt, dann a(7)-a(10) nach b(8)-b(11) kopiert.

Die gesuchte Prozedur muß sehr schnell sein, da das Originalarray serh groß und mehrdimensional ist, weiterhin wird darin nach ca. 100 Werten gesucht und bei jedem gefundenen Wert soll etwas eingefügt werden.

Wie gezeigt kriege ich es ja hin, dies alles durchzuführen, indem ich die beiden Arrays Eintrag für Eintrag durchlaufe und jeden Eintrag einzeln kopiere.
Aber das ist weder schnell noch elegant.

Mir schwebt da was mit der API-Funktion „CopyMemory“ vor, aber da kriege ich den Code nicht hin. Natürlich nehme ich auch gerne jede andere Codevariante.

Gruß
Reinhard

Moin, Reinhard,

es gibt keine schnellere Methode als die direkte Ansprache der einzelnen Zellen. Ich bezweifle sogar, dass es überhaupt eine andere Methode gibt. Die verkürzte Schreibweise für Arrays setzt ja voraus, dass keinerlei Lücken zwischen (1,n) und (m,n) liegen.

Die Werte (1…n, 1…m) liegen hintereinander im Speicher, also (1,1), (1,2), … (m,n). Mir ist keine Methode bekannt, die aus dieser Kette Teilstücke ansprechen könnte, noch nicht einmal eine Notation dafür kann ich mir vorstellen.

Gruß Ralf

Hallo Reinhard,

da anscheinend keiner eine Lösung weiss und ich auch net so viel Zeit habe, mal ein kleines Demo :wink: Schau dir das mal an, bastel es um und du bist am Ziel. Alle Routinen die du brauchst habe ich dir gepostet. Musst nur noch zusammensetzen :wink:

Option Explicit

Private Declare Sub Copy Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
Private Declare Sub Zero Lib "kernel32.dll" Alias "RtlZeroMemory" (Destination As Any, ByVal Length As Long)
Private Declare Sub Fill Lib "kernel32.dll" Alias "RtlFillMemory" (Destination As Any, ByVal Length As Long, ByVal Fill As Byte)

Dim A1(0 To 10) As Byte 'gefuelltes Array
Dim A2(0 To 11) As Byte 'leeres Array

Private Sub lösche(vRet() As Byte, pos As Byte) 'Array Inhalt schnell löschen, ab Position Pos
 Call Zero(vRet(pos), UBound(vRet) + 1)
End Sub

Private Sub Füll(vRet() As Byte, FillWith As String) 'Array schnell mit einem Wert füllen, wenn wir einmal dabei sind :wink:
 Call Fill(vRet(0), UBound(vRet) + 1, Left(FillWith, 1))
End Sub

Private Sub kopiere(vRet() As Byte, vData() As Byte) 'Array kopieren, auch hier weil ich einmal dabei war
 Call Copy(vData(0), vRet(0), UBound(vRet) + 1)
End Sub

'Zweite Hälfte in die erste kopieren
Private Sub vertausche(vRet() As Byte) 'Array Haelften tauschen
 Dim P As Long
 P = UBound(vRet) \ 2 + 1
 Call Move(vRet(0), vRet(P), P)
End Sub

'Verschieben
Private Sub verschiebe(vRet() As Byte, vData() As Byte, pos As Byte)
 Call Copy(vData(0), vRet(0), pos)
 Call Copy(vRet(0), vRet(pos), pos)
 Call lösche(vRet, pos)
End Sub

Private Sub Form\_Load()
 Dim x As Long
 For x = 0 To UBound(A1)
 A1(x) = x
 Next x
verschiebe A1, A2, 6
End Sub

MfG Alex

Hallo Alex,

da anscheinend keiner eine Lösung weiss

vielleicht will ich etwas was nicht geht, aber ich sehe das wie Toyota :smile:

Aber, es kann doch gar nicht sein *find* daß ich ein Riesen Array habe, a(1000000) wo z.B. in a(1) die 1 drinsteht, bei a(2) die 2 usw.

Nun muß es doch eine Api-Funktion geben, der ich sage, such mir in dem Speicherbereich den die Array-variable a belegt vom Anfang bis Ende nach dem Eintrag „500000“, wenn du den gefunden hast, kopiere in das Array b(1000001) die ersten 500000 Einträge von a nach b, b(500001) wird manuell eingetragen, danach kopiere die Einträge in a(500001) bis a(1000000) nach b(500002) und folgend.

Bei einem eindimensionale Array muß das doch gehen?

*Riesenseufz*

Ich habe alles was mir einfiel probiert, aber ich komme mit deinem Code nicht zum Ziel:frowning:

In dieser Tabelle siehst du in Spalte A die Variable A1 und in Spalte B die Variable A2.

Tabelle1
 │ A │ B │
───┼───┼───┤
 1 │ 0 │ 0 │
───┼───┼───┤
 2 │ 1 │ 1 │
───┼───┼───┤
 3 │ 2 │ 2 │
───┼───┼───┤
 4 │ 3 │ 3 │
───┼───┼───┤
 5 │ 4 │ 4 │
───┼───┼───┤
 6 │ 5 │ 5 │
───┼───┼───┤
 7 │ 6 │ 0 │
───┼───┼───┤
 8 │ 7 │ 0 │
───┼───┼───┤
 9 │ 8 │ 0 │
───┼───┼───┤
10 │ 9 │ 0 │
───┼───┼───┤
11 │ │ 0 │
───┼───┼───┤
12 │ │ 0 │
───┴───┴───┘

Tabellendarstellung erreicht mit dem Code in FAQ:2363

benutzt habe ich diese Codes von dir:

Private Sub verschiebe(vRet() As Byte, vData() As Byte, pos As Byte)
Call Copy(vData(0), vRet(0), pos)
Call Copy(vRet(0), vRet(pos), pos)
'Call lösche(vRet, pos)
End Sub
'
Private Sub Form\_Load()
Dim x As Long
For x = 0 To UBound(A1)
 A1(x) = x
Next x
Range("A1:A10") = Application.WorksheetFunction.Transpose(A1)
verschiebe A1, A2, 6
Range("B1:B12") = Application.WorksheetFunction.Transpose(A2)
End Sub

und ich auch net so
viel Zeit habe, mal ein kleines Demo :wink: Schau dir das mal an,
bastel es um und du bist am Ziel. Alle Routinen die du
brauchst habe ich dir gepostet. Musst nur noch zusammensetzen
:wink:

Alex, ich habe jetzt da schon viel rumgesucht im Internet, scheinbar gibt es bei Vb ein „strptr“, den gibt es in Vba nicht. Da gibt es wohl einen „varptr“ aber dafür ist keine Vba-Hilfe vorhanden, aber so ein Pointer ist wohl wichtig für rtlmovememory bzw. rtlcopymemory.

Was auch immer ich probierte auch mit byref oder byval, es gelang mir nicht das ersehnte Ziel hinzubekommen, daß ich von a(10) die letzen 4 Einträge nach b(7-11) kopiere :frowning:

Und, ich glaube, ich sollte das Gesamtprojekt aufgeben. Denn wenn ich es nichtmal hinkriege mit deiner Unterstützung in ein eindimensionals Array einen Eintrag einzufügen, wobei da die Bytelänge der Einträge bekannt ist, wie soll das erst werden wenn ich das probiere bei dem vorliegenden Fall, ein mehrdimensionales Array mit Texteinträgen unbekannter Bytelänge.

Gruß
Reinhard

Hallo Reinhard,

Nun muß es doch eine Api-Funktion geben, der ich sage, such
mir in dem Speicherbereich den die Array-variable a belegt vom
Anfang bis Ende nach dem Eintrag „500000“, wenn du den
gefunden hast, kopiere in das Array b(1000001) die ersten
500000 Einträge von a nach b, b(500001) wird manuell
eingetragen, danach kopiere die Einträge in a(500001) bis
a(1000000) nach b(500002) und folgend.

ja, gibt es ja auch. Wenn die Länge von a(i) bekannt ist, ist das gar kein Problem. Das bedeutet: Wenn Deine Arrays Zahlen beinhalten ist es leicht, Teile von Arrays in andere Teile von Arrays zu kopieren. Ich habe auch neulich ein mehrdimensionales Array in ein eindimensionales kopiert und war ganz erstaunt, daß das einfach so funktioniert hat.

Du hast aber Strings im Array ob und wie man da mit CopyMemory arbeiten kann, weiß ich nicht, ich kann es nicht. Das Problem ist wohl, daß bei Strings die länge der Felder variable ist.

Bei einem eindimensionale Array muß das doch gehen?

*Riesenseufz*

Ich habe alles was mir einfiel probiert, aber ich komme mit
deinem Code nicht zum Ziel:frowning:

In dieser Tabelle siehst du in Spalte A die Variable A1 und in
Spalte B die Variable A2.

Tabelle1
│ A │ B │
───┼───┼───┤
1 │ 0 │ 0 │
───┼───┼───┤
2 │ 1 │ 1 │
───┼───┼───┤
3 │ 2 │ 2 │
───┼───┼───┤
4 │ 3 │ 3 │
───┼───┼───┤
5 │ 4 │ 4 │
───┼───┼───┤
6 │ 5 │ 5 │
───┼───┼───┤
7 │ 6 │ 0 │
───┼───┼───┤
8 │ 7 │ 0 │
───┼───┼───┤
9 │ 8 │ 0 │
───┼───┼───┤
10 │ 9 │ 0 │
───┼───┼───┤
11 │ │ 0 │
───┼───┼───┤
12 │ │ 0 │
───┴───┴───┘

Tabellendarstellung erreicht mit dem Code in FAQ:2363

benutzt habe ich diese Codes von dir:

Private Sub verschiebe(vRet() As Byte, vData() As Byte, pos As
Byte)
Call Copy(vData(0), vRet(0), pos)
Call Copy(vRet(0), vRet(pos), pos)
'Call lösche(vRet, pos)
End Sub

Private Sub Form_Load()
Dim x As Long
For x = 0 To UBound(A1)
A1(x) = x
Next x
Range(„A1:A10“) = Application.WorksheetFunction.Transpose(A1)
verschiebe A1, A2, 6
Range(„B1:B12“) = Application.WorksheetFunction.Transpose(A2)
End Sub

und ich auch net so
viel Zeit habe, mal ein kleines Demo :wink: Schau dir das mal an,
bastel es um und du bist am Ziel. Alle Routinen die du
brauchst habe ich dir gepostet. Musst nur noch zusammensetzen
:wink:

Alex, ich habe jetzt da schon viel rumgesucht im Internet,
scheinbar gibt es bei Vb ein „strptr“, den gibt es in Vba
nicht.

StrPtr(Stringvariable) gibt Dir die Speicheradresse einer Stringvariable zurück. Das nützt Dir aber nichts, weil das nur für einfache Variablen gilt, für Arrays, die Strings enthalten nicht.
Zu gebrauchen ist das z.B. wenn Du einen String in ein Bytearray umwandeln möchtest.

CopyMemory ByVal StrPtr(StringVariable), Arr(0), 8&

Das drumherum habe ich mal weg gelassen, brauchen wir für das Verständnis nicht. Das da kopiert die ersten vier Zeichen eines Strings in ein Bytearray. (Richtige Vorbereitung vorausgesetzt)

Da gibt es wohl einen „varptr“

Das Selbe für eine einzelne Variable. Kopieren wir mal ein Long in ein Bytearray:

CopyMemory ByVal VarPtr(LongVariable), Arr(0), 4&

aber dafür ist keine
Vba-Hilfe vorhanden, aber so ein Pointer ist wohl wichtig für
rtlmovememory bzw. rtlcopymemory.

Was auch immer ich probierte auch mit byref oder byval, es
gelang mir nicht das ersehnte Ziel hinzubekommen, daß ich von
a(10) die letzen 4 Einträge nach b(7-11) kopiere :frowning:

OK. Kopieren wir mal vier Zahlen in einem Integer-Array um.

Private Declare Sub CopyMemory Lib "kernel32" Alias \_
 "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
 ByVal ByteLen As Long)

Private Sub Command1\_Click()
 Dim Arr(20) As Integer
 Dim i As Integer
 For i = 0 To 20
 Arr(i) = i
 Next
 CopyMemory Arr(5), Arr(10), 8&
 For i = 0 To 20
 List1.AddItem Arr(i)
 Next
End Sub

Und, ich glaube, ich sollte das Gesamtprojekt aufgeben. Denn
wenn ich es nichtmal hinkriege mit deiner Unterstützung in ein
eindimensionals Array einen Eintrag einzufügen, wobei da die
Bytelänge der Einträge bekannt ist, wie soll das erst werden
wenn ich das probiere bei dem vorliegenden Fall, ein
mehrdimensionales Array mit Texteinträgen unbekannter
Bytelänge.

Deshalb habe ich mich bisher nicht beteiligt, Sobald im Array Strings stehen, kenne ich keine Lösung.

Gruß Rainer

Hallo Reinhard,

möglicherweise ist ja der Lösungsansatz nicht optimal…
wenn Du mal sagst, wie groß die Werte werden können und
die Indexe, findet vielleicht jemand eine elegantere Lösung.

LG ALex

Hallo an alle.

Wenn es um die nicht bekannte Länge eines Strings geht, in Variablen kann man doch die Stringlänge festlegen mit

 Dim Variable As String \* 40

Geht denn daß nicht auch in Arrays? Irgendwie müssen die Daten ja dort rein.

Viele Grüße
Carsten

Hallo Carsten,

Wenn es um die nicht bekannte Länge eines Strings geht, in
Variablen kann man doch die Stringlänge festlegen
mit

Dim Variable As String * 40

ja ich weiß. Ich habe es mal so versucht:

Private Declare Sub CopyMemory Lib "kernel32" Alias \_
 "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
 ByVal ByteLen As Long)

Private Sub Command1\_Click()
 Dim Arr(20) As String \* 1
 Dim i As Integer
 For i = 0 To 20
 Arr(i) = Chr(i + 65)
 Next
 CopyMemory Arr(5), Arr(10), 8&
 For i = 0 To 20
 List1.AddItem Arr(i)
 Next
End Sub

das stürzt auch nicht ab, aber es wird nur ein Zeichen kopiert.

Geht denn daß nicht auch in Arrays? Irgendwie müssen die Daten
ja dort rein.

Ja, aber ich finde nicht heraus, wie genau die verwaltet werden und finde bei AVB, PlanetSourceCode oder sonst mit Google auch keine Hinweise. Das würde mich schon mal interessieren, aber ich bin wohl zu dumm zum Suchen.

Ein Zeiger lässt sich ja kopieren und ich hätte erwartet, daß die Zeiger hintereinander stehen. Unklar ist allerdings, wie viele Bytes so ein Zeiger hat. Ich habe auch schon mal ein paar Bytes mehr kopiert, keie Veränderung, noch nicht mal ein Absturz.

Hast Du eine Idee, wie man dem auf die Spur kommen könnte?

Gruß Rainer

Hallo Rainer.

Nicht wirklich eine Idee, dafür habe ich von Zeigern und API und all dem ganzen Kram leider zu wenig Ahnung.

Aber ich habe natürlich meine naiven Vorstellungen dazu und die sehen in etwa so aus:

Ich versuch ja schon lange selbst eine Software zu schreiben. In dieser Anwendung speichere ich als Variant deklarierte Arrays „auf Schlag“ mit „Open“ und „Put“ und „Close“ in Binär-Dateien mit der Erweiterung „.dat“.

Wenn ich mit jetzt überlege, daß ich ein Array, ganz gleich, wie groß es auch immer sein mag, sowieso Eintrag für Eintrag in einer Schleife nach irgendeinem Wert durchsuchen muß, dann halte ich persönlich es für sinnvoll, schon während des Durchsuchens innerhalb dieser Schleife einfach eine Kopie „mitzuschreiben“ und an der Fundstelle des Wertes dann neue Einträge (oder Zeilen, oder Datensätze) einzufügen.

Dann könnte man doch bestimmt auch in eine mit „For Random“ geöffnete Datei diese neuen Datensätze bereits während des Durchsuchens reinschreiben.

Ich finde diese Vorstellung eigentlich nicht mal naiv, denn das Array muß doch sowieso irgerndwo gespeichert werden.

Viele Grüße
Carsten

P.S. Ich gehe jetzt erstmal zum Frühstücken, hab’ nämlich Urlaub und bin durchaus entspannt.

Hallo Carstan,

Nicht wirklich eine Idee, dafür habe ich von Zeigern und API
und all dem ganzen Kram leider zu wenig Ahnung.

geht mir ähnlich. :smile: Wenn es nicht um Arrays aus Strings geht, dann ist mir das inzwischen klar, aber bei Strings eben gar nicht.

Aber ich habe natürlich meine naiven Vorstellungen dazu und
die sehen in etwa so aus:

Ich versuch ja schon lange selbst eine Software zu schreiben.
In dieser Anwendung speichere ich als Variant deklarierte
Arrays „auf Schlag“ mit „Open“ und „Put“ und „Close“ in
Binär-Dateien mit der Erweiterung „.dat“.

Hmmm, klar kann man das Array schnell auf die Platte schreiben, da bleibt aber immer noch der Festplattenzugriff und der ist sehr viel langsamer als ein Speicherzugriff.

Wenn ich mit jetzt überlege, daß ich ein Array, ganz gleich,
wie groß es auch immer sein mag, sowieso Eintrag für Eintrag
in einer Schleife nach irgendeinem Wert durchsuchen muß, dann
halte ich persönlich es für sinnvoll, schon während des
Durchsuchens innerhalb dieser Schleife einfach eine Kopie
„mitzuschreiben“ und an der Fundstelle des Wertes dann neue
Einträge (oder Zeilen, oder Datensätze) einzufügen.

Warum Reinhard Bereiche des Arrays kopieren möchte habe ich noch nicht verstanden, das ist halt Excel, da komme ich nicht mit. Ich kann mich nur auf den Umgang mit den Arrays beschränken.

Dann könnte man doch bestimmt auch in eine mit „For Random“
geöffnete Datei diese neuen Datensätze bereits während des
Durchsuchens reinschreiben.

Du willst die Datei ‚For Random‘ öffnen und dann gezielt auf einen Datensatz zugreifen? Das macht Ärger, die Datensatznummer ist Integer. :frowning: Da stößt man viel zu schnell an Grenzen, das stammt noch aus Zeiten, wo eine 500MB-Festplatte riesig war und sich die Entwickler Datenmengen mit mehreren Tausend Datensätzen nicht vorstellen konnten.

Ich finde diese Vorstellung eigentlich nicht mal naiv, denn
das Array muß doch sowieso irgerndwo gespeichert werden.

Das Array bleibt erst mal im Speicher, Reinhard möchte es ja an ein Listen-Steuerelement übergeben. Ob das dann so fesichert wird, oder ob das nur eine Anzeige ist, weiß ich nicht.

P.S. Ich gehe jetzt erstmal zum Frühstücken, hab’ nämlich
Urlaub und bin durchaus entspannt.

Na dann erhol Dich gut und genieße den Urlaub!

Gruß Rainer

Hallo Rainer.

Warum Reinhard Bereiche des Arrays kopieren möchte habe ich
noch nicht verstanden

Ich nämlich auch nicht.
Und: Befinden sich diese Listboxen auf einem UserForm oder auf dem Tabellenblatt? Keiner weiß es.
Eine Vermutung meinerseits ist auch, daß Reinhard möglicherweise so etwas in der Art wie einen „Katalog“ (ganz allgemein gesagt) in der Aufmachung eines Eigenschaften-Fensters aufbauen möchte, in die ein Benutzer irgendwelche Informationen einfügen kann. Daher auch meine erste Idee mit der „AddItem“-Methode.

Du willst die Datei ‚For Random‘ öffnen und dann gezielt auf
einen Datensatz zugreifen? Das macht Ärger, die
Datensatznummer ist Integer. :frowning: Da stößt man viel zu schnell
an Grenzen, das stammt noch aus Zeiten, wo eine
500MB-Festplatte riesig war und sich die Entwickler
Datenmengen mit mehreren Tausend Datensätzen nicht vorstellen
konnten.

Oh.

Na dann erhol Dich gut und genieße den Urlaub!

Danke, das werd’ ich versuchen

Viele Grüße
Carsten

Hallo Rainer,

Warum Reinhard Bereiche des Arrays kopieren möchte habe ich
noch nicht verstanden, das ist halt Excel, da komme ich nicht
mit.

nein, das hat mit Excel nix zu tun. Ich habe ein gefülltes Array a(5) das so im Speicher abgelegt ist (die Zahlen sind die Werte in dem Array):

1
2
3
4
5
6

Nun möchte ich es „vergrößern“ um einen Eintrag, damit es nachher so aussieht im Speicher:

1
2
3
Neuer Eintrag
4
5
6

Dazu kann ich mir ein neues leeres array b(6) anlegen, dann gehe ich das Array a einzeln durch und schaufle die ersten 3 Einträge in die drei ersten Einträge von b, dann schreibe ich den 4ten Eintrag in b hinein,dann schaufle ich die letzten 3 Einträge von a in die 3 letzten Einträge von b.

Das geht, kriegen wir alle hin.

Nun möchte ich aber auf einen Rutsch die ersten 3 Einträge in die 3 ersten Einträge von b kopieren und auch die 3 letzten Einträge von a in die 3 letzten Einträge von b kopieren. Darum geht es mir.

Trotz der Hilfe von Alex und Euch kriege ich das aber nichtmal mit einem eindimensionalen Array hin.

Die Codes von Alex habe ich stundenlang getestet in VB5.0 , ich glaube ich habe alle Varianten durchgespielt wo man strptr(), Byval, byref sowohl in den Aufrufen als auch in der API-Deklaration benutzen kann.

Ich glaube eine Lösung kann ich mir abschminken:frowning:
Denn erschwerdend kommt dazu, daß Originalarray um das es geht, wird beim Einlesen einer Textdatei erstellt, und ergibt dann ein Array von ca. a(45000,2) und alle Einträge sind Strings von unterschiedlicher Länge.

Soweit ich weiß wird das dann so im Speicher abgelegt, daß erst die 45000 Einträge mit dem Zweitindex 0 abgelegt werden, dann die nächsten 45000 Einträge mit dem zweitindex 1, dann die letzten 45000 Einträge mit dem Zweitindex 2.

Um da jetzt was in dieses Array „einzufügen“ müßte ich ja an drei Stellen etwas einfügen und die SpeicherAdressen dieser drei Stellen kenne ich ja nicht da die Einträge unterschiedliche Bytelängen haben.

Würde ich diese Speicheradressen kennen könnte ich ja mit rtlmovememory die nachfolgenden Einträge verschieben um da was einzutragen.

Theoretisch bin ich mir sehr sicher die Lösung zu kennen wie man das lösen kann.
Angenommen ich habe das Array a(45000,2) und ich möchte dort wo in a(x,1) das Wort „Huhu“ steht, etwas einfügen.
Dann muß ich nur ab der Startspeicheradresse vom Array a nach dem Wort „Huhu“ suchen.
Wenn ich jetzt die Speicheradresse des Wortes „Huhu“ kenne, nützt mir das erstmal nix.
Aber, soweit ich weiß hat jeder Eintrag in einer Arrayliste die im Speicher steht hinten eine 0 o.ä.
Wenn ich nun ermitteln könnte wieviele „Nullen“ es zzwischen der Startadresse des Array und dem Eintrag „Huhu“ gibt, so kann ich daraus berechnen, daß das Wort „Huhu“ in a(32378,1) stehen muß.
Auch durch Zählung der „Nullen“ kriege ich dann raus wo im Speicher a(32378,0) und a(32378,2) abgelegt wurde.
Dann könnte ich durch dreimaliges „Move“ das Problem lösen.

Soweit die Theorie :smile:

Ich hoffe ich konnte mich einigermaßen verständlich machen :smile:

Das Array bleibt erst mal im Speicher, Reinhard möchte es ja
an ein Listen-Steuerelement übergeben. Ob das dann so
fesichert wird, oder ob das nur eine Anzeige ist, weiß ich
nicht.

Letzlich soll die reine Ausgabe dann doch in Excel erfolgen. Aber ich wollte es ja umbauen sodaß man das Ergebnis in einer VB-Listbox sieht.
Leider weigert sich meine Listbox in VB5.0 beharrlich mehrere Spalten anzuzeigen. Hinweise auf ListView brachten mir nix, weil ich die bei VB5.0 nicht finde :frowning:

Danke an alle die sich einen Kopf machen um mir da zu helfen mit dem Problem der Arrayumverschiebung.
Gruß
Reinhard

Hallo Reinhard,

nein, das hat mit Excel nix zu tun. Ich habe ein gefülltes
Array a(5) das so im Speicher abgelegt ist (die Zahlen sind
die Werte in dem Array):

OK.

1
2
3
4
5
6

Nun möchte ich es „vergrößern“ um einen Eintrag, damit es
nachher so aussieht im Speicher:

1
2
3
Neuer Eintrag
4
5
6

Auch OK. Mit Zahlen kein Problem.

Private Declare Sub CopyMemory Lib "kernel32" \_
 Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
 ByVal ByteLen As Long)

Dim Arr() As Byte

Private Sub Command1\_Click()
 Dim Pos As Long, i As Integer
 Pos = 3 '




> Dazu kann ich mir ein neues leeres array b(6) anlegen, dann  
> gehe ich das Array a einzeln durch und schaufle die ersten 3  
> Einträge in die drei ersten Einträge von b, dann schreibe ich  
> den 4ten Eintrag in b hinein,dann schaufle ich die letzten 3  
> Einträge von a in die 3 letzten Einträge von b.  
>   
> Das geht, kriegen wir alle hin.


Ja, auch ohne neues Array. :smile:



> Nun möchte ich aber auf einen Rutsch die ersten 3 Einträge in  
> die 3 ersten Einträge von b kopieren und auch die 3 letzten  
> Einträge von a in die 3 letzten Einträge von b kopieren. Darum  
> geht es mir.


Wenn Du unbedingt zwei Arrays willst, das geht genau so.



    
    
    Private Declare Sub CopyMemory Lib "kernel32" \_
     Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, \_
     ByVal ByteLen As Long)
    
    Dim a() As Byte
    Dim b() As Byte
    
    Private Sub Command1\_Click()
     Dim Pos As Long, i As Integer
     Pos = 3 '
    
    
    
    > Trotz der Hilfe von Alex und Euch kriege ich das aber nichtmal  
    > mit einem eindimensionalen Array hin.
    
    
    Das muss aber jetzt auch bei Dir laufen, ist getestet.
    
    
    
    > Die Codes von Alex habe ich stundenlang getestet in  
    > **<u>VB5.0</u>** , ich glaube ich  
    > habe alle Varianten durchgespielt wo man strptr(), Byval,  
    > byref
    
    
    Brauchst Du bei Arrays nicht. Einfach weg lassen und nur das Feld des Arrays schreiben. Das wird Dein Problem gewesen sein.
    
    
    
    > sowohl in den Aufrufen als auch in der API-Deklaration  
    > benutzen kann.  
    >   
    > Ich glaube eine Lösung kann ich mir abschminken:frowning:  
    > Denn erschwerdend kommt dazu, daß Originalarray um das es  
    > geht, wird beim Einlesen einer Textdatei erstellt, und ergibt  
    > dann ein Array von ca. a(45000,2) und alle Einträge sind  
    > Strings von unterschiedlicher Länge.
    
    
    
    Das ist der Punkt. Sobald das Array als String deklariert ist, funktioniert das so nicht mehr. Ob und wie das dann geht, habe ich keine Ahnung. Dafür habe ich noch keine Lösung gesehen.
    
    
    
    > Soweit ich weiß wird das dann so im Speicher abgelegt, daß  
    > erst die 45000 Einträge mit dem Zweitindex 0 abgelegt werden,  
    > dann die nächsten 45000 Einträge mit dem zweitindex 1, dann  
    > die letzten 45000 Einträge mit dem Zweitindex 2.
    
    
    Das zweidimensionale Array ist eher nicht das Problem. Das Problem sind die Strings!
    
    
    
    > Um da jetzt was in dieses Array "einzufügen" müßte ich ja an  
    > drei Stellen etwas einfügen und die SpeicherAdressen dieser  
    > drei Stellen kenne ich ja nicht da die Einträge  
    > unterschiedliche Bytelängen haben.
    
    
    Zumal Du da nichts verändern kannst. So einfach ist es nicht.
    
    
    
    > Würde ich diese Speicheradressen kennen könnte ich ja mit  
    > rtlmovememory die nachfolgenden Einträge verschieben um da was  
    > einzutragen.
    
    
    Nein. Nur die Zeiger stehen in einem Zusammenhängenden Speicherbereich. Die einzelnen Strings werden an zufällig freie Speicheradressen geschrieben, stehen nicht direkt hintereinender. 
    
    
    
    > Theoretisch bin ich mir sehr sicher die Lösung zu kennen wie  
    > man das lösen kann.
    
    
    Du warst Dir sicher, weil Du fälschlicher Weise angenommen hast, daß das Array in der richtigen Reihenfolge in einem zusammenhängenden Speicherbereich steht. Das war ein Irrtum.
    
    
    
    > Angenommen ich habe das Array a(45000,2) und ich möchte dort  
    > wo in a(x,1) das Wort "Huhu" steht, etwas einfügen.  
    > Dann muß ich nur ab der Startspeicheradresse vom Array a nach  
    > dem Wort "Huhu" suchen.  
    > Wenn ich jetzt die Speicheradresse des Wortes "Huhu" kenne,  
    > nützt mir das erstmal nix.  
    > Aber, soweit ich weiß hat jeder Eintrag in einer Arrayliste  
    > die im Speicher steht hinten eine 0 o.ä.
    
    
    Nein. Diese 'Arrayliste' gibt es so nicht. Es gibt ein eigenes Array, in dem die Zeiger auf die Strings stehen. Das habe ich erfolglos versucht zu manipulieren. :frowning:
    
    
    
    > Wenn ich nun ermitteln könnte wieviele "Nullen" es zzwischen  
    > der Startadresse des Array und dem Eintrag "Huhu" gibt, so  
    > kann ich daraus berechnen, daß das Wort "Huhu" in a(32378,1)  
    > stehen muß.  
    > Auch durch Zählung der "Nullen" kriege ich dann raus wo im  
    > Speicher a(32378,0) und a(32378,2) abgelegt wurde.  
    > Dann könnte ich durch dreimaliges "Move" das Problem lösen.  
    >   
    > Soweit die Theorie :smile:
    
    
    Leider falsch. 
    
    
    
    > Ich hoffe ich konnte mich einigermaßen verständlich machen :smile:
    
    
    Ja, das schon, aber Du hast eine falsche Vorstellung. So wie du dachtest, wird das Array nicht verwaltet.
    
    
    
    > > Das Array bleibt erst mal im Speicher, Reinhard möchte es ja  
    > > an ein Listen-Steuerelement übergeben. Ob das dann so  
    > > fesichert wird, oder ob das nur eine Anzeige ist, weiß ich  
    > > nicht.
    > 
    >   
    > Letzlich soll die reine Ausgabe dann doch in Excel erfolgen.  
    > Aber ich wollte es ja umbauen sodaß man das Ergebnis in einer  
    > VB-Listbox sieht.  
    > Leider weigert sich meine Listbox in VB5.0 beharrlich mehrere  
    > Spalten anzuzeigen.
    
    
    Das geht schon, aber sehr schlecht zu handhaben und sieht auch nicht gut aus. Stell mal bei List2 Die Eigenschaft 'Columns' auf 3 und dann:
    
    
    
        
        
        Private Sub Command2\_Click()
         Dim c As Integer, r As Integer
         For i = 1 To 4
         List2.AddItem " "
         Next
         For r = 0 To 4
         List2.List(r) = CStr(r) + Chr(9) + "a" + Chr(9) + "b"
         Next
        End Sub
        
    
    
    
    
    Übel, finde ich. :frowning:
    
    
    
    > Hinweise auf ListView brachten mir nix,  
    > weil ich die bei VB5.0 nicht finde :frowning:
    
    
    Und das MsFlexgrid? Sag bloß, das hast Du auch nicht. Auch nicht unter Projekte/Komponenten? 
    
    Gruß Rainer

Hallo Jungs,

ich antworte nun mal nicht jeden einzeln.
Ihr macht euch das alles viel zu schwer oder denkt zu kompliziert :s

Schauen wir doch einmal uns das alles genauer an!

Bei der API CopyMemory wird einmal nach der Destination gefragt, dann noch nach der Source Quelle und dann noch einmal nach der Grösse.

Die Destination, sowie die Source sind kein Thema! Der Hund ist bei der Grösse begraben.

Wenn wir nun einmal ueberlegen, wie man das am besten löst fallen einem doch spontan 2 wege ein! Entweder man vergibt im Vorfeld schon eine Fixe Grösse. Diese kann man dann angeben. Also Grösse *2 ist ja klar :wink:( VB speichert intern String im Unicode Format ab, deswegen 2 Byte anstatt nur 1!)
Aber da stellt sich die Frage. Was für ein Daten Volumen kommen an Daten an. VB Strings koennen glaub bis zu max. 2 GB an Daten aufnehmen. Also verwerfen wir die Idee mal wieder ganz fix!

Für alle die es dennoch interessiert.

Public Function CopyString(ByVal Pointer As Long, ByVal Size As Long)As String
 Dim nString As String
 Dim nPos As Long
 nString = String$(Size, 0)
 CopyMemory ByVal StrPtr(nString), ByVal Pointer, Size \* 2
 nPos = InStr(nString, Chr(0))
 If nPos Then
 PtrStr = Mid$(nString, 1, nPos - 1)
 Else
 PtrStr = nString
 End If
End Function

Wenn wir nun einmal weiter überlegen. Hmm, welche Datentypen unter VB koennen Strings speichern. Da haetten wir einmal den String, der aber flexibel ist und wir die Grösse nicht wissen!
Dann haetten wir noch den Datentyp Variant! Und genau dem machen wir uns zu nutzen. Der Datentyp Variant kann alles mögliche beinhalten, also auch Strings. dabei interessiert die Länge nicht! der Datentyp Variant brauch 16 Byte!
Also schreiben wir den ganzen Kram halt auf Variant. Benötigt man später dann die Daten so kann man sie jederzeit wieder in einen String umwandeln :wink:

Speziell für Reinhard, wo ich mal hoffe das ich nun richtig liege.

'Demo mit 1000 Daten!
'eine Form erstellen.
'Darauf 2 listboxen ( List1 und List2)
'Ein Command Button ( Command1)
'List1 zeigt die Daten im Array A an und List2 die Daten im Array B

Option Explicit


Private Declare Sub Copy Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)


Dim a() As Variant
Dim b() As Variant
Dim Loading As Boolean

Private Sub Command1\_Click()
On Error Resume Next
Dim Count As Variant
Dim vData As String
Count = InputBox("Ab welcher Position einfügen?")
If IsNumeric(Count) Then
 If Count \> UBound(a) Or Count "" Then
 List2.AddItem b(i)
 End If
Next
Screen.MousePointer = 0
End Sub

Private Sub Form\_Activate()
Dim i As Long
Dim j As Byte
Dim k As Integer
If Loading Then
 Screen.MousePointer = 11
 Me.Caption = "Lade Daten"
 Loading = Not Loading
 ReDim a(1000)
 ReDim b(UBound(a) + 1)
 For i = 0 To 1000
 k = Int(Rnd \* 30) + 1
 For j = 1 To k
 a(i) = a(i) + Chr(Int((26 \* Rnd) + 1) + 65)
 Next j
 List1.AddItem a(i)
 Me.Caption = "Lade Daten [" & i & "/1000]"
 If i Mod 1000 = 0 Then DoEvents
 Next i
End If
Me.Caption = "Bereit"
Screen.MousePointer = 0
End Sub

Private Sub Form\_Load()
 Loading = True
End Sub

MfG Alex

1 Like

Hallo Jungs,

Hallo Alex!

ich antworte nun mal nicht jeden einzeln.
Ihr macht euch das alles viel zu schwer oder denkt zu
kompliziert :s

hmmm, die Lösung habe ich noch nie gesehen, SUPER !!! Schon gesichert! :smile:

Ja, das ist exakt das, was Reinhard gesucht hat und was ich nicht gefunden habe.

Gruß Rainer

Hallo Rainer,

hmmm, die Lösung habe ich noch nie gesehen, SUPER !!! Schon
gesichert! :smile:

Marke Eigenbau mit ca. 10 Minuten Arbeit *zwinker*

Ja, das ist exakt das, was Reinhard gesucht hat und was ich
nicht gefunden habe.

Da waerst du auch selbst darauf gekommen, wenn du nicht zu kompliziert gedacht haettest. Waerst du auf die Idee gekommen die Daten in ein Variant Feld abzulegen haettest du das auch binnen paar Minuten hinbekommen :smile: Ansonsten haettet man es halt mit einem String einer Fixen Grössen lösen koennen :smile: Dazu habe ich dir ja auch den Weg gezeigt.
Aber warum verwendet Reinhard bei solch einem Datenvolumen nicht eine Klasse und daraus eine Collection? Da ist er flexibler :wink:

Aber schön das wir es nun geschafft haben, Reinhard zu helfen. Da wird er sich sicher freuen und sein Vorhaben nicht aufgeben :wink:

Er muss nur darauf achten das er sich so den Speicher sinnlos zu müllt und das frueher oder später zu abstuerzen führen kann!

MfG Alex

Ein Zeiger lässt sich ja kopieren und ich hätte erwartet, daß
die Zeiger hintereinander stehen. Unklar ist allerdings, wie
viele Bytes so ein Zeiger hat. Ich habe auch schon mal ein
paar Bytes mehr kopiert, keie Veränderung, noch nicht mal ein
Absturz.

Ein Zeiger ist nichts weiter als eine Variable vom Typ Long. Ein Zeiger wird im Stack abgelegt, beinhaltet die Adresse der Daten im Heap und zeigt auf diese. Also ist die Grösse eines Zeigers immer 4 Byte!

MfG Alex

Hi Alex,

Ein Zeiger ist nichts weiter als eine Variable vom Typ Long.
Ein Zeiger wird im Stack abgelegt, beinhaltet die Adresse der
Daten im Heap und zeigt auf diese. Also ist die Grösse eines
Zeigers immer 4 Byte!

danke. Inzwischen hatte ich ein wenig ‚Grundlagenforschung‘ :smile: betrieben und habe gesehen, daß das vier Bytes sind. Mein erster Versuch, die zu verbiegen ist allerdings gescheitert. Ich habe inzwischen eine vage Vermutung, warum und wie man das eventuell umgehen kann. Ich werde jetzt aber aufhören, mir das Hirn zu zermartern wo da die Probleme liegen und wie man das eventuell doch noch packen könnte, Deine Lösung mit Hilfe von ‚Variant‘ funktioniert ja perfekt. Warum muss ich ja nicht unbedingt verstehen.

Gruß Rainer