Forum: Mikrocontroller und Digitale Elektronik Pointer in C


von Zeiger_1 (Gast)


Lesenswert?

Hallo zusammen,
ich arbeite mich gerade in die Programmierung von 8-Bit-µCs unter C ein.
Das Konzept mit den Pointern habe ich verstanden, nur eins nicht: Wozu 
benötigte ich auf der Ebene der 8-Biter eigentlich Pointer ?
Man kann doch auch vieles mit globalen Variablen machen und so z.B. 
ebenfalls Variablen-Werte in Funktionen verändern.
Ich sehe z.Zt. keine  Vorteile durch den Einsatz von Pointern.

Kann mir da jemand weiter helfen ?

Vielen Dank,

Zeiger_1

von Ralf (Gast)


Lesenswert?

Ein Argument für Pointer wäre, dass globale Variablen permanent 
Speicherplatz einnehmen, Pointer nicht, da der Zugriff dann erfolgt, 
wenn er benötigt wird. Der Speicherplatz der Variablen, auf die 
zugegriffen wird, kann ja später durch sog.Overlay wieder für ne andere 
Variable herhalten...

Ralf

von Sven P. (Gast)


Lesenswert?

Nicht? Dann hast du Zeiger ganz sicher nicht verstanden.

Paar ganz einfache Stichworte:
- 're-entrant' Funktionen*
- elegante und/oder effiziente Programmierung
- Vektoren und Arrays
- dynamische Speicherzuweisung*
- ...

* vielleicht auf kleinen Maschinen nicht ganz so relevant.

Vektor- und Array-Zugriffe zerfallen grundsätzlich in Zeiger. Zeiger als 
Rückgabeparameter können jede Menge Herumkopiererei sparen.

von Zeiger_1 (Gast)


Lesenswert?

Hallo Ralf,
wenn ich aber innerhalb der Funktion mit lokalen Variablen arbeite, wird 
der Speicherplatz doch auch wieder freigegeben, wenn ich die Funktion 
verlasse.
Ein Hauptargument bei den Pointern ist doch, daß man Werte innerhalb 
einer Funktion ändern will, die in der Funktion selber gar nicht bekannt 
sind.
Das sind nach meiner Vorstellung dann doch globale Variablen, auf die 
ich auch direkt, über ihren Namen, zugreifen kann.

Zeiger_1

von Johnny (Gast)


Lesenswert?

Klar kannst Du alles global machen, aber wenn Deine Projekte eine 
gewisse Grösse erreichen, kann das schnell mal unübersichtlich werden 
und verleitet zu doofen Fehlern. Daher macht man für Module / Funktionen 
nur die Daten sichtbar, welche für diese relevant sind.

von Klaus W. (mfgkw)


Lesenswert?

Globale Variablen sind für vieles nur bedingt geeignet und enden
sehr schnell in sehr schlechten Programmen.

Es gibt sinnvolle Anwendungen dafür, aber noch viel mehr
Fälle, wo man sie vermeiden sollte.

Daß man etwas theoretisch mit globalen Variablen machen kann,
heißt noch lange nicht, daß man es auch sollte.

von Zeiger_1 (Gast)


Lesenswert?

Hallo Sven,
diese Stichworte kenne ich alle, aber mehr auch nicht, vor allen Dingen 
keine konkreten Beispiele.

Wenn ich z.B. 100 Meßwerte in einem Array ablege und die von 
verschiedenen Funktionen aus bearbeiten will, wo bringen Pointer mir 
Vorteile gegenüber einer Anlage des Arrays als globale Variable ?

Den Speicherplatz für meine Meßwerte brauche ich auf jeden Fall.
Wo kann ich denn hierbei mit Pointern eleganter/effizienter arbeiten ?

Zeiger_1

von Klaus W. (mfgkw)


Lesenswert?

Bei jedem Zugriff auf ein Feldelement verwendest du Pointer, ob du
willst oder nicht.
Egal, ob das Feld lokal oder global ist.

Sobald du nach der Deklaration/Definition des Feldes in deinem
Quelltext den Feldnamen erwähnst, ist das ein Zeiger auf das
erste Element.

von Rogie (Gast)


Lesenswert?

z.B. sind Zeiger nützlich, wenn du eine Funktion programmieren willst, 
um 2 Werte miteinander zu vertauschen. Diese musst du der Funktion 
nämlich als Zeiger übegeben:
Beispiel:
void swap (int *c1, int *c2)
{
  int tmp = *c1;
  *c1 = *c2;
  *c2 = tmp;
}

Dann der Aufruf:

int c1=10;
int c2=20;

swap(&c1,&c2);

von P. S. (Gast)


Lesenswert?

Zeiger_1 schrieb:

> diese Stichworte kenne ich alle, aber mehr auch nicht, vor allen Dingen
> keine konkreten Beispiele.

Mit ein wenig Erfahrung merkst du das schneller selbst, als es dir 
jemand erklaeren kann.

> Wenn ich z.B. 100 Meßwerte in einem Array ablege und die von
> verschiedenen Funktionen aus bearbeiten will, wo bringen Pointer mir
> Vorteile gegenüber einer Anlage des Arrays als globale Variable ?

