Forum: PC-Programmierung Array Pointer Problem


von Lars (Gast)


Lesenswert?

include.h
___________________________________________________
typedef struct
{
   Uint uifile;
   Uint *nnel;
} Block;


extern Block Per[2];
______________________________________END INCLUDE.h


main.c
_____________________________________________________
#include <include.h>


Uint AC[] =
{
   10,
   20,
};

Uint DC[] =
{
   30,
   40
};

Block Per[] =
{
   {
      Ai, AC
   },
   {
      Di, DC
   }
};

unsigned short int Get 1(Uint uifile)
{

...........
}

unsigned short int Get 2 (Uint uifile)
{
   ......
}

__________________________ END MAIN

Get 1 soll folgendes machen. Suche in Block Per[] ob uifile = Ai 
vorhanden ist, Wenn ja suche in AC[] nach einer nummer z.B 10 und return 
den Index dieser nummer. Oder wenn Ui vorhanden ist in DI[]suchen.

Get 2 soll anhand des festgestellten Index aus get 1 nun rückschliessen 
auf die nummer des jewieligen Index. Beispielsweise soll bei Index 1 
innerhalb von AC dann die Zahl 20 return werden.

WIe kann man das machen?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Get1 und Get2 passen nicht zueinander. Get1 soll einen Index in per 
liefern (für Get2) und einen Index einer Zahl in dem Array per[].nnel 
sichten und diesen Index auch zurückliefern. Das sind zwei 
Informationen, die zurückzugeben sind. Nur mit einem Index kommt du 
nicht an die Zahl ran.

Aber ich könnte mir vorstellen, dass Get1 den Index-aus-Per 
zurückliefert, bei dem uifile eingetragen ist.

Ich könnte mir dann vorstellen, dass Get2 den von Get1 ermittelten 
Index-von-Per benutzt, um das Array (AC oder DC) zu finden und dessen 
Elemente abzuklopfen, ob sie einer gesuchten Zahl entsprechen. Dieser 
ware dann Index-in-xC.

Was dir dann noch in der Sammlung fehlt, ist eine Get3, die mit den 
Indices aus Get1 (Index-aus-Per ) und Get2 (Index-in-xC) den Wert aus 
deinem Datenfeld xC heraus fischt.

Bei der Implementierung brauchst du ausserdem Informationen wie gross 
deine Arrays sind. Also musst du entweder die Elementanzahl in [] 
eintragen oder einen Stopperwert fürs Durchsuchen als letztes Element in 
den Arrays eintragen.

von Karl H. (kbuchegg)


Lesenswert?

Zunächst mal solltest du in die Struktur 'Block' noch die
Größe des Arrays eintragen. Zur Laufzeit ist diese Information
aus einem Block Objekt nicht mehr ableitbar, also muss sie
dort gespeichert werden:
1
typedef struct
2
{
3
   Uint uifile;
4
   Uint nnelSize;
5
   Uint *nnel;
6
} Block;
7
8
9
Uint AC[] = { 10, 20 };
10
Uint DC[] = { 30, 40 };
11
12
#define ARRAY_SIZE(x)  (sizeof(x) / sizeof(*x) )
13
14
Block Per[] =
15
{ { Ai, ARRAY_SIZE(AC), AC  },
16
  { Di, ARRAY_SIZE(DC), DC  }
17
};
18
19
//
20
// Suche in Block Per[] ob uifile = Ai
21
// vorhanden ist, Wenn ja suche in AC[] nach einer
22
// nummer z.B 10 und return den Index dieser nummer.
23
//
24
// Return: Index des gesuchten Elements
25
//         -1   element nicht gefunden
26
//         -2   uifile nicht gefunden
27
//
28
int Get_1( Uint uifile, uint element )
29
{
30
  size_t i, j;
31
32
  for( i = 0; i < ARRAY_SIZE(Per); ++i ) {
33
34
    if( Per[i].uifile == uifile ) {
35
36
      for( j = 0; j < Per[i].nnelSize; ++j ) {
37
        if( Per[i].nnel[j] == element )
38
          return j;
39
      }
40
41
      return -1;
42
    }
43
  }
44
45
  return -2;
46
}
47
48
Uint Get_2( Uint uifile, int index )
49
{
50
  size_t i;
51
52
  for( i = 0; i < ARRAY_SIZE(Per); ++i ) {
53
54
    if( Per[i].uifile == uifile ) {
55
      if( index < 0 || index >= Per[i].nnelSize )
56
        return 0;
57
58
      return Per[i].nnel[index];
59
    }
60
  }
61
62
  return 0;
63
}

