Vektor an Funktion übergeben und verändern

Gast #2557628
Lesenswert?

Hi

Folgende Prozedur sollte eignetlich die Werte eines Vektors 
inintialisieren.
Das macht sie aber nicht.
1
typedef int TVector[3];
2

3
void InitVec(TVector* Vector, int a, int b, int c)
4
{
5
   *Vector[0] = a;
6
   *Vector[1] = b;
7
   *Vector[2] = c;
8
}

Der erste Wert stimmt, der zweite schon nicht mehr.

Was ist hier bitte falsch?

Danke Andy
Gast #2557638
Lesenswert?

ich vermute mal hier gibt es einen konflikt zwischen einen Vektor und 
einer Liste von Vektoren. ein Typedef mit array zusammen habe ich noch 
nie verwedet.

Mach das ganze als Struct dann ist es auch für jeden lesbar und 
verständlich.
Gast #2557645
Lesenswert?

@Karlheinz: Danke für den Hinweis

Hm, wenn ich aber
1
  Vector[0] = a;
2
  Vector[1] = b;
3
  Vector[1] = c;
schreibe, dann sagt mit der Compiler, es sei "incompatible types in 
assignment".

..oder bzw. wie kann ich auf das zweite Element zugreifen. Im Speicher 
stehen die Elemente ja hintereinander. Habe schon die Adresse um 4 
erhöht, und dann zugeweisen. Das sieht aber dann nicht sehr elegant 
aus:)
#2557646
Lesenswert?

Der * Operator dereferenziert dir eine Adresse (Liefert also den Wert 
der an der Adresse steht)
Der [] macht das auch nur in Array Schreibweise. [2] dereferenziert dir 
das 2. Arrayelement ausgehend von der Startadresse (Und deiner Funktion 
wird ja die Startadresse deines Arrays übergeben). Coolerweise kann man 
beide Schreibweisen mischen solange man weiß was man macht ;-)

Peter II schrieb:
> Mach das ganze als Struct

Würd ich nicht machen. Solange die Datentypen all deiner Containerwerte 
gleich sind ist ein Array sicher eine gute Wahl.

L.g.
#2557694
Lesenswert?

Wenn ich jetzt meine doch ziemlich eingerosteten C Kenntnisse 
zusammenklaube würde ich sagen Stefan Ernsts Variante müsste so korrekt 
sein.

Die eigentlich Frage ist aber warum muss der TO so ein krankes typedef 
machen.
Braucht er wirklich zigmal einen Variablentyp mit 3 Integer (z.B. 
3-dimensionale Koordinate im Raum), warum macht er dann nicht ein struct 
und benennt die einzelnen Variablen sauber.
Ich habe viele Jahre C programmiert, das ist schon einige Jahre her aber 
ich glaube so ein Typedef habe ich noch nie benötigt.
Gast #2557713
Lesenswert?

@Michael: Danke für die Infos. Die aktuelle Datanstruktur gefällt mir 
auch besser weil man sich Schreibarbeit erspart und das Ganze sehr gut 
lesbar ist.

@Joachim: Danke! Wie greifst du aber auf das nächste Element zu?

@Stefan: Danke, das funktioniert einwandfrei. Auch der Variablenzugriff 
funktionert sehr schnell. Beim dsPic 37 Instruktionen für
1
int8_t InitVec(TVector *Vector, int32_t a, int32_t b,int32_t c,int32_t d)
2
{
3
  (*Vector)[0] = a; // 5 Instruktionen
4
  (*Vector)[1] = b; // 5 Instruktionen
5
  (*Vector)[2] = c; // 5 Instruktionen
6
}


Interessant dünkt mich, dass die Anweisung
1
int8_t InitVec(TVector *Vector, int32_t a, int32_t b,int32_t c,int32_t d)
2
{
3
  (*TVector)[0] = a; // syntax error
4
  (*TVector)[1] = b; 
5
  (*TVector)[2] = c; 
6
}

Haber es so gelesen, als sei es eine Typenkonvertierung.

Beste Grüsse

Stefan
Gast #2557721
Lesenswert?

@Udo: Erst jetzt gelesen. Wenn ich gewusst hätte, dass es zu solchen 
Problemen kommt, dann hätte ich vieleicht auch eine Struktur definiert.

Kannst du bitte begründen wieso die Definition bitte nicht sauber sein 
soll?
#2557750
Lesenswert?

Andreas schrieb:

> Kannst du bitte begründen wieso die Definition bitte nicht sauber sein
> soll?

