Forum: Mikrocontroller und Digitale Elektronik Array-Problem?


von Joachim .. (joachim_01)


Lesenswert?

Hi,
hab gestern abend zwe kleine Routinen, dez to Bitmuster + dey to hex 
geschrieben. Heute will ich den Code um I2C Routinen erweitern und 
stelle dabei fest, daß auf meinem LCD 20x4 speichermüll erscheint bzw 
der Code völlig zerstört wird. Der Code läuft auf nem 18F252.
Ich weiß... ist zum Teil ziemlich umständlich und mehr gebastelt als 
professionell geschrieben, dies sollte jetzt aber nicht Grundlage einer 
Diskussion werden...
1
void main(void) {
2
3
char buffer [10];
4
char pattern[] = "0000 0000";
5
char Dummy[] = "---";  // <-Ohne dies nur Schrott aufm Display
6
char pattern_1[] = "00";
7
8
unsigned char var =29;  //Test
9
char *pattern_ram;
10
char *pattern_hex ;
11
unsigned char DeviceSelect;
12
13
pattern_hex = &pattern_1[0] ;  // liegt hier der Fehler?
14
pattern_ram = &pattern[0];     // liegt hier der Fehler?
15
...
16
...
17
}

Und dann:
1
void decToHex (unsigned char value, char *res){
2
unsigned char value1;
3
char result[2];
4
5
    //1.char
6
    value1 = value; // mem
7
    value1 /=16;
8
    if (value1 > 9) value1 = value1 -10 + 'A' ;  
9
    else  value1 += '0';
10
    result[0] = value1;
11
    *res = result[0];
12
    //
13
    //2.char
14
    value1 = value;
15
    value1 %=16;
16
    if (value1 > 9) value1 = value1 -10 + 'A' ;  
17
    else  value1 += '0';
18
    result[1] = value1;
19
    *(res+1)= result[1];
20
    *(res+2)= result[2] = 0;
21
}

von Karl H. (kbuchegg)


Lesenswert?

Joachim ... schrieb

> Ich weiß... ist zum Teil ziemlich umständlich und mehr gebastelt als
> professionell geschrieben, dies sollte jetzt aber nicht Grundlage einer
> Diskussion werden...

Jein.
Eigentlich sollte es das schon. Denn es zeigt sich, dass erstaunlich 
viele Fehler auf gebastelten, nicht aufgeräumten und unübersichtlichen 
Code zurückzuführen sind. Eben weil der Programmierer die Übersicht 
verloren hat.

Räumt man den Code auf, dann ist der Fehler plötzlich für alle klar und 
deutlich zu sehen.

> pattern_hex = &pattern_1[0] ;  // liegt hier der Fehler?
> pattern_ram = &pattern[0];     // liegt hier der Fehler?

Die Frage kann man so nicht beantworten. Rein formal gibt es an dieser 
Zuweisung nichts auszusetzen. Es fragt sich allerdings was du dir davon 
versprichst, wenn du hier eine extre Pointervariable einsetzt. Wozu 
brauchst du sie? Was bringt dir diese Variable, was dir eine direkte 
Verwendung des Arrays nicht bringt (es gibt Fälle, wo man so ein 
Konstrukt benötigt. kann aber mit dem bischen Code nicht verifiziert 
werden)




>
1
> void decToHex (unsigned char value, char *res){
2
> unsigned char value1;
3
> char result[2];
4
> 
5
>     //1.char
6
>     value1 = value; // mem
7
>     value1 /=16;
8
>     if (value1 > 9) value1 = value1 -10 + 'A' ;
9
>     else  value1 += '0';
10
>     result[0] = value1;
11
>     *res = result[0];
12
>     //
13
>     //2.char
14
>     value1 = value;
15
>     value1 %=16;
16
>     if (value1 > 9) value1 = value1 -10 + 'A' ;
17
>     else  value1 += '0';
18
>     result[1] = value1;
19
>     *(res+1)= result[1];
20
>     *(res+2)= result[2] = 0;
21
> }
22
>