Nimm etwas ganz einfaches, z.B. atoi(). Zeige mir, wie du das ohne 
Uebergabe eines Pointers implementierst.

von Mark B. (markbrandis)


Lesenswert?

Globale Variablen: Tatsächlich macht es im Embedded-Bereich wesentlich 
öfter Sinn, sie zu verwenden, als bei Software die auf einem Standard-PC 
läuft. Immer fröhlich lokale Variablen auf dem Stack auf- und abbauen 
ist eben auch nicht gerade förderlich für die Performanz. Außerdem weiß 
ich eben bei einer globalen Variablen oder einem globalen Array genau, 
wieviel Speicher draufgeht. Bei einer Funktion mit lokalen Variablen, 
von der ich unter Umständen nicht genau sagen kann wie oft sie 
aufgerufen wird, kann ich den Speicherverbrauch über die Laufzeit nicht 
so genau abschätzen.

Dann wäre da noch MISRA C. Nicht ohne Grund schränkt dieser Standard die 
Verwendung von Zeigern weitgehend ein. Dynamisch Speicher anfordern mit 
malloc() ist verboten. Variable Zeiger auf Funktionen sind verboten. Das 
hat schon seinen Grund, man will hier schließlich Quellen für Fehler und 
Instabilität vermeiden.

Mit Zeigern kann man viel machen, aber eben auch viel Mist. Ein Prof an 
meiner ehemaligen Hochschule (zugegeben ein Vollblut-Informatiker und 
kein Embedded Spezialist) sagte mal in der Vorlesung: "90 Prozent aller 
Fehler in C-Programmen rühren von Zugriffen auf nicht oder falsch 
initialiserte Zeiger her". Wird wohl was dran sein.

Klaus Wachtler schrieb:
> Globale Variablen sind für vieles nur bedingt geeignet und enden
> sehr schnell in sehr schlechten Programmen.
>
> Es gibt sinnvolle Anwendungen dafür, aber noch viel mehr
> Fälle, wo man sie vermeiden sollte.
>
> Daß man etwas theoretisch mit globalen Variablen machen kann,
> heißt noch lange nicht, daß man es auch sollte.

Ersetze "globale Variable" durch "Zeiger", dann kannste das Ganze gleich 
nochmal posten ;-)

von Helmut L. (helmi1)


Lesenswert?

Bestes Beispiel ist z.B. die Stringverarbeitung.

Du hast eine Funktion die 2 String vergleicht ( strcmp ) wenn die jetzt 
mit festen globalen Variablen arbeiten muesste dann koennte sie nur 2 
Strings vergleichen. Da die Funktion strcmp aber 2. Pointer auf String 
mitbekommt kann sie so unendlich viele verschiedene Strings miteinander 
vergleichen. Sie bekommt halt nur die beiden Pointer (Addressen) wo die 
beiden Strings sich befinden mit geteilt.

Am besten du holst dir mal ein Buch ueber die Grundlagen von 'C'



Gruss Helmi

von gast (Gast)


Lesenswert?

Stichwort: "Call by Reference"

Wenn Du in einer Funktion mehr als eine Variable der Aufrufenden 
Funktion ändern willst, geht das nicht per return sondern (in C) nur, 
indem Du die Adresse der zu ändernden Variablen übergibts (wie bei der 
o.a. swap funktion)

von Zeiger_1 (Gast)


Lesenswert?

@Klaus:
Sobald du nach der Deklaration/Definition des Feldes in deinem
Quelltext den Feldnamen erwähnst, ist das ein Zeiger auf das
erste Element.

Da ist sicherlich richtig, aber als Programmierer brauche ich in C beim 
Zugriff auf dieses Array absolut keinerlei Zeiger zu definieren und muß 
auch nicht damit arbeiten.
Ich greife einfach auf das Array-Element zu und fertig ists. Was der 
Compiler im Hintergrund daraus macht, interessiert eigentlich nicht, 
hauptsache es funktioniert (ohne Pointer)

@Rogie
Das Beispiel leuchtet ein

@Peter
atoi ist in meiner stdio-lib enhalten und ich programmiere einfach:
z=atoi(s1);   // wobei s1 ein String ist.
Hier benötige ich keinen Zeiger.

Und dann noch: wozu Pointer auf Funktionen ?

Zeiger_1

von Mark B. (markbrandis)


Lesenswert?

Zeiger_1 schrieb:
> Und dann noch: wozu Pointer auf Funktionen ?

Zum Beispiel für Polymorphie.

von Oliver (Gast)


Lesenswert?

>// wobei s1 ein String ist.

und der hat den Typ char* :-)

Oliver

von Random .. (thorstendb) Benutzerseite


Lesenswert?

warum?
weils einfach einfach ist :-)

do {
  uart_putc(*string);
} while(*string++);


VG,
/th.

von Klaus W. (mfgkw)


Lesenswert?

Es steht dir doch frei, Zeiger zu ignorieren.
Viel Spaß!

von P. S. (Gast)


Lesenswert?

Bei manchen Leuten koennte man meinen, sie fragen um Recht zu bekommen, 
nicht um etwas zu lernen...

von gast (Gast)


Lesenswert?