Für die 2.te Funktion musst du dir noch was überlegen, wie du den
Fehlerfall handhaben willst. Im Moment wird immer 0 retourniert.
Wenn 0 in deinen Daten nicht vorkommt, dann ist das ok, ansonsten
musst du mit dem Returnwert noch was anfangen. Für Get_1 hab ich
mir die Freiheit genommen und den Returnwert von Uint (wie er
eigentlich sein sollte) auf int geändert, damit ich 2 spezielle
Werte als Fehlerindikator durchbringe.

von Lars (Gast)


Lesenswert?

Das habe ich bisher..

unsigned short int get1 (Uint file, Uint *nnel)
{
   Uint ui,uo = 0;
   for (ui;ui<=sizeof Per; ui++)
   {
      if(BlockPer[ui] == file)
      {
         if (file == Ai)
         {
            nel = &AI[0];
            for (ui;ui<=sizeof AI; ui++)
            {
               nnel++;
               if(gesuchter_index == nnel)
               {
                  return gesuchter_index;
               }
            }
         }
         if (uiProfile == iProfFDi)
         {
            ... ähnlich wie oben
         }

      }
   }
}

geht das?

von Lars (Gast)


Lesenswert?

ah jetzt sehe ich erst die Antwort. Mal sehn ob es geht. Besten Dank

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> Das habe ich bisher..
>
> unsigned short int get1 (Uint file, Uint *nnel)
> {
>    Uint ui,uo = 0;

Beachte: ui ist nicht initalisiert

>    for (ui;ui<=sizeof Per; ui++)

ui ist nach wie vor nicht initialisiert.
sizeof liefert die Größe des Objektes (in dem Fall Per)
in Bytes. Das kannst du hier nicht brauchen.

>    {
>       if(BlockPer[ui] == file)

Wer oder was ist BlockPer

>       {
>          if (file == Ai)

Warum Ai hier hardcoden. Im Per Array steht doch Ai drinnen.
Du musst das nur auswerten.

>          {
>             nel = &AI[0];
>             for (ui;ui<=sizeof AI; ui++)

Autsch: Schon wieder ui

>             {
>                nnel++;

Nö. nnel ist ein Pointer (wenn du damit den Pointer in der
Block Struktur meinst).
Den willst du ganz sicher nicht erhöhen. Er ist dein einziger
Pointer zu den Daten. In dem Moment in dem du den veränderst,
ist dein Zugang zu den Daten futsch.

>                if(gesuchter_index == nnel)

Pointer mit Index vergleichen?
Das wird wohl so nichts werden

>                {
>                   return gesuchter_index;
>                }
>             }
>          }
>          if (uiProfile == iProfFDi)
>          {
>             ... ähnlich wie oben
>          }
>
>       }
>    }
> }
>
> geht das?

Nein.

von Lars (Gast)


Lesenswert?

mh kann ich ARRAY_SIZE auch unter C verwenden. Code nicht unter C++ !!!

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> mh kann ich ARRAY_SIZE auch unter C verwenden. Code nicht unter C++ !!!

Mit deinen C-Kenntnissen ist es aber nicht weit her.
ARRAY_SIZE ist ein Makro! Und ich hab im Source Code die
Makro Definition angegeben.
1
#define ARRAY_SIZE(x)  (sizeof(x) / sizeof(*x) )

So kann man korrekt rausfinden, wieviele Elemente ein Array
besitzt, sofern x noch als Array sichtbar ist.

Man könnte es auch so schreiben
1
#define ARRAY_SIZE(x)  (sizeof(x) / sizeof(x[0]) )

es wird ganz einfach die Gesamtgröße des Arrays in Bytes durch
die Größe eines Elements (ebenfalls in Bytes) dividiert.

Ein Uint Array
  Uint a[] = { 1, 2, 3 };

hat eine sizeof von 6 (wenn ich mal den sizeof(Uint) als 2 annehmen).
Das erste Element hat eine sizeof von 2 (weil es ja ein UInt ist),
daher besteht das Array aus 6 / 2 = 3 Elementen

von Lars (Gast)


Lesenswert?

omg stimmt ja besten Dank..

von Lars (Gast)


Lesenswert?