Der Code ist heftig kompliziert. Wenn du realisiert hast, dass diese 
Funktion im Prinzip aus 2 Teilen besteht, die konzeptionell das Gleiche 
machen, dann solltest du das auch in einer eigenen Funktion 
manifestieren. Mal sehen, wo uns das hinführt
1
char toHexNibble( unsigned char nibble )
2
{
3
  if( nibble > 9 )
4
    return nibble - 10 + 'A';
5
6
  return nibble + '0';
7
}
8
9
void decToHex (unsigned char value, char *res)
10
{
11
  res[0] = toHexNibble( value >> 8 );     // oberen 4 Bit, aka High-Nibble
12
  res[1] = toHexNibble( value & 0x0F );   // unteren 4 Bit, aka Low-Nibble
13
  res[2] = '\0';
14
}

ich würde mal sagen: das Aufräumen hat sich gelohnt. Das ganze Gebilde 
ist einfach und die Funktionsweise ist leicht nachzuvollziehen. Es ist 
auch leicht zu verifizieren, dass die Funktion an sich korrekt ist, wenn 
der Aufrufer für res die Adresse eines Arrays übergibt, welches gross 
genug ist. Man kann auch aus dem Code ganz leicht ablesen, dass der 
Aufrufer ein Array mit mindestens einer Länge von 3 angeben muss.

Ein Aufruf der Form
1
unsigned char var =29;  //Test
2
char pattern_1[] = "00";
3
4
...
5
  decToHex( var, pattern_1 );
6
...

ist daher vollkommen in Ordnung.

Huch, da ist ja jetzt fast die Hälfte Code weggefallen! Und was übrig 
bleibt, ist auch noch leichter zu verstehen und nachzuvollziehen das es 
korrekt ist. Und genau das hab ich in der Einleitung gemeint, warum sich 
solche Diskussionen lohnen.


>     *(res+1)= result[1];

warum verwendest du hier Pointersyntax, wenn du nicht musst? Die 
Pointersyntax bringt dir hier nichts, ausser das der Code kompliziert 
aussieht.

von Stefan E. (sternst)


Lesenswert?

Ein Problem ist schon mal hier:
1
char result[2];
2
...
3
    *(res+2)= result[2] = 0;
Hier schreibst du eine 0 hinter das Array "result".
(Wofür soll das Array überhaupt gut sein? Es erfüllt keinen Zweck in der 
Funktion.)

von Joachim .. (joachim_01)


Lesenswert?

Naja... war'n n paar Tests die ich dringelassen hab.

Strategie war eigentlich, ein Array per Referenz zu übergeben (das hat 
aber nicht klappen wollen) deswegen auch die ziemliche overheadische 
Umkopiererei....
Problem ist, daß
*(res+2)= result[2] = 0; //Ende
es so aussieht, als ob sich da irgendwas überschneidet, mal geht's mal 
geht's nicht - deswegen hab ich das getestet. Ich hatte mit 
Speicherkopier-Funktionen (Programm nach RAM) rumprobiert weil ich mir 
nicht sicher bin ob Code auch wirklich im RAM liegt, das Ergebnis war 
aber nicht so dolle.

Ich bin nich sicher ob
 char *String;
und
ram char *string das gleiche auf nem PIC ist. Vor allem: Wie kommt der 
Code ins RAM? Irgendn paar Zeilen Coden müssn den da wohl reinkopieren. 
Oder passiert das schon beim Ablegen des Hex-Files?

von Udo S. (urschmitt)


Lesenswert?

Joachim ... schrieb:
> Problem ist, daß
> *(res+2)= result[2] = 0; //Ende
> es so aussieht, als ob sich da irgendwas überschneidet, mal geht's mal
> geht's nicht

Herrgott Grundlagen erste Seite C Buch!
Ein Array der Größe 2 hat 2 Elemente, das 1. result[0] und das 2. 
result[1].
Mit result[2] schreibst du ins 3. nicht vorhandene Element und damit 
irgendwas kaputt!

von Karl H. (kbuchegg)


Lesenswert?

Joachim ... schrieb:
> Naja... war'n n paar Tests die ich dringelassen hab.
>
> Strategie war eigentlich, ein Array per Referenz zu übergeben (das hat
> aber nicht klappen wollen)

und gleich nochmal: Grundlagen - C-Buch

Arrays können nicht per Referenz an eine Funktion übergeben werden. Bei 
der Übergabe eines Arrays wird immer die Startadresse des Arrays an die 
Funktion gegeben. Daher sieht das typischerweise auch so aus