von Klaus W. (mfgkw)


Lesenswert?

Aber er hat doch recht:
Man braucht keine Zeiger. Globale Variablen gehen auch, sind viel
einfacher und übersichtlicher als lokale.
Sortieren und Suchen braucht man nicht, wenn man in seinem Programm
von Anfang Ordnung hält.
Felder gehen auch ohne Zeiger, statt Strings nimmt man ein paar
char nacheinander.

Und das beste: wir müssen ihm die Zeiger gar nicht erst erklären.

von Zeiger_1 (Gast)


Lesenswert?

Bei manchen Leuten koennte man meinen, sie fragen um Recht zu bekommen,
nicht um etwas zu lernen...

Hallo Peter,
na klar wollte ich was lernen, aber bitte mit einigen einleuchtenden 
Beispielen und nicht mit Statements wie:
Zeiger sind toll, muß man einfach können, Zeiger stehen in jedem 
C-Lehrbúch (na klar, wo denn auch sonst).
Solche allegemeinen Aussagen finde ich überall, aber bei der Angabe von 
Beispielen, die NICHT auf PCs laufen, hapert es dann doch.

Einige ganz konkrete und gute Beispiele habe ich bekommen von Random, 
Helmut und Regie (vielen Dank dafür), aber leider nicht von Dir, Peter.

Zeiger_1

von Klaus W. (mfgkw)


Lesenswert?

Von ihm gibt es auch vernünftige und hilfreiche Beiträge.
Muß nicht an ihm liegen, wenn die Chemie nicht stimmt.

von Klaus W. (mfgkw)


Lesenswert?

achso, und ein relativ einfaches und sehr praktisches Beispiel
für Funktionszeiger:
Die Übergabe einer Vergleichsfunktion an die Funktionen
bsearch() und qsort() aus der Standardbibliothek.

von Mark B. (markbrandis)


Lesenswert?

Naja wenn alle hier nur ein Loblied auf Zeiger singen, muss ich wohl 
daraus schließen, dass sich hier noch keiner mit Standards wie eben 
MISRA beschäftigt hat.

Zeiger haben nicht nur Vorteile. Wer das nicht sehen will, ist im 
Endeffekt ein genauso schlechter Programmierer wie jemand, der sie von 
vornherein für Teufelswerk ;-) hält.

Klaus Wachtler schrieb:
> achso, und ein relativ einfaches und sehr praktisches Beispiel
> für Funktionszeiger:
> Die Übergabe einer Vergleichsfunktion an die Funktionen
> bsearch() und qsort() aus der Standardbibliothek.

Es soll tatsächlich Hardware geben, für die nicht die gesamte C Standard 
Library zur Verfügung steht. Kaum zu glauben, aber wahr.

von Klaus W. (mfgkw)


Lesenswert?

Es ging um ein Beispiel, wozu Zeiger gut sind.

Wenn es auf einem konkreten System kein bsearch gibt und
ich etwas in einem Feld suchen will, schreibe ich bsearch() in
10 oder 20 Zeilen selbst.

Dann habe ich wieder ein Beispiel für Zeiger auf Funktionen.

von Zeiger_1 (Gast)


Lesenswert?

@Klaus:
"Von ihm gibt es auch vernünftige und hilfreiche Beiträge."
Genau, und über so einen hätte ich mich gefreut, da hätte ich etwas 
lernen können.


@Klaus:
Die Übergabe einer Vergleichsfunktion an die Funktionen
bsearch() und qsort() aus der Standardbibliothek

Da ist wieder das Anfangsproblem: ich habe doch geschrieben, das ich 
mich mit 8-Bit-Controllern befasse und dafür einige gute Beispiele für 
Zeiger-Anwendungen suche.

Wie Mark Brandis schon geschrieben hat, gibt es Compiler, die nicht 
alles unterstützen, so kennt mein 8-Bit-Compiler bsearch und qsort 
nicht, das ist dann doch wieder etwas für die PC-Ebene und darum ging es 
mir leider nicht.

Zeiger_1

von Mark B. (markbrandis)


Lesenswert?

Klaus Wachtler schrieb:
> Es ging um ein Beispiel, wozu Zeiger gut sind.
>
> Wenn es auf einem konkreten System kein bsearch gibt und
> ich etwas in einem Feld suchen will, schreibe ich bsearch() in
> 10 oder 20 Zeilen selbst.
>
> Dann habe ich wieder ein Beispiel für Zeiger auf Funktionen.

Gut, es kommt halt auf den Einsatzzweck an. In der Motorsteuerung zum 
Beispiel habe ich bis jetzt noch nicht so viele Such- und 
Sortieralgorithmen gesehen. Woanders wiederum braucht man sie, klar.

von Helmut L. (helmi1)


Lesenswert?

>so kennt mein 8-Bit-Compiler bsearch und qsort
>nicht, das ist dann doch wieder etwas für die PC-Ebene und darum ging es
>mir leider nicht.

Der Compiler selber kennt diese Funktionen auch nicht. Die sind Teil der 
mit dem Compiler gelieferten Bibliotheken. Aber man kann sich ja auch 
selber diese Funktionen schreiben und in eine eigene Bibliothek tun. Und 
schon kennt dein Compiler die auch.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> Es ging um ein Beispiel, wozu Zeiger gut sind.