Weil Arrays in C Bastarde sind, die sich in einigen Bereichen anders 
verhalten als jede anderer Variablentyp. Krass ausgedrückt: Ein Array 
ist selten ein vernünftiger 'Datentyp'. Und genau so, als Datentyp, 
versuchst du hier ein Array zu verwenden. Verwende Arrays als das was 
sie gedacht sind: als einfaches Mittel zur Datenhaltung. Aber nicht um 
damit einen Datentyp aufzubauen. Das ist am Ende praktisch immer mehr 
Arbeit, als wie wenn man gleich eine saubere struct aufbaut.


1
typedef struct
2
{
3
  int x;
4
  int y;
5
  int z;
6
} TVector;
und du hast einen Datentyp der sich sauber verhält
1
void InitVec(TVector* Vector, int a, int b, int c)
2
{
3
   Vector->x = a;
4
   Vector->y = b;
5
   Vector->z = c;
6
}
7

8
TVector AddVec( TVector a, TVector b )
9
{
10
  TVector result = { a.x + b.x, a.y + b.y, a.z + b.z };
11
  return result;
12
}
13

14
int main()
15
{
16
  TVector CircumPoint;
17
  TVector CenterPoint;
18

19
  InitVec( &CenterPoint, 2, 3, 0 );
20

21
  double Radius = 5.0;
22
  TVector Offset = { Radius, 0, 0 };
23
  CircumPoint = AddVec( CenterPoint, Offset );
24

25
  ...
#2557775
Lesenswert?

Karl Heinz Buchegger schrieb:
> typedef struct
> {
>   int x;
>   int y;
>   int z;
> } TVector;
> und du hast einen Datentyp der sich sauber verhältvoid InitVec(TVector* Vector, 
int a, int b, int c)
> {
>    Vector->x = a;
>    Vector->y = b;
>    Vector->z = c;
> }

Dazu war ich zu faul zum Schreiben. Danke Karl Heinz.

Wenn man dem Ding jetzt noch einen sprechenden Namen gibt wie z.B. 
"CubicVektor", dann wüsste man sogar schon am Typ dass es sich um einen 
3-Dimensionalen Vektor (Vektor im geometrischen Sinne) handelt.
Gast #2557778
Lesenswert?

@Karl Heinz: Danke, und Ok, von dem Standpunkt aus, dass es sich 
wirklich nur für einfache Listen gedacht sind, dann kann ich es 
nachvollziehen.

...siehst in dieser Defintion auch so einen Stilbruch?
1
#define MAX_DIM 3
2

3
typedef struct 
4
{
5
  int32_t x[MAX_DIM];
6
}TVector;


Diese Lösung hat halt den grossen Vorteil, dass man auf die Elemente 
einfach über Schleifen zugreifen kann. Wenn ich also später eine 
Dimension hinzufüge, dann muss ich an weniger stellen ändern.

z.B.
1
void Init0Vector(TVector* Vector)
2
{
3
  int i;
4
  for (i=0; i<MAX_DIM; i++
5
   Vector->x[0] = 0;
6
}
#2557789
Lesenswert?

Joachim Drechsel schrieb:
> TVector AddVec( TVector a, TVector b )
> {
>   TVector result = { a.x + b.x, a.y + b.y, a.z + b.z };
>   return result;
> }
>
> result liegt dann auf dem Stack ...

macht ja nix.
Lass den Compiler optimieren, wenn der Compiler das kann hilf ihm mit 
einem 'inline' an der richtigen Stelle und das ist genauso effizient, 
wie wenn man das selbst ausschreibt.
#2557791
Lesenswert?

Andreas schrieb:
> Diese Lösung hat halt den grossen Vorteil, dass man auf die Elemente
> einfach über Schleifen zugreifen kann. Wenn ich also später eine
> Dimension hinzufüge, dann muss ich an weniger stellen ändern.

Das ist doch eine Milchmädchenrechnung, Ein 4-dimensinaler vektor ist 
ein ganz neuer Datentyp, also sollte man da auch einen neuen definieren.
Mit deinem Array verlierst du jegliche Kontrolle wo jetzt welcher Wert 
drinsteht.
Was nützt dir deine for Schleife wenn du dann 4 statt 3 Werte zum 
initialisieren übergeben musst?

Joachim Drechsel schrieb:
> TVector AddVec( TVector a, TVector b )
> {
>   TVector result = { a.x + b.x, a.y + b.y, a.z + b.z };
>   return result;
> }
>
> result liegt dann auf dem Stack ...

Uuups das hatte ich nicht gesehen, hier sollte man eher dem Vector a den 
Vector b dazuaddieren. Dadurch dass man keinen returnwert definiert und 
Vector b als const deklariert würde das auch deutlich.
#2557793
Lesenswert?

Karl Heinz Buchegger schrieb:
> Joachim Drechsel schrieb:
>> TVector AddVec( TVector a, TVector b )
>> {
>>   TVector result = { a.x + b.x, a.y + b.y, a.z + b.z };
>>   return result;
>> }
>>
>> result liegt dann auf dem Stack ...
>
> macht ja nix.
> Lass den Compiler optimieren, wenn der Compiler das kann hilf ihm mit
> einem 'inline' an der richtigen Stelle und das ist genauso effizient,
> wie wenn man das selbst ausschreibt.

Sorry Karl Heinz das verstehe ich jetzt nicht. Result liegt als lokale 
Variable auf dem Stack und wird ungültig wenn die Funktion beendet wird.
#2557795
Lesenswert?

Andreas schrieb:
> ...siehst in dieser Defintion auch so einen Stilbruch?

ist schon besser.
Dadurch, dass du das Array in eine struct eingebettet hast, hast du es 
wieder zu einem 'normalen' Datentyp gemacht. Wie gesagt: Das 
Hauptproblem in C besteht darin, dass Arrays sich anders verhalten.

> Diese Lösung hat halt den grossen Vorteil, dass man auf die Elemente
> einfach über Schleifen zugreifen kann. Wenn ich also später eine
> Dimension hinzufüge, dann muss ich an weniger stellen ändern.

:-)
Ganz ehrlich.
Ich arbeite jetzt seit 30 Jahren im Bereich Computergrahik. Und am 
Anfang hab ich auch gedacht: Wenn da noch eine Dimension dazukommt ....
Die Anzahl der Fälle, in denen das tatsächlich notwendig war, konnte ich 
an 2 Fingern abzählen :-)
#2557803
Lesenswert?

