# Header Dateien Verwirrung!



## ocsme (27. Aug 2019)

Guten Tag,

derzeit beschäftige ich mich etwas mit C und habe einige Fragezeichen im Kopf vor allem bezüglich den Header-Dateien.
Ich weiß das man so gesehen alles in eine Header Datei schreiben kann. So habe ich aus dem Buch Grundkurs C von Jürgen Wolf das Beispiel hier nach gebaut:

Hallo.h (hab diese Datei erst Kompiliert danach hatte ich in der main() im Terminal nur rosa Rauschen )

```
#include <stdio.h>

int i;

void print_was() {
    printf("Hallo %d\n",i);
}
```

Main.c

```
#include <stdio.h>
#include <stdlib.h>
#include "Hallo.h"

int main(void) {
    int j;
    for( j = 0; j < 10; j++,i++) {
        print_was();
    }
    return 0;
}
```

Also kann ich ganze C Programme in die Header Datei rein kopieren. Nun dachte ich mir mhhh... das erinnert mich doch sehr stark an die ganzen Standard Klassen von Java also schauen wir mal in den /usr/include Ordner rein und Ja gefunden Math.h z. b. Doch dort stehen ja nur Konstanten, Variablen und Direktiven drin. 
Wo bekommt man aber die Funktionen sqrt,... her wenn man die Math.h includet?

Vielleicht kann das jemand für "doofies" Erklären.

Denn ich habe schon viel im Internet nachgelesen und nichts gefunden. Dachte auch erst mhhh... vielleicht liegt ja eine Bibliothek hinten dran das nichts anderes ist als ein Archivdatei aus Kompilierten Dateien.

Kann mir doch sicher jemand Helfen 

LG


----------



## fhoffmann (27. Aug 2019)

Uralte C-Compiler haben bei Auftreten eines #include den Inhalt der Datei, die included wird, an die Stelle des #include geschrieben und die c-Datei anschließend kompiliert. Das tun sie schon lange nicht mehr; aber mann kann sich den Vorgang dennoch so vorstellen, als täten sie es. Deshalb ist dein Beispiel auch kompilierbar.

Üblich ist es jedoch, nur die Deklaration einer Methode (Klasse) in die Header-Datei zu schreiben. Die Impementation gehört in die zugehörige c-Datei. Dann wird die Implementation nur einmal kompiliert. In allen anderen Dateien, die die Header-Datei includen, ist nur bekannt, dass die Methode existiert.


----------



## ocsme (27. Aug 2019)

Vielen Dank für die schnelle Antwort.

Okay das leuchtet mir ein ich sehe die Header Datei so ein bisschen wie eine ART Interface bei Java. Doch was ich überhaupt nicht verstehe ist woher weiß nun mein Programm wenn ich die Standard Header Datei includiere oder eine von mir ausgedachte in welchem C Code die Funktion liegt.
Ist etwas doof geschrieben. Als Beispiel ganz einfach man schreibt immer #include <stdio.h> so nun ist das ja ein Standard Fall doch woher weiß nun das C Programm, dass ich schreibe, wo die Funktion zu finden ist? in stdio steht nur drin das es eine printf Funktion gibt aber WO???? 

Das Beispiel lässt sich ja nun auf sämtliche Datentypen zurück führen nehmen wir z. B. ich habe eine Stack.h dort steht so etwas drin wie pop(), push() ... <- die ganzen Funktionen von dem Stack // so in etwas wäre ja nun auch ein Interface in Java
nun include ich diese Headerdatei in meine MainStack.c. Dort wird nun der Stack ausprogrammiert. Wenn ich den Stack nun benutzen wollen würde in einem anderen Programm include ich ja sicherlich nicht Stack.h? wenn doch dann verstehe ich einfach nicht woher das Programm weiß wo MainStack dann ist? 

Irgendwie verstehe ich immer noch nichts!

LG


----------



## kneitzel (27. Aug 2019)

Der C-Compiler hat keine Ahnung, wo die Funktion liegt. Er weiß nur, dass es die geben soll.

Verantwortlich ist für das zusammen stückeln dann der sogenannte Linker. Dem wird gesagt, was er alles zusammen packen soll. Und dabei gibt es dann bei jedem Part sowas wie ein Inhaltsverzeichnis. Eine Library sagt z.B. was sie alles an Funktionen hat (und wo diese in der Library zu finden sind) aber auch, was sie alles braucht. Der Linker setzt das dann zusammen. Da wo stand, was gebraucht wird, schreibt er dann, wo es zu finden ist. Sollte irgendwo etwas gebraucht werden, was der Linker nicht gefunden hat, dann meckert der Linker.