ich verstehe aber nicht wie sich nnelSize berechnet ?

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> ich verstehe aber nicht wie sich nnelSize berechnet ?

Es wird hier
1
Block Per[] =
2
{ { Ai, ARRAY_SIZE(AC), AC  },
3
  { Di, ARRAY_SIZE(DC), DC  }
4
};

gesetzt. Der Compiler rechnet das zur Compilezeit aus.
Ersetze einfach mal ARRAY_SIZE durch den Makroinhalt, so wie
das der Präprozessor macht.
1
Block Per[] =
2
{ { Ai, sizeof(AC) / sizeof(*AC), AC  },
3
  { Di, sizeof(DC) / sizeof(*DC), DC  }
4
};

sizeof wird vom Compiler ausgewertet, daher kommt der Compiler
auf:
1
Block Per[] =
2
{ { Ai, 4 / 2, AC  },
3
  { Di, 4 / 2, DC  }
4
};

und nachdem der Optimizer die Konstanten ausgewertet hat, steht da
1
Block Per[] =
2
{ { Ai, 2, AC  },
3
  { Di, 2, DC  }
4
};

die 2 sind jeweils die Anzahl der Elemente in AC bzw. DC

von Lars (Gast)


Lesenswert?

Also an dieser Stelle ein grosses Danke schön für diese Klasse Erklärung 
seit gestern.

von Karl H. (kbuchegg)


Lesenswert?

Nachtrag:
Natürlich hättest du die Arraygrößen auch händisch reinschreiben
können. Letztendlich ist es ja egal, wo die Zahl herkommt, ob die
nun vom Compiler berechnet wird oder ob du sie im Quelltext
einträgst.
Aber die Compilerberechnung ist
* bequemer
* weniger anfällig für Fehler

Nehmen wir mal an, das Ganze sehe so aus ...
1
Uint AC[] = { 10, 20 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, 2, AC  },
6
  { Di, 2, DC  }
7
};

... was ja völlig korrekt wäre.

In 2 Monaten kommst du drauf, dass bei AC noch ein Wert mehr dazu
muss.
1
Uint AC[] = { 10, 20, 70 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, 2, AC  },
6
  { Di, 2, DC  }
7
};

Ooops. Da die Ursprungsversion schon 2 Monate alt ist, kannst du dich
nicht mehr an jedes Detail erinnern. Das in der Definition von Per
die Arraygröße der Arrays einzutragen ist, hast du schon längst
vergessen. Da du das vergessen hast, denkst du auch nicht dran, und
der 2-er bleibt da drinn, obwohl es eigentlich
1
Block Per[] =
2
{ { Ai, 3, AC  },
3
  { Di, 2, DC  }
4
};

heissen müste. Da dort aber nach wie vor eine 2 eingetragen ist, wird
auch deine Suchschleife die 70 nie finden, da ja die Suchschleife
auf die korrekt eingetragene Anzahl angewiesen ist.

Mit dem Makro kann dir das nicht passieren. Warum? Weil der
Compiler während der Compilezeit den sizeof Ausdruck auswertet.
1
Uint AC[] = { 10, 20, 70 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, ARRAY_SIZE(AC), AC  },
6
  { Di, ARRAY_SIZE(DC), DC  }
7
};

wird zu
1
Uint AC[] = { 10, 20, 70 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, sizeof(AC) / sizeof(*AC), AC  },
6
  { Di, sizeof(DC) / sizeof(*DC), DC  }
7
};

das wiederrum wird (noch während des Compilierens) zu
1
Uint AC[] = { 10, 20, 70 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, 6 / 2, AC  },
6
  { Di, 4 / 2, DC  }
7
};

und daraus folgt dann wieder
1
Uint AC[] = { 10, 20, 70 };
2
Uint DC[] = { 30, 40 };
3
4
Block Per[] =
5
{ { Ai, 3, AC  },
6
  { Di, 2, DC  }
7
};

Und damit steht die korrekte Array Größe in der Per Initialisierung,
ohne dass du dich darum kümmern musstest.

Sowas nennt man auch 'defensives Programmieren': Einen etwas
höheren Tippaufwand in Kauf nehmen um sich selbst vor potentiellen
Fehlern zu schützen, die möglicherweise auftreten können/werden.

Ganz abgesehen, dass
1
Block Per[] =
2
{ { Ai, ARRAY_SIZE(AC), AC  },
3
  { Di, ARRAY_SIZE(DC), DC  }
4
};