Andreas schrieb:
> ...siehst in dieser Defintion auch so einen Stilbruch?#define MAX_DIM 3
>
> typedef struct
> {
>   int32_t x[MAX_DIM];
> }TVector;

Das könnte man machen, hat aber den gravierenden Nachteil, daß man nicht 
weiss welche Dimension jetzt dieser Vektor tatsächlich hat. Um irgendwas 
damit tun zu können brauchst du zumindest die aktuelle Dimension.
#2557813
Lesenswert?

Udo Schmitt schrieb:

> Sorry Karl Heinz das verstehe ich jetzt nicht. Result liegt als lokale
> Variable auf dem Stack und wird ungültig wenn die Funktion beendet wird.

Wie gesagt: macht ja nix.
Ich gebe ja keinen Pointer darauf als Returnwert heraus

int twice( int j )
{
  int k = 2 * j;
  return k;
}

k liegt auf dem Stack und wird aus der Funktion herausgegeben. Kein 
Problem. Und mit Strukturen funktioniert das genauso.

> Uuups das hatte ich nicht gesehen, hier sollte man eher dem Vector a
> den Vector b dazuaddieren.

Kannst du natürlich machen. Das entspricht dann aber einem += Operator 
und keinem + Operator mehr.

> Dadurch dass man keinen returnwert
> definiert und Vector b als const deklariert

Die Notation, dass man Strukturen auch per Kopie übergeben kann, ist dir 
noch nicht wirklich geläufig, oder?
Gast #2557839
Lesenswert?

@Karl Heinz:

Im Bereich der Computergrafik änderen sich die Dimensionen 
warhscheinlich nicht so oft.

Wenn man aber Firmware für Mikrocontroller schreibt, dann möchte man 
Speicher sparen und wenn man nun eine generelle Vector-Bibliothek 
erstellen möchte, die dann anwendungsspezifisch angepasst werden kann, 
dann wäre es schon sehr praktisch.


Bzgl. Variabenzugriff über Schleifen: Es ist schon eine erhebliche 
Erleichterung. Ich habe jetzt aber gram mal meinen Code durchgeschaut 
und geprüft, an welchen Stellen Schleifenaufrufe drin sind. Es sind 
nicht viele:) Ein Grund ist aber auch, dass eine Schleife auch wieder 
Zeit benötigt und man diese Ressource auch sparen möchte:) Das spricht 
dann wieder würd dich:)


@Joachim: Für den Zugriff könnte man ja auch defines oder sets 
verwenden. Damit könnte man dann auch die Lesbarkeit erhöhen
1
#define _x  0
2
#define _y  1
3
#define _z  2

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren