mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik C Programmierung Denkfehler?


Autor: Alexander S. (amper)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi zusammen,

ich möchte eine Funktion in einer Funktion aufrufen (diese wird 
vordefiniert)
und der Rückgabe wert soll ein Array sein. Allerdings geht es nur wenn 
ich das array als global anlege. Könnte mir jemand erklären warum das so 
ist ?

Grundstrucktur des Programms:

//Defintions and Declaration:

unsigned short int    a;
unsigned short int    b;
unsigned short int    c;

unsigned short int array[3];   -> als globales Array funktioniert das 
Programm



// Function-Predefinitions:

unsigned short int func2()
{
        unsigned char i=0;
  unsigned short int s_a = 20;
  unsigned short int s_b = 40;
  unsigned short int s_g = 60;
  array[1]=s_a*2;
  array[2]=s_b*2;
  array[3]=s_g*2;
  return(array[i]);
}


void func1(void)
{

->  unsigned short int array[3]; => als lokales Array geht es nicht
    func2();
    th_U = times[1];
    th_V = times[2];
    th_W = times[3];
}


//MAIN

int main(void)
{
  func1();
  return 0;
}



Danke im vorraus für eure Hilfe

Autor: Bernd Hallinger (bhallinger) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Arry als Rückgabe geht nicht. Du must der Funktion einen Zeiger auf 
das Array übergeben. Dann kannst du in der Funktion das Array verändern.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deine 'lokale' Variante:
Alexander S. wrote:
> unsigned short int func2()
> {
>         unsigned char i=0;
>   unsigned short int s_a = 20;
>   unsigned short int s_b = 40;
>   unsigned short int s_g = 60;
/*** array[...] ist hier nicht deklariert */
>   array[1]=s_a*2;
>   array[2]=s_b*2;
>   array[3]=s_g*2;
>   return(array[i]);
> }

Autor: MeinerEiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Geht deswegen nicht, weil func2 nichts von dem lokalen Array weiss.
Es kenn nur seine Variablen und die globalen. Die lokalen Variablen 
einer anderen Funktion sieht es nicht.

Der lokale Array gilt also nur in func1.

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@ Bernd Hallinger
> Ein Arry als Rückgabe geht nicht. Du must der Funktion einen Zeiger auf
> das Array übergeben. Dann kannst du in der Funktion das Array verändern.
Nur zum richtigen Verständnis: Eine "Array"-Variable in "C" ist doch 
immer ein Zeiger (auf das erste Element).

In dem Quelltextauszug sind aber noch reilich Ungereimtheiten, so dass 
ich meine Zweifel habe, dass er sich überhaupt compilieren läßt, bzw. 
sinnvolle Ergebnisse liefert.

Stichworte: undefinierte/-deklarierte Variablen, Namensräume, 
Bereichsüberschreitungen, ...

Tschü Dude

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd Hallinger wrote:
> Ein Arry als Rückgabe geht nicht.

Das geht schon, Du mußt Dir nur einen entsprechenden Typ definieren.

Bloß gewinnst Du dabei nichts, da das der Returnwert der Funktion ist, 
den Du einer gleichen Variable des Aufrufers zuweisen mußt.
Der Aufrufer muß sie also immer anlegen.


Peter