Hier ist eins:
1
int (*TranslateCommand(char **argv))(int argc, char **argv)
2
{
3
  int i=-1;
4
  int tmp=0;
5
  
6
  tmp = strlen(argv[0]);
7
8
  while(*pShellCmdText[++i])
9
  {    
10
    if(!(memcmp(argv[0], pShellCmdText[i], tmp+1 )) ) return(pShellCmdFunc[i]);     //cmd found
11
  }
12
  return(0);
13
}
14
15
16
int (*pCommand)(int argc, char **argv) = 0;
17
pCommand = TranslateCommand(argv);
18
if(pCommand) retValue = pCommand(argc, argv);

Grübeln dürft ihr selbst :-)

VG,
/th.

von Klaus W. (mfgkw)


Lesenswert?

Zeiger_1 schrieb:
> @Klaus:
> "Von ihm gibt es auch vernünftige und hilfreiche Beiträge."
> Genau, und über so einen hätte ich mich gefreut, da hätte ich etwas
> lernen können.

ich fand das, was er hier geschrieben hat, nicht so unvernünftig.

>
>
> @Klaus:
> Die Übergabe einer Vergleichsfunktion an die Funktionen
> bsearch() und qsort() aus der Standardbibliothek
>
> Da ist wieder das Anfangsproblem: ich habe doch geschrieben, das ich
> mich mit 8-Bit-Controllern befasse und dafür einige gute Beispiele für
> Zeiger-Anwendungen suche.

Am Anfang hattest du geschrieben, daß du generell etwas zu Zeigern 
willst.
Erst später hast du konkret nach Zeigern auf Funktionen gefragt,
wofür du hiermit ein Beispiel hast.
Es kann gut sein, daß du keinen Sinn darin siehst, oder erst später
einen Sinn darin siehst, oder so etwas wirklich nie brauchst.
Da kann aber hier niemand etwas dafür.
Ich brauche Zeiger häufig, Zeiger auf Funktionen gelegentlich,
du musst sie doch nicht nehmen.

>
> Wie Mark Brandis schon geschrieben hat, gibt es Compiler, die nicht
> alles unterstützen, so kennt mein 8-Bit-Compiler bsearch und qsort
> nicht, das ist dann doch wieder etwas für die PC-Ebene und darum ging es
> mir leider nicht.
>
> Zeiger_1

Vom printf im Testprogramm abgesehen auch auf AVR machbar:
1
// sucht in einem sortierten Feld (*base)[] nach einem
2
// Element, für das die Funktion (*compar)() Gleichheit mit dem
3
// Schlüssel (*key) verspricht, und liefert einen Zeiger auf
4
// das gefundene Element, oder NULL
5
// (entspricht dem Original-bsearch() nach ANSI-C)
6
void *bsearch_exakt( const void *key,
7
                     const void *base,
8
                     size_t nmemb,
9
                     size_t size,
10
                     int (*compar)( const void *, const void * )
11
                     )
12
{
13
  switch( nmemb )
14
    {
15
    case 0:
16
      return NULL;
17
18
    case 1:
19
      return ( (*compar)( base, key )==0 ? (void *)base : NULL );
20
21
    default :
22
      // Teilen, und suchen lassen:
23
      {
24
        size_t n1 = nmemb/2;
25
        const void  *p1 = (const char*)base+(n1*size);
26
        int    v1 = (*compar)( p1, key );
27
        if( v1==0 )
28
          {
29
            // Schlüssel genau getroffen
30
            return(void *) p1;
31
          }
32
        else if( v1<0 )
33
          {
34
            // base[n1] kleiner als Schlüssel;
35
            // also in der oberen Hälfte suchen.
36
            // base[n1] braucht schon nicht mehr betrachtet
37
            // zu werden.
38
            return bsearch_exakt( key,
39
                                  (const char*)p1+size,
40
                                  nmemb - n1 - 1,
41
                                  size,
42
                                  compar
43
                                  );
44
          }
45
        else
46
          {
47
            // base[n1] größer als Schlüssel;
48
            // also in der unteren Hälfte suchen.
49
            // base[n1] braucht schon nicht mehr betrachtet
50
            // zu werden.
51
            return bsearch_exakt( key,
52
                                  base,
53
                                  n1,
54
                                  size,
55
                                  compar
56
                                  );
57
          }
58
      }
59
60
    } // switch
61
62
} // bsearch_exakt()
63
64
65
typedef struct
66
{
67
  int schluessel;
68
  int wert;
69
}  wertepaar_t;
70
71
72
// Vergleichsfunktion passend zur Sortierreihenfolge des Feldes:
73
int vergleich_f( const void *p1, const void *p2 )
74
{
75
  return ((const wertepaar_t*)p1)->schluessel - ((const wertepaar_t*)p2)->schluessel;
76
}
77
78
79
int main( int nargs, char **args )
80
{
81
  // (nach .schluessel) sortiertes Feld mit Beispieldaten:
82
  wertepaar_t daten[10] =
83
    {
84
      { 1, 11 },
85
      { 2, 22 },
86
      { 3, 333 },
87
      { 4, 44 },
88
      { 5, -5 },
89
      { 6, 66 },
90
      { 7, 777 },
91
      { 8, 88 },
92
      { 9, 99 },
93
      { 10, -10 },
94
    };
95
96
97
  wertepaar_t zusuchen = { 5, 0 };  // es soll nach 5 gesucht werden,
98
                                    // wert hier egal
99
  wertepaar_t *gefunden_p =
100
    (wertepaar_t *)bsearch_exakt( &zusuchen,
101
                                  daten, 10, sizeof(wertepaar_t),
102
                                  vergleich_f
103
                                  );
104
105
  if( gefunden_p )
106
  {
107
    printf( "gefunden: %d\n", gefunden_p->wert );
108
  }
109
110
  return 0;
111
}

Wenn du das jetzt nicht brauchen kannst, entschuldige ich mich
schon vorher dafür.

von Klaus W. (mfgkw)


Lesenswert?

sorry, ein #include <stdio.h> gehört noch dazu (an den Anfang)...

von 123 (Gast)


Lesenswert?

+ Pointer sind prima um Strukturen an Funktionen zu übergeben

+ Für Scheduler, State-Machines oder Event-Handler sind Pointer auf 
Funktionen sehr praktisch

von Klaus W. (mfgkw)


Lesenswert?

Mark Brandis schrieb:
> Naja wenn alle hier nur ein Loblied auf Zeiger singen, muss ich wohl

Ich singe nicht ein Loblied auf die Zeiger, weil ich sie so toll fände.
Aber in C kommt man halt nicht dran vorbei, sie zu benutzen.


> daraus schließen, dass sich hier noch keiner mit Standards wie eben
> MISRA beschäftigt hat.
> ...

doch, aber teilweise sind die Empfehlungen (als mehr verstehe ich
es nicht) dort auch nicht so ganz praxisnah.
Wer nicht mit Strings und Zeigern umgehen kann, muss es halt
bleiben lassen. Weil die einen nicht damit klar kommen und damit
laufend Fehler bauen, muß man es den anderen ja nicht verbieten.

Die MISRA-Rezepte sind weder öffentlich (soweit ich weiß) noch
allgemein als richtig oder gültig akzeptiert.
Sicher sind sinnvolle Punkte dabei, aber vieles auch gleich
wieder ziemlich dogmatisch oder zumindest zu pauschal.
Wer die Problematik hinter MISRA ernst nimmt und die Fehler,
die man in C bauen kann, vermeiden will, muß auf etwas anderes
umsteigen (Java o.s.ä.); eine KAstration von C hilft nicht viel.

Daß man mit Zeigern viel Blödsinn machen kann, ist unbestritten.
Aber bei Fragen nach Anwendungen von Zeigern gleich damit zu
kommen, sie zu vermeiden, weil man lt. MISRA damit Fehler
machen kann, ist vielleicht doch etwas übertrieben m.E..

von P. S. (Gast)


Lesenswert?

Zeiger_1 schrieb:

> Einige ganz konkrete und gute Beispiele habe ich bekommen von Random,
> Helmut und Regie (vielen Dank dafür), aber leider nicht von Dir, Peter.

Falsch, das Beispiel mit atoi war sehr konkret, du hast es nur nicht 
verstanden. Nach wie vor steht die Aufgabe fuer dich im Raum, atoi() 
ohne Zeiger zu implementieren.

von Stefan Kunz (Gast)


Lesenswert?

Ein Beispiel für die Verwendung von Zeigern auch für den 
Embedded-Bereich wäre die Berechnung einer DFT/FFT, wo man, je nach 
Programmierung, ein Array übergeben muss mit den Messwerten und ein 
zweites für das Ergebnis.
Mit Zeigern programmiert wunderbar portierbar.
Mit einer globalen Array würd man den Code nicht nochmal benutzen können 
bzw. eingeschränkt.
Ein anderer Grund warum man die Verwendung von globalen Variablen 
einschränken sollte, ist der einfache, dass diese Variablen in den 
fertigen Bibliotheken "überschreiben" könnten.

MfG
Stefan

von Sven P. (Gast)


Lesenswert?

Zeiger sparen jede Menge Datenschaufelei bei Strukturen, das habe ich 
dir aber ganz zu Beginn bereits gesagt. Und genau das ist auf 8bittern 
doch sinnvoll, oder nicht?
Sonst benutzt du für jeden Port-Zugriff übrigens auch Zeiger, auch wenn 
du das nicht merkst. Dann braucht man die, um mit dem EEProm und dem 
Programmspeicher zu reden (EEPROM, PROGMEM)...

von tobi (Gast)


Lesenswert?

Angenommen du hast eine Reihe von String (char-arrays).
Mit diesen möchtest du im Laufe des Programms etwas tun, d.h. mit einer 
Funktion manipulieren oder ähnliches.
Willst du nun für jedes Array eine extra Funktion schreiben?
Falls das Array was du bearbeiten willst lokal ist, willst du dann 
erstmal das ganze in einen globalen Buffer schreiben? Auch wenn der 
Buffer sehr lang aber das zu bearbeitende Array sehr kurz ist?

Zeiger sind unter Anderem immer dann sinnvoll wenn du Felder/Strukturen 
usw. bearbeiten/lesen willst die du aber noch nicht konkret kennst. Da 
ist es imho einfacher und übersichtlicher sich einfach einen Zeiger und 
die Länge übergeben zu lassen anstatt immer auf etwas globales 
zuzugreifen, welches dann vorher immer entsprechend zu beschreiben bzw. 
dies nachher erst auszulesen.

Wenn du deinen Code so strukturierst das du zusammengehörige 
Funktionalität jeweils in einer Datei steht dann wird es schnell 
verwirrend wenn du dann immer auf globale Elemente aus anderen Dateien 
zugreifst. Irgendwann verlierst du den Überblick wann und wo welches 
deiner globalen Elemente beschrieben wird. Da ist es einfacher und 
vorallem übersichtlicher wenn du dir einfach einen Zeiger übergeben 
lässt und dann mit diesem arbeitest.

Wenn man mit Pointern unvorsichtig umgeht können diese einem das Leben 
schwer machen. Andersrum wird einiges auch durch bewusste nutzung von 
Pointern vereinfacht.

von Rene H. (Gast)


Lesenswert?

Alles was mehr als 8 Byte zum übergeben ist musst Du mit Pointern 
machen. Andere Gründe dafür:

- linked list
- rekursion

Es gibt viele Gründe wo Pointer nicht nur Sinnvoll sind, sondern auch 
nötig.

von joep (Gast)


Lesenswert?

>Zeiger haben nicht nur Vorteile. Wer das nicht sehen will, ist im
>Endeffekt ein genauso schlechter Programmierer wie jemand, der sie von
>vornherein für Teufelswerk ;-) hält.
Ich würde sagen Zeiger haben nur dann nicht nur Vorteile, wenn man nicht 
richtig mit ihnen umgeht. Wenn man fit in der C-Programmierung und mit 
Zeigern ist sehe ich keine Nachteile darin.

Zeiger sind einfach ein schönes Werkzeug der Sprache C. Natürlich lassen 
sich auch alle Probleme (theoretisch) ohne Zeiger lösen. Allerdings 
kommt ja auch niemand auf die Idee alle Programme in asm zu schreiben, 
nur weil es eben gehen würde.

Genauso könnte der Threadersteller auch fragen warum es eine 
for-Schleife in C gibt. Mit einer while-Schleife lässt sich ja auch jede 
for-Schleife ersetzen. Das selbe mit switch case -> if usw.

Übrigens spätestens wenn du einigermaßen modulare Funktionen schreiben 
möchtest, die vielleicht auch noch in einem anderen Projekt verwendet 
werden sollen wirst du meistens Zeiger brauchen.

>Mark Brandis schrieb:
>>Klaus Wachtler schrieb:
>> achso, und ein relativ einfaches und sehr praktisches Beispiel
>> für Funktionszeiger:
>> Die Übergabe einer Vergleichsfunktion an die Funktionen
>> bsearch() und qsort() aus der Standardbibliothek.

>Es soll tatsächlich Hardware geben, für die nicht die gesamte C Standard
>Library zur Verfügung steht. Kaum zu glauben, aber wahr.
Es soll auch tatsächlich Hardware geben, für die keine Integer-Typen, 
while-Schleifen und/oder Strukturen gebraucht werden, also wofür gibts 
die ganzen Dinge in C?
Sorry, aber die Begründung ist doch total am Ziel vorbeigeschossen.

von sebba (Gast)


Lesenswert?

Globale Variablen um Daten in Funktionen zu schieben und wieder 
rauszuholen?!

Das ist 1. total unübersichtlich,
2. ziemlich ineffizient (ich muss ja immer erst die Daten in diese eine 
globale Variable kopieren)
3. extrem schlechter Stil
und im großen und ganzen einfach Quatsch!

Funktionen sind ja extra dafür da, dass man sie mehrfach verwenden kann. 
Wenn ich nun eine Funktion habe, die mir einen String auf der seriellen 
ausgibt, will ich doch meinen String nicht immer erst an eine bestimmte 
Speicherstelle kopieren. Und erst recht nicht ohne Zeiger...

ich darf ja dann nichtmal

while(*src)
  *(dst++) = *(src++);

machen, sondern muss

buchstabe1_ziel = buchstabe1_quelle;
buchstabe2_ziel = buchstabe2_quelle;
buchstabe3_ziel = buchstabe3_quelle;

machen.

Also alles in allem ist C ohne Zeiger so wie assembler wenn man nur 
"and", "not und "jz" hat... Es geht, aber schön ist das nicht.


So, Senf dazugegeben, glücklich, tschüß
Sven

von Random .. (thorstendb) Benutzerseite


Lesenswert?

> buchstabe1_ziel = buchstabe1_quelle;
> buchstabe2_ziel = buchstabe2_quelle;
> buchstabe3_ziel = buchstabe3_quelle;
1
#define zielQuelle(number)  buchstabe##number##_ziel = buchstabe##number##_quelle
2
3
zielQuelle(0);
4
zielQuelle(1);
5
zielQuelle(2);
6
zielQuelle(3);