Wenn Du eine Library baust, dann musst Du also die Header Datei weiter geben und die Library selbst. Das kann dann eine .lib Datei sein. Die Header Datei nutzt der Compiler, der Linker nutzt dann die .lib Datei.


----------



## ocsme (27. Aug 2019)

kneitzel hat gesagt.:


> Wenn Du eine Library baust, dann musst Du also die Header Datei weiter geben und die Library selbst. Das kann dann eine .lib Datei sein. Die Header Datei nutzt der Compiler, der Linker nutzt dann die .lib Datei.



Hier den Link habe ich gefunden schon vor ein paar Tagen und ich glaube jetzt habe ich auch das hier verstanden 



			Programmieren mit gcc
		



> *Mehr Spaß mit Libraries       *
> Bevor wir die Gefilde von _gcc_ verlassen, wollen wir noch ein paar Worte zum Thema Linken und Libraries sagen. Es ist gar nicht so schwierig, eigene Bibliotheken zu erzeugen. Wenn Sie eine Reihe von Routinen geschrieben haben, die Sie häufig aufrufen, sollten Sie diese vielleicht zu einer Gruppe von Quelltextdateien zusammenfassen, aus jeder Quelldatei eine Objektdatei erzeugen und dann aus diesen Objektdateien eine Bibliothek erstellen. Anschließend brauchen Sie diese Routinen nicht mit jedem Programm, das darauf zugreift, erneut zu kompilieren.
> 
> Nehmen wir an, daß Sie einige Quelldateien haben, in denen häufig benutzte Routinen wie zum Beispiel
> ...



Das probiere ich später mal aus und gebe Bescheid 
Dann habe ich das ganze nun auch verstanden Danke an euch zwei


----------



## ocsme (27. Aug 2019)

So ich habe nun das ganze versucht doch bekomme es nicht hin da ich auch nicht genau weiß in welchen Ordern die Daten hin müssen bzw. wollte die ganzen Daten auf dem Desktop lassen  <- da ich nicht weiß in welche lib oder include Verzeichnis dort die Rede ist. usr/include und /usr/lib/gcc/x86_64-linux-gnu/7.4.0???

Deswegen habe ich folgendes gemacht was bis jetzt auch geklappt hat. Alle Dateien auf dem Deskopt(Schreibtisch) gespeichert:

min.c

```
int min(int a, int b) {
    return a > b ? b : a;
}
```

max.c

```
int min(int a, int b) {
    return a > b ? a : b;
}
```

Natürlich sind die zwei Dateien nicht sehr sinnhaft es geht mir ja nur darum das ich das mit den Libraries und Header Dateien besser verstehe 

Als nächstes habe ich die Zwei .c Dateien übersetzt mit:
*gcc -c max.c min.c*

Danach noch die Librarie erstellt mit:
*ar rs libstuff.a max.o min.o*

zu guter Letzt habe ich die Header Datei erstellt mit den Einträgen:
libstuff.h

```
extern int min(int,int);
extern int max(int,int);
```

main.c

```
#include <stdio.h>
#include "/home/test/Schreibtisch/libstuff.h"

int main(void) {
    
    printf("%d %d\n", max(3,4),min(3,4));
    
    return 0;
}
```

Sobald ich nun versuche die Datei mit gcc -o main main.c zu übersetzen bekomme ich folgende Fehlermeldung:


> gcc -o Main Main.c
> /tmp/cc2Wbeyn.o: In Funktion »main«:
> Main.c.text+0x14): Warnung: undefinierter Verweis auf »min«
> Main.c.text+0x25): Warnung: undefinierter Verweis auf »max«
> collect2: error: ld returned 1 exit status



Da ich keine Ahnung habe wo die Liebarie hin muss den diese ist ja nun auch auf meinem Desktop wie die Header Datei!  Denke ich das er diese Liebarie eben nicht findet und dann sagt min und max gibt es nicht.

Kann mir dabei vielleicht nochmal jemand weiter Helfen?
Denn ich habe auch von meinem Link oben nicht so ganz verstanden wie das mit diesen Schaltern hier gemeint ist:


> Mit der Option -_I_ weisen Sie _gcc_ an, das Verzeichnis _include_ in den Include-Pfad einzufügen, in dem _gcc_ nach Include-Dateien sucht. Die Option -_L_ funktioniert ganz ähnlich, indem sie _gcc_ anweist, das Verzeichnis _lib_ in den Library-Pfad einzutragen.
> 
> Das letzte Argument auf der Befehlszeile ist -_lstuff_; damit wird der Linker angewiesen, die Bibliothek _libstuff.a_ einzubinden (solange sie irgendwo im Library-Pfad zu finden ist). Das _lib_ am Anfang des Dateinamens wird für Bibliotheken automatisch angenommen.
> 
> Sie sollten den Schalter -_l_ auf der Befehlszeile jedesmal benutzen, wenn Sie andere als die Standardbibliotheken einbinden wollen. Wenn Sie beispielsweise mathematische Routinen aus _math.h_ benutzen möchten, sollten Sie am Ende der _gcc_-Befehlszeile -_lm_ anhängen, womit _libm_ eingebunden wird. Bedenken Sie aber, daß die Reihenfolge der -_l_-Optionen von Bedeutung ist. Ein Beispiel: Wenn Ihre Bibliothek _libstuff_ Routinen aus _libm_ aufruft, dann muß in der Befehlszeile -_lm_ hinter -_lstuff_ stehen:



LG


----------



## kneitzel (27. Aug 2019)

Also die genannten Verzeichnisse sind nicht für von Dir erstellte Include und Library Dateien. Die kannst Du irgendwo hin legen und dann gibt Du den Ort lediglich mit an.

Du kannst die Dateien aber auch bei dir im Verzeichnis ablegen, das ist auch ok.

Beim übersetzen musst Du dann aber natürlich angeben, dass er die library mit einbinden soll. Das wäre dann z.B. ein -l stuff
Wenn die libstuff.a woanders liegt, dann kannst Du auch noch den Ort angeben mit -L
Also gcc -o main -l stuff main.c

Ist aber bei mir schon sehr lange her, dass ich sowas gemacht habe, daher bitte nicht böse sein, wenn ich das etwas falsch in Erinnerung haben sollte. (Mein Wechsel weg von C++ war 2003   )


----------



## ocsme (27. Aug 2019)

Leider bekomme ich das Kompilieren einfach nicht hin.
Die ganzen Dateien liegen auf dem Schreibtisch, habe die Datei libstuff.a mal nach /usr/lib/gcc/x86_64-linux-gnu/7.4.0 verschoben und versucht zu Kompilieren. 

Immer noch der selbe Fehler 

Keine Ahnung am liebsten hätte ich ja so etwas wie z. B.
gcc -o main main.c libstuff.a benutzen 

Was ich nur nicht verstehe ist das es auch nicht in C von A - Z drin steht z. B.  zumindest habe ich unter den Begriffen Librarie, Libraries, Bibliothek und Header nichts gefunden was zum Thema passt  Kann doch nicht wahr sein 

Naja wenn nicht lass ich es einfach denn so habe ich es ja nun verstanden denn das erklärt dann auch das man z. B. unter der Header Datei math.h die Funktionen so nicht findet diese sind dann schon Kompiliert in einer Librarie drin  Das habe ich ja nun alles verstanden 

Dann geht es morgen mal an die Arrays und Strings 

LG


----------



## mihe7 (28. Aug 2019)

ocsme hat gesagt.:


> gcc -o main main.c libstuff.a


Das sollte auch funktionieren, wenn libstuff.a sich im gleichen Verzeichnis befindet. Alternativ `gcc -o main main.c /home/test/Schreibtisch/libstuff.a`

Mach einfach nochmal von vorne: leg Dir erstmal ein Verzeichnis für das ganze Zeug an. Darunter erstellst Du nochmal zwei Verzeichnisse, namentlich stuff und app. Dabei simuliert stuff ein Library-Projekt und app eine Anwendung.

In stuff legst Du die Dateien libstuff.h, min.c und max.c ab. Innerhalb von stuff erzeugst Du auch die lib (gcc und ar, wie Du es ja schon gemacht hast). Danach solltest Du die Dateien

```
stuff/libstuff.h
stuff/min.c
stuff/max.c
stuff/min.o
stuff/max.o
stuff/libstuff.h
```
haben.

Unter app legst Du Dir erstmal die main.c:

```
#include <stdio.h>
#include "libstuff.h"

int main(void) {
    
    printf("%d %d\n", max(3,4),min(3,4));
    
    return 0;
}
```
Beachte das angepasst include (Deines würde auch funktionieren, aber so hast Du keine absoluten Pfadangaben in der Datei).

Du kannst Deine main kompilieren:

```
gcc -c main.c -I ../stuff
```
und linken

```
gcc -o main main.o -lstuff -L ../stuff
```
oder auch beides zusammen

```
gcc -o main main.c -I ../stuff -L ../stuff -lstuff
```

Mit -I (großes Ida) gibst Du ein (zusätzliches) Verzeichnis an, in dem der Compiler nach header-Files suchen soll. Du kannst gcc auch mitteilen, dass er dort nur nach Headerfiles suchen soll, die mit Anführungszeichen inkludiert wurden. Dazu wird dann -iquote statt -I verwendet.

Mit -l (kleines Ludwig) gibst Du an, welche Lib (der Linker sucht bei Angabe von -lstuff nach libstuff.a) verwendet werden soll, mit -L dagegen, wo der Linker (zusätzlich) nach Libs suchen soll.


----------



## kneitzel (28. Aug 2019)

ocsme hat gesagt.:


> gcc -o main main.c libstuff.a benutzen



Also da fehlt das -l und bei einer Library wird das .a und das führende lib nicht mit angegeben.
Wo mihe7 aber Recht hat: Da war damals kein Leerzeichen, also -lstuff war die Ausgabe, die notwendig ist.

Du kannst auch noch einmal https://access.redhat.com/documenta...7/html/developer_guide/creating-libraries-gcc durchgehen. Wichtige Anmerkung: Du baust keine shared LIbrary sondern eine static library.

Du könntest z.B. einmal die library prüfen wie dort angegeben: nm libstuff.a
Mir fällt z.B. auf, dass Du da ar rs .... angegeben hast aber ar rcs ... als Aufruf in der verlinkten Dokumentation angegeben wurde.

Also ich habe es auf meinem Linux jetzt einmal nachvollzogen. Zwei Verzeichnisse: lib und test:

in lib: min.c, max.c
Aufrufe:
gcc -c min.c max.c
==> min.o, max.o wurden erzeugt
ar rcs libstuff.a min.o max.o
==> libstuff.a wurde erzeugt
nm libstuff.a:

min.o:
0000000000000000 T min

max.o:
0000000000000000 T max

cp libstuff.a ../test
==> Ergebnis kommt ins test Verzeichnis.

Nun geht es weiter in test:
- libstuff.a ist schon da, also kommt noch libstuff.h und main.c dazu.

Nun versuche ich das übersetzen mit:
gcc -o main -L. -lstuff main.c
/tmp/cccjjue: In function `main':
main.c.text+0x14): undefined reference to `min'
main.c.text+0x25): undefined reference to `max'
collect2: error: ld returned 1 exit status

Hmm, unerwartetes Ergebnis ... Im Augenblick verstehe ich das nicht muss ich gestehen. Die Library findet er, denn lasse ich -L. weg, dann meckert er -lstuff an.

Versuchen wir was anderes:
gcc -c main.o main.c
==> main.o wird erzeugt

gcc -o main main.o libstuff.a 
==> main wird erzeugt und kann aufgerufen werden ...

rm main main.o && gcc -o main main.c libstuff.a 
=> funktioniert auch

Und dann schaut man sich das etwas an und siehe da: Ich habe etwas vergessen:
gcc <source files> <Options>
Also nächster Versuch

gcc main.c -L. -lstuff -o main
==> Yeah, wieso nicht gleich so 

Gegenprobe: das main.c wieder ans Ende gesetzt:
konrad@mba:~/Projects/c++/test$ gcc -o main -L. -lstuff main.c
/tmp/ccxcwucN.o: In function `main':
main.c.text+0x14): undefined reference to `min'
main.c.text+0x25): undefined reference to `max'
collect2: error: ld returned 1 exit status
konrad@mba:~/Projects/c++/test$ 

Nunja - sowas passiert, wenn man sich einige Jahre nicht mit sowas beschäftigt hat


----------



## kneitzel (28. Aug 2019)

Also wieso das -lstuff am Ende sein muss verstehe ich immer noch nicht. (Die anderen Optionen können auch vor dem main.c kommen in meinen Tests.)

Ich habe da jetzt diverse Seiten überflogen aber habe dafür keine Erklärung gefunden. Aber evtl. hat da ja noch jemand eine Erläuterung für.