Autor: Heinz Blättner (heinzb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Arrays als rueckgabe wert geht schon.

Wenn Du das array mit call by reference uebergibst (pointer auf array)
dann kann die aufgrufene funktion da reinschreiben und der Aufrufer hat 
dann die Werte da wo er sie will.

Also auch als automatische variable (in der funktion deklariert)

Nur wenn ich mir das so anschaue was du da vorhast schlage ich vor das 
Du
eine strukur definierts da arrays ein paar nachteile haben.

Die dimension des arrays muss zwischen Aufrufer und Aufgerufenen 
abgesprochen sein oder man uebergibt das als zusaetzliche variable.

Also in etwa so:

//Defintions and Declaration:
typedef struct _mydata_s {
        unsigned short int    a;
        unsigned short int    b;
        unsigned short int    g;
} mydata_t;


// Function-Predefinitions:

mydata_t * func2( mydata_t *pD )
{
        unsigned char i=0;
  unsigned short int s_a = 20;
  unsigned short int s_b = 40;
  unsigned short int s_g = 60;
  pD->a = s_a*2;
  pD->a = s_b*2;
  pD->a = s_g*2;
// Das return st nicht notwendig da func2 ueber ptr pD direkt zugriff
// auf die daten hat
  return(pD);
}


void func1(void)
{
    mydata_t  loc_data;    // !!! nicht initialisiert
    func2( &loc_data );    // nach aufruf enthaelt
// loc_data.a  loc_data.b  loc_data.g die gwuenschten daten
    th_U = times[1];
    th_V = times[2];
    th_W = times[3];
}


//MAIN

int main(void)
{
  func1();
  return 0;
}

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@Heinz Blättner
> Wenn Du das array mit call by reference uebergibst (pointer auf array)...

Wie oben schon geschrieben:
Eine "Array"-Variable in "C" ist doch immer ein Zeiger (auf das erste 
Element).

Also kann man ein "Array" (nicht nur ein Element!) doch nur als Pointer 
übergeben.

Tschü Dude

Autor: Bernd Hallinger (bhallinger) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eben es ist schon ein Pointer aber man muss der Funktion die Adresse hin 
übergeben. Die Adresse / der Pointer muss der Funktuion bekannt gemacht 
werden nicht das Array zurückgeben.

void foo (unsigned int * liste)
{
liste[1] = 0;
liste[2} = 4711;
}


void main(void)
{
unsigned int Folge[10];

foo(Folge);

printf("%d", Folge[2]);
}

Autor: Heinz Blättner (heinzb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 12er Dude (Gast)
>> Wenn Du das array mit call by reference uebergibst (pointer auf array)...

> Wie oben schon geschrieben:
> Eine "Array"-Variable in "C" ist doch immer ein Zeiger (auf das erste Element).
IMMER nicht
siehe: 
http://en.wikipedia.org/wiki/C_(programming_langua...

> Also kann man ein "Array" (nicht nur ein Element!) doch nur als Pointer
> übergeben.
Das ist der default Fall
Mit etwas Aufwand kann man auch arrays by value uebergeben :-)
Es wird dann wie gewohnt eine Kopie auf dem stack erzeugt.

br heinz

Autor: Heinz Blättner (heinzb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beispiel fuer array call by value:


struct Array {
     int element[100];
} a;

void foo( struct Array arr)
{
   arr.element[0] = 1;
}

int main(void)
{
    a.element[0] = 0;
    foo(a);
    return a.element[0];
}

main exist status wird 0 werden, da foo() eine Kopie des arrays bekommt,
damit wird a.element[0] nicht veraendert.

Das ist aber nicht empfehlenswert
  (da zusaetzlicher laufzeit fuer array kopieren anfaellt)
Besondert nicht auf embedded Kontrollern da:
- RAM ist nicht beliebig vorhanden (Platz fuer Kopie auf dem Stack)
- Laufzeit (fure das kopieren)

br heinz

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@Heinz Blättner
> en.wikipedia.org/wiki/C_(programming_langua...
Da steht doch genau das drin, was ich beschrieben habe. Welcher Teil 
widerspricht? (Bitte mal direkt gegenüberstellen)

>> Also kann man ein "Array" (nicht nur ein Element!) doch nur als Pointer
>> übergeben.
> Das ist der default Fall
> Mit etwas Aufwand...
Das hat dann aber nicht mehr viel mit Array-Parametern/-Rückgabewerten 
zu tun, sondern ist typunabhängig.

In Deinem Bsp. von heute 18:59 hast Du selbst gezeigt:
Array "Folge[]" ist zuweisungskompatibel zu Pointer (uint*) "liste".

Tschü Dude

Autor: Heinz Blättner (heinzb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@12er Dude (Gast)
>> en.wikipedia.org/wiki/C_(programming_langua...
>Da steht doch genau das drin, was ich beschrieben habe. Welcher Teil
>widerspricht? (Bitte mal direkt gegenüberstellen)
However, there is a distinction to be made between arrays and pointer 
variables. Even though the name of an array is in most expression 
contexts converted to a pointer (to its first element), this pointer 
does not itself occupy any storage. Consequently, you cannot change what 
an array "points to", and it is impossible to assign to an array.


>>> Also kann man ein "Array" (nicht nur ein Element!) doch nur als Pointer
>>> übergeben.
>> Das ist der default Fall
>> Mit etwas Aufwand...
>Das hat dann aber nicht mehr viel mit Array-Parametern/-Rückgabewerten
>zu tun, sondern ist typunabhängig.
typunabhängig ???

>In Deinem Bsp. von heute 18:59 hast Du selbst gezeigt:
>Array "Folge[]" ist zuweisungskompatibel zu Pointer (uint*) "liste".
Ist nicht von mir

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12er Dude wrote:
> Wie oben schon geschrieben:
> Eine "Array"-Variable in "C" ist doch immer ein Zeiger (auf das erste
> Element).

Vorsichtig ausgedrückt:
NEIN NEIN UND NOCHMAL NEIN! :-)

Vektoren sind keine Zeiger!
int Vektor[100];
int *Zeiger_auf_Vektor = Vektor;
int **Zeiger_auf_Zeiger_auf_Vektor = &Zeiger_auf_Vektor;

int **Kein_Zeiger_auf_Zeiger_auf_Vektor = &Vektor;

http://www.lysator.liu.se/c/c-faq/c-2.html

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

@ Sven P.
Schau Dir bitte den Verlauf des Thread und nicht nur die letzten 
Postings an. Zu klären ist, wie ein Array zurück-/übergeben wird.

Die von Dir gezeigten Zusammenhänge sind mir schon geläufig.
int Vektor[100];
int *Zeiger_auf_Vektor = Vektor;
// "Zeiger_auf_Vektor" zeigt nicht auf Vektor, sondern auf &(Vektor[0])
int *Zeiger_auf_Vektor = &Vektor;
// geht zur Not auch, bringt nichts, wie oben
"Vektor" ist (und bleibt) für den Compiler ein i m p l i z i t e r 
Zeiger, der aber selbst keine Adresse besitzt und daher nicht im 
Speicher zu finden ist. Also kann man seinen Wert nutzen/zuweisen 
(Adresse, auf die er zeigt), oder ihn derefernzieren.

Tschü Dude

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12er Dude wrote:

> "Vektor" ist (und bleibt) für den Compiler ein i m p l i z i t e r
> Zeiger, der aber selbst keine Adresse besitzt und daher nicht im
> Speicher zu finden ist. Also kann man seinen Wert nutzen/zuweisen
> (Adresse, auf die er zeigt), oder ihn derefernzieren.

Trotzdem solltest du vorsichtig sein mit der Aussage, dass ein Array ein 
Zeiger ist. Denn genau das ist es nicht. Ein Array ist ein Array. Ein 
Zeiger ist ein Zeiger. In manchen Fällen degeneriert ein Array zu einem 
Zeiger auf sein erster Element.
Aber ein Array ist KEIN Zeiger.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12er Dude wrote:
> Hallo,
>
> @ Sven P.
> Schau Dir bitte den Verlauf des Thread und nicht nur die letzten
> Postings an. Zu klären ist, wie ein Array zurück-/übergeben wird.
Schau Dir bitte den Verlauf des Threads an und nicht nur die letzten 
Postings. Dann fällt Dir nämlich auf, dass bereits die zweite Antwort 
hier von mir stammt und das Problem mit dem Codefetzen beschreibt.

Ist zwar keine Antwort auf dem Silbertablett, aber etwas Mitdenken darf 
man wohl erwarten. Zumal im Post vor mir schon eine mögliche und übliche 
Lösung gegeben wurde.

> Die von Dir gezeigten Zusammenhänge sind mir schon geläufig.
Sah aber nicht danach aus.

Ein Vektor ist und bleibt ein Vektor. Karl heinz Buchegger hat das 
richtig beschrieben.

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin nicht allein ;)
http://books.google.de/books?id=vhOsStUNcnAC&pg=PA...

Und bitte das Wort "implizit" beachten.

Tschü Dude

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12er Dude wrote:
> Hallo,
>
> ich bin nicht allein ;)
> 
http://books.google.de/books?id=vhOsStUNcnAC&pg=PA...
>
> Und bitte das Wort "implizit" beachten.
>
> Tschü Dude

Ich nehme an du meinst den Satzteil "... Zeigerarray ist, wie bei 
anderen Arrays auch, ein impliziter Zeiger ..."

Nun, er ist dort genauso falsch wie bei dir.
Ein Array ist kein Zeiger. Noch nicht mal implizit.

Warum wir so darauf herumreiten?

Na dann erklär doch mal mit deinem impliziten Zeiger, wo denn hier das 
Problem liegt:

file1.c
*******
int Test[5];

int main()
{
  foo();

  printf( "%d\n", Test[2] );
}

file2.c
*******
extern int* Test;

void foo()
{
  Test[2] = 5;
}

Ein Array ist kein Zeiger und ein Zeiger ist kein Array.
Ein Array kann unter bestimmten Umständen zu einem Zeiger auf die 
Adresse des ersten Array-Elementes degenerieren. Aber: Das bedeutet 
nicht, dass es ein Zeiger IST! Die Umwandlung in die erste 
Elementadresse wird rein durch die Verwendung des Arrays ausgelöst und 
durch sonst gar nichts. Die Verwendung der Wörter 'Array', 'Zeiger' und 
'ist' in ein und demselben Satz ist zumindest problematisch bis oft 
einfach nur falsch. Im besten Fall ist es für den geneigten Leser 
einfach nur missverständlich oder verwirrend, so dass dieser Satz am 
Besten so nie gefallen wäre.

Mit dem gleichen Recht könnte ich auch sagen, dass ein int ein 
impliziter Zeiger ist, der nie irgendwo auftaucht. Denn natürlich führt 
der Compiler darüber Buch, wo im Speicher welche Variable liegt. In 
diesem Sinne ist praktisch alles ein 'impliziter Zeiger' (auch 
Funktionen). Das hilft aber niemandem weiter und erklärt nichts.

Autor: 12er Dude (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl heinz Buchegger,

gut, dann beenden wir hier diese Haarspalterei. Auf einen grünen Zweig 
kommen wir wohl eh nicht.

Und sorry an den OP, dass wir seinen Thread missbraucht haben.

Tschü Dude

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
12er Dude wrote:

> Und sorry an den OP, dass wir seinen Thread missbraucht haben.

Ich denke das ist kein Problem.

Alles worauf Sven und ich hinaus wollen ist:
Sei vorsichtig, was du einem Neueinsteiger erzählst. Ich hab schon 
mitgekriegt, dass du den Unterschied verinnerlicht hast und dass du 
Arrays und Zeiger nicht verwechselst. Aber ein Neueinsteiger hört 
'Array', 'Zeiger' und baut sich innerlich den Satz zusammen 'Ein Array 
ist ein Zeiger'. Dass du den Satz ganz anders gemeint hast, überhört er. 
Es bringt nichts, bei diesem Thema mit sprachlichen Feinheiten zu kommen 
und das Wesentliche in ein einziges Wort 'implizit' zu legen. Diese 
Botschaft kommt einfach nicht an.

Das hab ich oft genug auf comp.lang.c-c++ und Konsorten miterlebt. Bis 
wir uns dort in der Community darauf geeinigt haben, solche Sätze schon 
im Keim zu ersticken. Ab da lief es dann besser.

Autor: name (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Feld gleich Zeiger?

was passt hier nicht:

[c]
void schmafu (void)
{
    int  test[2];
    int* ptest = test;
    int  nochntest[2];

    test++;
    ptest++;
    nochntest[]++;

    *test = 'a';
    *ptest = 'b';
    *(nochntest[]) = 'c';
    *(nochntest[0]) = 'c';
}

p.s.: als Anfänger hab ich sowohl Variante a als auch Variante b ohne 
Initialisierung des Zeigers probiert. b fand ich lustiger!
c hab ich noch nicht probiert, aber das wär doch die Umsetzung der 
Aussage Array == Pointer?

Autor: Johnny Maxwell (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> gut, dann beenden wir hier diese Haarspalterei. Auf einen grünen Zweig
> kommen wir wohl eh nicht.

Der Unterschied ist doch ziemlich deutlich: Ein Pointerarray braucht 
noch ein zusaetzliches Wort im Speicher (eben fuer den Pointer) und ein 
Array nicht, weil dessen Adresse fest ist.

Ob 1 Wort (also z.B. 4 Bytes) jetzt weniger als ein Haar sind muss jeder 
selber wissen :)

Einen groesseren Unterschied macht das in der Adressierung: 
Pointerarrays werden indirekt adressiert, Arrays direkt.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.