Beim Aufrufer ...
1
  int Werte[5];
2
3
  ...
4
  foo( Werte );
5
  ...
... wird das Array direkt angegeben. Der Name eines Arrays alleine (also 
ohne eine Indizierung) fungiert als die Startadresse des Arrays im 
Speicher.

Und beim Empfänger ...
1
  void foo( int * dieWerte )
2
  {
3
     ....
4
  }
... wird diese Startadresse in einer Pointervariablen abgelegt. Und da 
zusätzlich in C noch gilt ...

    *( a + i )   <==>  a[i]

(in Worten: Array-Indizierung ist nichts anderes als eine andere 
Schreibweise für eine bestimmte Form eines Pointerzugriffs)

... kann man innerhalb der Funktion ganz normale Array-Syntax benutzen 
um mit dem erhaltenen Pointer etwas zu machen
1
  void foo( int * dieWerte )
2
  {
3
    dieWerte[0] = 8;
4
  }


Du solltest den Erwerb eines Buches in Betracht ziehen. Denn das sind 
noch die einfachen Grundlagen!

von Udo S. (urschmitt)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Beim Aufrufer ...
>   int Werte[5];
>
>   ...
>   foo( Werte );
>   ...

Karl Heinz Buchegger schrieb:
> Und beim Empfänger ...  void foo( int * dieWerte )
>   {
>      ....
>   }

darf ich folgende Erweiterung vorschlagen:
1
   int Werte[5];
2
 
3
   ...
4
   foo( Werte, sizeof( Werte ) );
5
   ...
6
  
7
   void foo( int * dieWerte, int size )
8
   {
9
      ...
10
   }

von Joachim .. (joachim_01)


Lesenswert?

>Denn das sind noch die einfachen Grundlagen!
Yep, ich weiß... ist manchmal aber eher n Verständnis- u. Übungsproblem 
- weniger ein Zu-faul-um-ins-Buch-zu-kucken-Problem ;-)

>> *(res+2)= result[2] = 0; //Ende
>Herrgott Grundlagen erste Seite C Buch!

Deswegen ja auch eine 0 und keine '0'. Aber immerhin: Der Herrgott hat 
mir durch dich den Weg gezeigt - ich hatte an anderer Stelle nen 
ähnlichen Fehler; nu sieht's besser aus. Fluchen hilft halt doch.

Danke an die Helfer.

von Udo S. (urschmitt)


Lesenswert?

Joachim ... schrieb:
> Deswegen ja auch eine 0 und keine '0'.

???

Schreibe 100 mal
In ein Array mit 2 Elementen DARF ICH NICHT IN DAS DRITTE !!!! ELEMENT 
SCHREIBEN. Weder eine '0' noch eine 0!

von MagIO (Gast)


Lesenswert?

@Karlheinz Buchegger:
"Arrays können nicht per Referenz an eine Funktion übergeben werden. Bei
der Übergabe eines Arrays wird immer die Startadresse des Arrays an die
Funktion gegeben. Daher sieht das typischerweise auch so aus"

Hä?????? (Ist glaube ich ein wenig Missverständlich ausgedrückt.)

Eine Referenz IST die Startadresse!


#include<stdio.h>

char test[] = "Juhu";

int main()
{
  printf( "%s\n", test );
  printf( "%s\n", &test[0] );

  return 0;
}

Die beiden printf sind identisch.

Und das ist auch genau was hier wichtig ist zu verstehen:
Wann immer der Compiler ein test ohne [x] sieht, dann behandelt er es 
genau so, wie ein &test[0]. In anderen Worten: Das Label eines Arrays 
ist gleichzusetzen mit dem Pointer auf das erste Element des Arrays.

von Karl H. (kbuchegg)


Lesenswert?

MagIO schrieb:
> @Karlheinz Buchegger:
> "Arrays können nicht per Referenz an eine Funktion übergeben werden. Bei
> der Übergabe eines Arrays wird immer die Startadresse des Arrays an die
> Funktion gegeben. Daher sieht das typischerweise auch so aus"
>
> Hä?????? (Ist glaube ich ein wenig Missverständlich ausgedrückt.)

Hast du recht.
Danke, dass du mich darauf hingewiesen hast.

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.