Ich hoffe aber, dass Du die Schritte, die ich beschrieben habe, auch nachvollziehen kannst.

Ach ja: Eine Änderung hatte ich an Deiner main.c: Ich habe die .h Datei ohne Pfad angegeben - im aktuellen Verzeichnis wird die ja gefunden.


----------



## httpdigest (28. Aug 2019)

kneitzel hat gesagt.:


> Also wieso das -lstuff am Ende sein muss verstehe ich immer noch nicht. (Die anderen Optionen können auch vor dem main.c kommen in meinen Tests.)


Diese Stackoverflow-Antwort erklärt es eigentlich ganz gut: https://stackoverflow.com/questions...der-of-l-option-in-gcc-matter#answer-11894098


> When you add a library using the -loption, the linker does not unconditionally take _all_ object files from the library. It only takes those object files that are _currently needed_, i.e. files that resolve some currently unresolved (pending) symbols. After that, the linker completely forgets about that library.


----------



## kneitzel (28. Aug 2019)

Ahh, super. Wobei ich mich gerade Frage, ob das ein neues Verhalten ist oder ob ich das von 2003 noch hätte kennen müssen (und ich schlicht nur nicht drüber gestolpert bin auf Grund von Makefiles, die immer erst objectfiles erzeugt haben und am Ende alles verlinkt hatten ...)

Aber bin erst einmal unterwegs und auf dem Handy lässt sich sowas nicht gut recherchieren.


----------



## kneitzel (28. Aug 2019)

Ahh, in dem Stackoverflow-Thread ist die Antwort auf meine Frage schon drin. Das ist eine Posix / GCC Sache. Ein User merkt da an: "Other compiler tools like msvc and borland doesn't follow this approach and it works just fine. "

==> Meine damalige Entwicklung lief fast ausschließlich unter Windows und ich habe so 88/89 mit Turbo C 2.0 angefangen und bin da sehr lange eben auf diesem Compiler geblieben (über Turbo c++ / Borland C++) ehe ich dann 2000 auf Visual Studio 6 gewechselt bin...)

Und alle Entwicklungen auf Linux liefen rein über (generierte) Makefiles, so dass ich da nicht drüber gestolpert bin.


----------



## mihe7 (28. Aug 2019)

kneitzel hat gesagt.:


> Also da fehlt das -l und bei einer Library wird das .a und das führende lib nicht mit angegeben.


Du kannst auch direkt die .a-Datei angeben. Von der man-Page

```
The only difference between using an -l option and
           specifying a file name is that -l surrounds library with lib and .a
           and searches several directories.
```


----------



## kneitzel (28. Aug 2019)

mihe7 hat gesagt.:


> Du kannst auch direkt die .a-Datei angeben. Von der man-Page
> 
> ```
> The only difference between using an -l option and
> ...


Ja, ist richtig. Interessant ist sogar, dass ich mich im Rahmen meiner Versuche dann auch selbst erinnert habe, denn als mein `gcc -o main -L. -lstuff main.c` ja auf einen Fehler gelaufen ist, habe ich ja auch alles noch einmal in "Einzelschritten" gemacht incl. einem `gcc -o main main.o libstuff.a`

Dass ich vorher aber Quatsch geschrieben hatte, ist mir da nicht aufgefallen. Daher auf jeden Fall Danke für die Korrektur und die klare Erläuterung.


----------



## ocsme (28. Aug 2019)

WOW 

Vielen Lieben Dank an euch  es hat geklappt und verstanden habe ich es nun auch so weit. 
Wieso diese ganzen Schalter und wozu die sind etc. damit befasse ich mich jetzt erst einmal nicht weiter. 
Hab ja mit dem C und C++ Stoff mehr als genug zu tun! 

Bei mir hat er auch immer gemekert wenn -lstuff nicht am ende steht! Dann kommt das hier:


> gcc -o main main.o -lstuff -L stuff
> /usr/bin/ld: -lstuff kann nicht gefunden werden
> collect2: error: ld returned 1 exit status



Da kann man froh sein so nette Hilfe zu haben  @kneitzel , @mihe7 und @httpdigest

LG


----------



## temi (28. Aug 2019)

ocsme hat gesagt.:


> aus dem Buch Grundkurs C von Jürgen Wolf



Nur kurz zur Info. Ich war vor Java auch im C/C++ Forum (nicht hier, ein anderes Forum) unterwegs und da haben die Bücher von diesem Autoren einen extrem üblen Ruf. Es wird dort dringend davon abgeraten mit diesen Büchern C/C++ lernen zu wollen.


----------



## Xyz1 (28. Aug 2019)

ocsme hat gesagt.:


> Nun dachte ich mir mhhh... das erinnert mich doch sehr stark an die ganzen Standard Klassen von Java also schauen wir mal


Math ist in Java partiell nativ implementiert, damit gewisse Funktionen schnell sind.

Das soll heißen es wird auf Betriebssystem Funktionen zurückgegriffen. 

Sin und cos sind zum Bleistift solche Kandidaten. Ist damit Deine Frage gelöst?


----------



## M.L. (28. Aug 2019)

> Es wird dort dringend davon abgeraten mit diesen Büchern C/C++ lernen zu wollen.


...wobei das aber auch mit anderen C/C++ - Resourcen passieren kann, ein (alter) Beispielthread von qt-forum.de : https://www.qtforum.de/viewtopic.php?f=1&t=11716  (ungefähr ab dem 6. Posting)


----------



## temi (28. Aug 2019)

M.L. hat gesagt.:


> wobei das aber auch mit anderen C/C++ - Resourcen passieren kann



Wohl wahr, aber bei JW sind sich offenbar alle sehr einig. Im von dir verlinkten Thread werden ja auch ein paar Bücher empfohlen. Ich selbst habe den "Breymann" und zwei Bücher von Scott Meyers, die ich alle empfehlen kann, wobei die von Scott Meyers eher für Fortgeschrittene und Profis sind.


----------



## ocsme (28. Aug 2019)

Danke werde ich mich mal zu schlau machen. Ich habe nur die zwei kleinen Bücher mir damals mal gekauft Grundkurs C und C++ von Jürgen Wolf und bin echt froh das ich erst mit Java angefangen habe. Ohne Grundwissen wäre ich damit überhaupt nicht klar gekommen  

Ich hab hier mal noch ein Beispiel vielleicht kann mir dabei jemand Helfen zu den Pointern in Verbindung mit Arrays.

```
int feld[2][3] = {{1,2,3},{4,5,6}};
int *px;
px = (int *) feld;
printf("%d\n",*px);
px = feld[0];
printf("%d\n",px[1]);
px = feld[1];
printf("%d\n",*px);
px = &feld[1][2];
printf("%d\n",px[0]);
```

feld ist eine Referenz und *px ein int Pointer. Diesem Pointer wird der Anfang des Arrays also dies Referenz mit gegeben. So weit so unklar  
In meinem Beispiel hier ist das Feld zweidimensional und ich kann mit (int *) feld nichts anfangen  was bedeutet das? ich dachte man könnte dann einen **px Pointer z. B. nutzen doch auch dabei kommen nur Warrnings 

Wenn nicht erstelle ich ein neues Thema denn hier gehört es ja eh nicht hin 

lg


----------



## temi (28. Aug 2019)

ocsme hat gesagt.:


> Diesem Pointer wird der Anfang des Arrays also dies Referenz mit gegeben.



Ist schon was her, aber bei C++ mit dem Begriff "Referenz" aufpassen, der hat nämlich eine eigene Bedeutung.


----------



## mihe7 (29. Aug 2019)

ocsme hat gesagt.:


> bin echt froh das ich erst mit Java angefangen habe. Ohne Grundwissen wäre ich damit überhaupt nicht klar gekommen


Die Voraussetzungen (und damit auch die Zielsetzungen) bei der Entwicklung von C waren ganz andere als bei Java. Dazwischen liegen etwa 20 Jahre und nicht umsonst hat C den Ruf eines besseren Assemblers. Bei C brauchst Du etwas mehr technisches Verständnis, Du musst mehr "in RAM" denken.



ocsme hat gesagt.:


> Ich hab hier mal noch ein Beispiel vielleicht kann mir dabei jemand Helfen zu den Pointern in Verbindung mit Arrays.



Nehmen wir mal an, Du hast folgende Bytes im Speicher ab Adresse 1000 stehen:

```
0 0 0 1 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 6
```

Die Bytes alleine sind erstmal nur Bytes. Ohne weitere Informationen, kannst Du dazu nichts sagen. 

Man könnte jetzt mitteilen: das sind ganzzahlige 32-Bit-Werte, wobei das höherwertige Byte zuerst kommt. Daraus kannst Du ableiten, dass an Adresse 1000 die Zahl 1, an Adresse 1004 die Zahl 2, an Adresse 1008 die Zahl 3 usw. gespeichert sind.

Das sind jetzt einfach mal sechs 32-Bit-Werte, die nacheinander im Speicher stehen. Das könnten also z. B. die Werte von sechs Variablen sein. Ich könnte Dir aber auch sagen, dass die Werte zusammengehören, und ein eindimensionales Array der Länge 6 bilden. Damit könntest Du sofort beantworten, was das fünfte Element dieses Arrays ist.

Genauso gut könnte es aber auch ein zweidimensionales Array sein, z. B. der Größe 2x3, bei dem der Spaß zeilenweise abgelegt ist (erst alle Elemente der ersten Zeile, dann alle Elemente der zweiten Zeile usw.) Dann kannst Du beantworten, was das erste Element der zweiten Zeile ist.

Kurz: es dreht sich eigentlich nur darum, wie die Daten interpretiert werden. In C sagst Du dem Compiler, wie er was zu interpretieren hat.

Die Folge oben könnte z. B. Deinem Array "feld" entsprechen (auf einem System, bei dem int 32-Bit-Werte sind und in Big Endian abgelegt werden). D. h. feld wäre einfach ein Bezeichner für die Adresse 1000. Durch die Angabe `int[2][3]` sagst Du dem Compiler, dass es 2x3 int-Werte sind, die zeilenweise nacheinander im Speicher liegen sollen. Dadurch weiß der Compiler auch, wie er `feld[0][1]` zu interpretieren hat.

Ein Pointer ist dagegen eine Variable, die eine Speicheradresse aufnimmt. Durch Dereferenzierung greifst Du auf den Speicher an eben dieser Adresse zu.

Dein px ist also die Variable, die eine Adresse speichert. Du kannst px verändern; damit änderst Du nur die gespeicherte Speicheradresse. Wenn Du auf die gespeicherte Adresse zugreifen willst, musst Du den Pointer dereferenzieren. Dafür gibt es den "dereference operator", auch "value at" genannt. Das ist das Sternchen vor dem Pointer. 

D. h. mit `px` ist die Adresse gemeint, die in px gespeichert ist, mit `*px` ist der Wert an der Adresse gemeint, die in px gespeichert ist ("value at px").

Mit Zeigern (also den gespeicherten Adressen) kannst Du in C rechnen (Pointer-Arithmetik). Der Clou ist, dass dabei die Größe des beim Pointer angegebenen Datentyps berücksichtigt wird. 

Nehmen wir an, in px wäre die 1000 (erstes Element des Arrays) gespeichert. Dann wäre px+1 nicht etwa 1001 sondern 1004 (wenn ein int 32-Bit breit ist)  


```
Var  Addr  Wert
feld 1000  1 <----+ *px
     1004  2      | *px+1
     1008  3      | *px+2
     ....         |