besser dokumentiert, welche Funktion der 2-te Eintrag hat.
Diese Definition brauch ich mir nur ansehen um zu wissen, was
denn der Sinn der 2-ten Initialisierung eines Block ist.
Wohingegen ich bei
1
Block Per[] =
2
{ { Ai, 2, AC  },
3
  { Di, 2, DC  }
4
};
nur raten kann (oder in der Struktur nachschauen müsste), was denn
die 2 sein könnten.

von Lars (Gast)


Lesenswert?

Also wenn ich es debuge dann sagt er, dass die Zeile

for( j = 0; j < Per[i].nnelSize; ++j ) {

nicht richtig erreicht wird was daran liegt, das nnelSize keinen Wert 
hat. Ich lasse ja jetzt die Schleife durch per laufen sollte ich aber 
nicht als die Grösse des Arrays angeben

also

Per[i].nnelSize = ARRAY_SIZE(Per) ?

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> Also wenn ich es debuge dann sagt er, dass die Zeile
>
> for( j = 0; j < Per[i].nnelSize; ++j ) {
>
> nicht richtig erreicht wird was daran liegt, das nnelSize keinen Wert
> hat.

Das kann nicht sein. Irgendeinen Wert muss es haben.

> Ich lasse ja jetzt die Schleife durch per laufen sollte ich aber
> nicht als die Grösse des Arrays angeben
>
> also
>
> Per[i].nnelSize = ARRAY_SIZE(Per) ?

Nein.
Du hast irgendetwas anderes falsch gemacht.
Zeig mal alles.

von Lars (Gast)


Lesenswert?

Fehler gefunden ich habe nach dem if die Klammern vergessen. Jedoch 
verstehe ich nicht woher nnelSize seine Grösse bezieht.

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> Fehler gefunden ich habe nach dem if die Klammern vergessen. Jedoch
> verstehe ich nicht woher nnelSize seine Grösse bezieht.

Sag ich doch die ganze Zeit: Die steht bereits in der Struktur
drinnen.
Und die steht deshalb drinnen, weil sie hier
1
Block Per[] =
2
{ { Ai, ARRAY_SIZE(AC), AC  },
3
  { Di, ARRAY_SIZE(DC), DC  }
4
};

rein-initialisiert wurde.

von Lars (Gast)


Lesenswert?

Also die erste Function wird nun korrekt durchlaufen und liefert mit den 
korrekten Index. Jedoch wird dieser Index nicht in Funktion übergeben, 
sonder irgendein "uninitialiserter Wert" 32980.

if( PerBlock[i].nnel[j] == element )
        {
            index = j;
            return index;     //Return Index
        }

Muss ich den index ausserhalb der ersten Funktion nochmals schreiben 
bevor er in die zweite gegeben wird oder speichert er die Variable Index 
( auch ausserhalb von beiden Funktionen definiert ) bereits in der 
ersten Fkt ab?

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> Also die erste Function wird nun korrekt durchlaufen und liefert mit den
> korrekten Index. Jedoch wird dieser Index nicht in Funktion übergeben,
> sonder irgendein "uninitialiserter Wert" 32980.
>
> if( PerBlock[i].nnel[j] == element )
>         {
>             index = j;
>             return index;     //Return Index
>         }
>
> Muss ich den index ausserhalb der ersten Funktion nochmals schreiben
> bevor er in die zweite gegeben wird oder speichert er die Variable Index
> ( auch ausserhalb von beiden Funktionen definiert ) bereits in der
> ersten Fkt ab?

Wo kommt denn nun wieder die variable namens 'index' her?

In der ganzen Funktion, wie ich sie eingangs geschrieben habe
1
int Get_1( Uint uifile, Uint element )
2
{
3
  size_t i, j;
4
5
  for( i = 0; i < ARRAY_SIZE(Per); ++i ) {
6
7
    if( Per[i].uifile == uifile ) {
8
9
      for( j = 0; j < Per[i].nnelSize; ++j ) {
10
        if( Per[i].nnel[j] == element )
11
          return j;
12
      }
13
14
      return -1;
15
    }
16
  }
17
18
  return -2;
19
}

gibt es keine Variable namens 'index'

von Lars (Gast)


Lesenswert?

ich habe statt

j = index

von Lars (Gast)


Lesenswert?

ich möchte einfach nicht das j returnen sondern einen Index dieser dann 
in get2 gegeben wird.

von Karl H. (kbuchegg)


Lesenswert?

???

Poste mal deinen Code.
Schön langsam sieht es danach aus, dass du selbst nicht genau weist
was du willst.

> ich möchte einfach nicht das j returnen sondern einen Index dieser dann
> in get2 gegeben wird.

Das ganze nochmal. Aber diesmal im deutschen Satz.

von Lars (Gast)


Lesenswert?

ich mochte das der Index aus der ersten Funktion, also in deinem Code 
return j der zweiten Funktion übergeben wird.

ich habe j zu index umgetauft.

Dabei ist der Ablauf so das beide Funktionen von einer anderen Stelle 
aufgerufen werden.

Problem: wenn ich "j" return und "j" der zweiten Funktionen übergeben 
möchte dann steht das nicht mehr der korrekte errechnete Wert aus 
Funktion 1 drinne sondern irgend ein Wert?=

von Karl H. (kbuchegg)


Lesenswert?

Wie du die Variable innerhalb der Funktion nennst ist doch
völlig wurscht. Nachdem die Funktion verlassen wird existiert
die Variable ja sowieso nicht mehr.

Möglicherweise ist ja das das Problem.
verwendet werden die Funktionen zb so.

int main()
{
  int index;
  int value;

  index = Get_1( Ai, 20 );     // suche nach 20 und erhalte den Index
  value = Get_2( Ai, index );  // hole das Element an der Position index

  // hier muss value 20 sein

  // der Get_1 hat bestimmt wo in Ai ein Element mit dem Wert 20
  // steht. Als Ergebnis liefert Get_1 eine 1 zurück um anzugeben
  // dass AC[1] gleich 20 ist.
  //
  // Die Umkehrfunktion Get_2 besorgt den Wert aus AC (indem
  // Ai angegeben wurde. Da index, der 2-te Parameter, der in
  // die Funktion hineingeht, den Wert 1 hat, liefert die Funktion
  // Get_2 den Wert von AC[1]. Und dieser ist 20
}

von Karl H. (kbuchegg)


Lesenswert?

Lars wrote:
> ich mochte das der Index aus der ersten Funktion, also in deinem Code
> return j der zweiten Funktion übergeben wird.

Ja dann mach das doch.
Die Funktion Get_1 liefert den Wert. Den fängst du in einer
Variablen auf und übergibst in an die 2-te Funktion

> ich habe j zu index umgetauft.

Namen sind Schall und Rauch.
Mir scheint du bastelst da irgendeine Beziehung zwischen den
Funktionen. Es gibt keine! Die Funktionen arbeiten auf serselben
Datenstruktur. Aber mehr als das haben die beiden nicht gemeinsam.

>
> Dabei ist der Ablauf so das beide Funktionen von einer anderen Stelle
> aufgerufen werden.
>
> Problem: wenn ich "j" return und "j" der zweiten Funktionen übergeben
> möchte dann steht das nicht mehr der korrekte errechnete Wert aus
> Funktion 1 drinne sondern irgend ein Wert?=

Zeig die Stelle des Aufrufs.

von Lars (Gast)


Lesenswert?

Get1 (uifile, element);
   index=j;
Get2(uifile, index);

von Karl H. (kbuchegg)


Lesenswert?

> Get1 (uifile, element);
>   index=j;
> Get2(uifile, index);

Und was ist mit dem Returnwert?

Get1 liefert einen Wert!!!!!!
genau den Wert den du haben willst

  index = Get1( uifile, element);


Steck doch bitte deine Nase in ein C-Grundlagenbuch!
Das sind absolute Basics.

von Lars (Gast)


Lesenswert?

ja werde ich wohl machen müssen. Trotzdem besten Dank für Ihre Zeit.

von Lars (Gast)


Lesenswert?

Wo wird der Pointer initialisiert?

von Karl H. (kbuchegg)


Lesenswert?

Welcher Pointer?

Der hier?
typedef struct
{
   Uint uifile;
   Uint nnelSize;
   Uint *nnel;         <---- Pointer
} Block;


Na hier:
Block Per[] =
{ { Ai, ARRAY_SIZE(AC), AC  },
  { Di, ARRAY_SIZE(DC), DC  }
};
                         ^
                         |
                         |



Zähl nach: Für einen Block gilt eine Zeile
   { Ai, ARRAY_SIZE(AC), AC  },
      ^        ^          ^
      |        |          |
      |        |          +---- nnel
      |        +----- nnelSize
      +----- uifile

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.