muuhahahahaha

von P. S. (Gast)


Lesenswert?

joep schrieb:

> Zeiger sind einfach ein schönes Werkzeug der Sprache C.

Eigentlich sind Zeiger sogar grundlegender Bestandteil unserer 
Rechnerarchitekturen (ja, es gibt Ausnahmen). C stellt sie nur zur 
Verfuegung. In den "guten alten Zeiten (TM)" hat das auch Basic ganz 
selbstverstaendlich getan. Sprachen, die keine Zeiger kennen, sind also 
eher der Spezialfall, weil sie einen wesentlichen Bestandteil der 
zugrundeliegenden Architektur verstecken. Hat man verstanden, wie ein 
Rechner funktioniert, sind Zeiger auch gar nichts so besonderes. Muehe 
haben damit eher die Leute, die erst lernen wie man programmiert und 
dann, wie ein Rechner funktioniert.

Nur mal so, weil es manchmal so klingt, als seien Zeiger irgendwie eine 
schlecht ueberlegte Idee der C-Erfinder gewesen...

von JojoS (Gast)


Lesenswert?

Arrays sind auch böse weil nur eine andere Schreibweise für Zeiger, ein 
falsch berechneter Index führt zu gleichen Fehlern.
MISRA oder ähnliches ist ja nicht extra für 8-Bitter, im Gegenteil ich 
denke das wird eher auf grösseren µCs angewendet die z.B. auch eine MMU 
haben (wobei man die Regeln für defensive Programmierung sicher sinnvoll 
sind). Ich habe selber lange Zeit mit einem spez. protected Mode OS 
gearbeitet und alle Module liefen in eigenen Code- und Memorysegmenten. 
Wenn man da irgendwo ein Byte zuviel gelesen oder geschrieben hat stand 
alles (dafür exakt an dem fehlerhaften Code und wartete auf den 
Debugger). Da lernt man den Unterschied zwischen Programmen die 
funktionieren und solchen die robust sind.
Aber für 8-Bitter nimmt man ja gerade C (wenn nicht Assembler) weil die 
Resourcen limitiert sind. Exzessive Zeigerverschachtelungen und dyn. 
Speicherorgien machen deshalb sowieso keine Freude, dafür sind z.B. die 
AVR RISC Befehlssätze garnicht ausgelegt.

von Mark B. (markbrandis)


Lesenswert?

Tja, dann muss es wohl sehr viele Leute geben, die nicht richtig 
programmieren können und es trotzdem tun - bei den vielen kritischen 
Sicherheitslücken, die durch Buffer Overflows zustande kommen... :-)

Schön wäre es, wenn man in C Exceptions werfen könnte, anstatt dass sich 
bei einem fehlerhaften Zeiger- oder Array-Zugriff das Programm gleich 
komplett verabschiedet oder durch undefiniertes Verhalten glänzt.

von Klaus W. (mfgkw)


Lesenswert?

Ja, nur ist halt C nunmal C.

Ich nehme ja auch lieber C++, wo nur irgend möglich - leider nicht
auf den kleinen Mistdingern mit ein paar Byte RAM.

Aber das ist, was ich oben meinte: wenn man C für zu gefährlich hält,
muß man in den sauren Apfel beißen und mehr Geld für einen "echten"
Rechner ausgeben, der genug RAM und ROM hat für C++ oder Java oder
sonstwas. Darf ein MC nur 2 EUR kosten, muß man C oder Assembler
nehmen. Damit lebt man billiger, aber hat den Spagat zwischen
effizient und fehlerträchtig vor sich. Das wiederum geht nur gut,
wenn man in C (dto. ASM) weiß was man tut, d.h. die Leute sind
mindestens um das teurer, was man sich am Rechner spart.

von Karl H. (kbuchegg)


Lesenswert?

Mark Brandis schrieb:
> Tja, dann muss es wohl sehr viele Leute geben, die nicht richtig
> programmieren können und es trotzdem tun - bei den vielen kritischen
> Sicherheitslücken, die durch Buffer Overflows zustande kommen... :-)
>
> Schön wäre es, wenn man in C Exceptions werfen könnte, anstatt dass sich
> bei einem fehlerhaften Zeiger- oder Array-Zugriff das Programm gleich
> komplett verabschiedet oder durch undefiniertes Verhalten glänzt.

Bringt dir nichts.
Exceptions sind kein Allheilmittel. Am Anfang steht immer das 
Bewusstsein, dass an einer bestimmten Programmstelle etwas passieren 
kann. Gleich danach kommt die Überlegung, wie ich diesen fehlerhaften 
Zustand detektieren kann. Und dann die Entscheidung: werfe ich eine 
Exception oder liefere ich einen Fehlercode zurück.
-> Wenn du den Fehler nicht frühzeitig erkennst, hilft dir auch eine 
Exception nichts, weil keiner da ist, der sie wirft.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> Aber das ist, was ich oben meinte: wenn man C für zu gefährlich hält,
> muß man in den sauren Apfel beißen und mehr Geld für einen "echten"
> Rechner ausgeben,