px   2000  1000  -+
```

Auch möglich ist es, den subscript-operator zu verwenden: `px[i]` ist nichts anderes als `*(px+i)`. Auf die in px gespeicherte Adresse wird also i-mal die Größe eines ints addiert und anschließend wird der so berechnete Zeiger dereferenziert.

Was sind nun `feld[0]` bzw. `feld[1]`? Da Du ein 2D-Array hast, handelt es sich um die Adressen der ersten Elemente der ersten bzw. zweiten Zeile.



ocsme hat gesagt.:


> ich dachte man könnte dann einen **px Pointer z. B. nutzen doch auch dabei kommen nur Warrnings


Nur Warnungen? Da könnte auch ein Fehler kommen. 

Wäre px eine Variable vom Typ `int **`, dann würdest Du dadurch zweimal dereferenzieren. Im Beispiel in den Code-Tags oben: ist px 1000. Damit ist *px der Wert an Adresse 1000, also die 1. Damit ist **px der Wert an Adresse 1... Da solltest Du bei der Ausführung ein segfault bekommen.

Zum Abschluss noch ein Hinweis: es ist gut möglich, dass das alles nicht 100 %-ig korrekt ist. Versteh es einfach als mentale Stütze.


----------



## ocsme (29. Aug 2019)

Danke 

Doch leider verstehe ich immer noch nicht das hier 
Also nehmen wir an ich habe ein Array dann Funktioniert die Zuweisung eines Pointers so:

```
int feld[2] = {1,2,3,4,5,6};
int *px;
px = feld;
```

ist das Array nun zweidimensional geht es komischerweise so:

```
int feld[2][3] = {{1,2,3},{4,5,6}};
int *px;
px = (int *) feld;
```

Da ich nicht verstehe wieso das an dieser Stelle so gemacht wird also px = (int *) <--- ??? feld
komme ich auch nicht drauf wie ich ein mehrdiminsionales Array als 3,4, etc Dimensionen Referenzieren könnte mit einem Pointer.

Vielleicht weiß da jemand eine Idee wenn nicht lasse ich es erst einmal.
Ich habe auch zu den Büchern noch einmal nach geschaut und die hier gefunden sind zwar schon etwas älter doch vielleicht immer noch zu gebrauchen?





						C. Das Grundlagen Buch : Amazon.de: Bücher
					

C. Das Grundlagen Buch | | ISBN: 9783815813812 | Kostenloser Versand für alle Bücher mit Versand und Verkauf duch Amazon.



					www.amazon.de
				









						C++, Das Grundlagenbuch, m. CD-ROM : Willms, Gerhard: Amazon.de: Bücher
					

C++, Das Grundlagenbuch, m. CD-ROM | Willms, Gerhard | ISBN: 9783815814376 | Kostenloser Versand für alle Bücher mit Versand und Verkauf duch Amazon.



					www.amazon.de
				




Bei C++ bin ich noch nicht da habe ich aber auch eine alte Version von Jürgen Wolf  Doch vielleicht steht da ja die Sachen verständlicher drin?


LG

Vielleicht versteht man so meine Frage etwas besser:

```
int feld[2] = {1,2,3,4,5,6};
int *px;
px = feld;

