Forum: Compiler & IDEs Vektor an Funktion übergeben und verändern


von Andreas (Gast)


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

von Karl H. (kbuchegg)


Lesenswert?

Andreas schrieb:

> void InitVec(TVector* Vector, int a, int b, int c)

Hier bekommst du einen Pointer auf das erste Element im Array.

>    *Vector[0] = a;

Die Arrayindizierung beinhaltet bereits das Dereferenzieren des 
Pointers.

     Vector[0] = a;

von Peter II (Gast)


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.

von Andreas (Gast)


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:)

von Michael R. (dj_motionx)


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.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Halt einen Zeiger auf einen Zeiger übergeben, änderst Du dessen
Inhalt ...
1
void InitVec(TVector **Vector, int a)
2
{
3
   *Vector = a;
4
}

von Stefan E. (sternst)


Lesenswert?

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

von Udo S. (urschmitt)


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.

von Andreas (Gast)


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

von Andreas (Gast)


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?

von Karl H. (kbuchegg)


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
  ...

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

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 ...

von Udo S. (urschmitt)


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.

von Andreas (Gast)


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
}

von Karl H. (kbuchegg)


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.

von Udo S. (urschmitt)


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.

von Udo S. (urschmitt)


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.

von Karl H. (kbuchegg)


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 :-)

von Udo S. (urschmitt)


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.

von Joachim D. (Firma: JDCC) (scheppertreiber)


Lesenswert?

Ich würde auch in der Struktur die Variablen benennen anstatt nur ein
Array zu verwenden, alleine schon wegen der Lesbarkeit (kann ja sein,
auch andere möchten das mal verwenden oder man schaut sich das nach
einem Jahr mal wieder an).

von Karl H. (kbuchegg)


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?

von Udo S. (urschmitt)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Die Notation, dass man Strukturen auch per Kopie übergeben kann, ist dir
> noch nicht wirklich geläufig, oder?

Nein, nicht so. Reden wir jetzt von c oder c++?
Aber wie gesagt, c habe ich in den letzten 6-7 Jahren so gut wie nicht 
mehr benutzt, und c++ vorher nicht viel und dann gar nicht mehr.

von Andreas (Gast)


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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.