falsch.
Wenn man C für zu gefährlich hält, muss man lernen wie man die Gefahr 
meistern kann und plötzlich verliert diese 'Gefahr' völlig ihren 
Schrecken.

Klar, ein 'Pointer im Gehölz' kann einem den Tag versauen. Aber das kann 
eine simple Addition auch, wenn sie überläuft. Wer schützt mich 
eigentlich davor, in einer for-Schleife die Abbruchbedingung falsch zu 
formulieren und eine Endlosschleife zu bauen?

Das Ganze ist ein bischen wie: Wir verbieten Hämmer und erlauben nur 
noch Schraubenzieher. Dort ist die Gefahr geringer, dass man sich auf 
den Daumen haut.

von Karl H. (kbuchegg)


Lesenswert?

Zeiger_1 schrieb:
> alles unterstützen, so kennt mein 8-Bit-Compiler bsearch und qsort
> nicht, das ist dann doch wieder etwas für die PC-Ebene und darum ging es
> mir leider nicht.

Warum soll das was nur für die PC Ebene sein.
Versuch mal einen kleinen Zeit-Scheduler zu schreiben. Du wirst 
draufkommen, dass eine vernünftiger Ansatz darin besteht, die 
zukünftigen Events nach ihrer zeitlichen Reihenfolge zu ordnen. Und 
schon musst du sortieren und hast einen vernünftigen Einsatz für qsort.

von Klaus W. (mfgkw)


Lesenswert?

@ Karl heinz Buchegger:

Das sehe ich genauso, es setzt aber Programmierer voraus, mit denen
das klappt.
Bei der MISRA-Schiene (auf die mich mit meiner Litanei eigentlich
noch bezog) wird versucht, C so zu kastrieren, daß es hoffentlich
ungefährlich wird.
Das halte ich eben für frommes Wunschdenken und eine gefährliche
Illusion, auch wenn etliche der Empfehlungen natürlich Sinn machen.
Irgendwie erinnert mich das an die tollen "sicheren" Funktionen
in Visual C++ wie strcat_s() etc., die genauso gefährlich sind
wie ihre Originale, wenn man sie nicht verstanden hat.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:

> Erst später hast du konkret nach Zeigern auf Funktionen gefragt,
> wofür du hiermit ein Beispiel hast.
> Es kann gut sein, daß du keinen Sinn darin siehst, oder erst später
> einen Sinn darin siehst, oder so etwas wirklich nie brauchst.

Versuch mal ein halbwegs universell verwendbares Menüsystem zu 
schreiben, welches auch noch gut konfigurierbar sein soll und nicht 
allzuviel Platz wegnehmen darf.
Ohne Funktionszeiger bist du dort mehr oder weniger aufgeschmissen.

Nur mal so als Beispiel für den TO.

von Karl H. (kbuchegg)


Lesenswert?

Aber zur Ehrenrettung des TO möchte ich noch sagen:
Ich kann ihn schon verstehen. Die üblichen Einführungsbeispiele zu 
Zeigern
1
int main()
2
{
3
  int  i = 0;
4
  int* pi = &i;
5
6
  *pi = 5;
7
  printf( "%d\n", i );
8
}

sind wirklich witzlos. Kein Mensch verwendet Zeiger in dieser Form. Das 
Beispiel soll einen Aspekt demonstrieren, nämlich dass jede Variable 
eine Adresse im Speicher hat und Zugriffe auch über diese Adresse 
geführt werden können. Mehr nicht.

Das wahre Potential von Zeigern erschliesst sich erst, wenn sie im 
Konzert der restlichen Sprachwerkzeuge mitspielen. In diesem Sinne sind 
die meisten Dinge in einer Programmiersprache für sich alleine gesehen 
trivial und eigentlich ziemlich uninteressant. Die wahre Mächtigkeit 
kommt erst dadurch zustande, dass man diese Dinge auf vielfältige Weise 
miteinander kombinieren kann.
So auch bei Zeigern. Auf den ersten Blick erscheinen sie harmlos und 
simpel. Aber ihre Power merkt man erst, wenn man sie in einem Programm 
zum Einsatz bringt.

Bsp:
Was ist der grundlegende Unterschied zwischen diesen beiden 
Funktions-Variationen
1
void lcd_string( char * pString )
2
{
3
  while( *pString != '\0' )
4
    lcd_char( *pString++ );
5
}
1
void lcd_string( char String[] )
2
{
3
  uint8_t i;
4
5
  for( i = 0; i < strlen( String ); ++i )
6
    lcd_char( String[i] );
7
}

(mal abgesehen davon, dass die Verwendung von strlen in der 
Abbruchbedingung sagen wir mal ... suboptimal ... ist)

Richtig: Bei der ersten Version, die konsequent auf Zeigerbenutzung 
ausgelegt ist, ist die Stringlänge nicht limitiert.
Bei der zweiten Version sollte man beten, dass der String besser nicht 
länger als 255 Zeichen ist.

Sicherer, im Sinne von 'kommt auch mit ungültigen Strings zurecht', ist 
keine der beiden Versionen. Ein klares Beispiel, in dem man sich durch 
den Verzicht auf Zeiger keinen Vorteil sondern einen Nachteil 
eingehandelt hat.

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.