//äquivalent dazu wäre:
px = &feld[0]

//mehrdimensional:
int feld[2][3] = {{1,2,3},{4,5,6}};
int *px;
px = (int *) feld; //wie kommt man auf den Cast mit dem Int-Zeiger?

//äquivalent dazu wäre:
px = &feld[0][0]
```


----------



## kneitzel (29. Aug 2019)

Was passiert denn, wenn Du das weg lässt?

==> Du bekommst eine Warnung. Incompatible pointer types werden angemeckert.

Ein Array ist ein Zeiger auf das erste Element.
Also bei int feld[2] ist feld ein zeiger auf ein int.
Aber bei int feld[2][3] ist feld kein zeiger auf ein int sondern auf ein Array von int (auf ein int[3], denn davon hast Du ja zwei).

Diese Warnung soll besagen: Pass auf, was Du da machst. Denn wenn Du Dir die Erklärung von mihe anschaust:
px+1 geht, da es jetzt nur ein int ist, eben 4 Bytes weiter. Wenn Du aber als Typ ein int[3] hast, dann ist das nicht 4 sondern 12 Bytes lang. ==> Das "nächste" Element wäre also ggf. etwas anderes, als Du jetzt erhälst. Daher die Warnung.

==> Als Entwickler solltest Du Dir genau überlegen, was Du machst. In diesem Fall musst Du explizit sagen: Ich will das als einzelne int behandeln.


----------



## ocsme (29. Aug 2019)

Nochmals Danke.

Vielleicht hat ja noch jemand letzte Worte zu den Büchern da oben.
Derzeit habe ich mir das Buch von Kirsch, Schmitt besorgt Programmieren in C, Eine mathematikorientierte Einfuehrung. 

Mal schauen vielleicht wird dadurch mehr Klarheit geschaffen?

LG


----------



## thecain (29. Aug 2019)

Amazon.com: C Programming Language, 2nd Edition: 8601410794231: Brian W. Kernighan, Dennis M. Ritchie: Books
					

Amazon.com: C Programming Language, 2nd Edition: 8601410794231: Brian W. Kernighan, Dennis M. Ritchie: Books



					www.amazon.com
				




Damit habe ich C gelernt und fand es gut. Wobei ich sagen muss, dass ich jetzt nicht gross in die tiefe ging bzw. es auch nicht mehr anwende seit ein paar Jahren.


----------



## ocsme (29. Aug 2019)

Ja über das Buch bin ich auch gestolpert doch das PROBLEM dabei ist leider das ich nicht so gut Englisch kann 
Ich weiß in der Informatiker Szene kommt man ohne Englisch nicht zurecht! Doch dafür habe ich noch etwas Zeit hoffe ich  

LG


----------

