C lernen, Newbie sucht Rat

ice-breaker schrieb:
lol, in KEINER Sprache kann ich auf das Wissen von Datenstrukturen und Algorithmen verzichten, ein O(n^3)-Algorithmus ist nunmal in jeder Sprache langsam, egal ob Java, C# oder C.
Nein, es gibt Sprachen, in denen dir der Algorithmus egal sein kann: die deklarativen Sprachen. Oder hast du in SQL jemals einen expliziten Algorithmus dafür vorgegeben, wie du deine Daten aus den Tabellen erhalten willst? Nö, du sagst nur, dass du die Daten willst.

Was Datenstrukturen angeht ist C aber wirklich fieser als die meisten anderen Sprachen. Ich sag nur doppelt verkettete Listen und variable Arrays.

@palace4d: Das Web-Argument ist wirklich schlecht!. C ist nunmal die für Anfänger am schwersten zu lernende Sprache, warum sollte er eine Sprache lernen, die schwer zu erlernen ist und für sein Ziel ihm gar nichts bringt da er danach eine Web-Sprache lernen kann? Dann kann er auch direkt mit einer Websprache loslegen.
Jo, wenn eh Richtung Web will und voraussichtlich niemals für einen der Global Player mit den extremen High Performance - Anwendungen wie Facebook arbeiten wird, dann ist C absolut unnötig. Dann lieber eine der Sprachen, die keine Speicherverwaltung benötigen und die schwache Typisierung haben.
 
Daaron schrieb:
Nein, es gibt Sprachen, in denen dir der Algorithmus egal sein kann: die deklarativen Sprachen. Oder hast du in SQL jemals einen expliziten Algorithmus dafür vorgegeben, wie du deine Daten aus den Tabellen erhalten willst? Nö, du sagst nur, dass du die Daten willst.
Ok, das war unglücklich fprmuliert (Korintenkacker :-p): In allen Sprachen in denen man selbst Algorithmen schreibt, sind diese und die genutzten Datenstrukturen relevant.

Aber auch in SQL wirst du eine langsame Ausführung (Queryzeit) haben, wenn dein formulierter Befehl ineffizient ist. Insoweit würde ich den geschriebenen Algorithmus in SQL schon in die Algorithmik-Ecke stecken. Es macht je nach Datenbank, Tabellenstruktur ja schon einen Unterschied, ob ich Abfragen mit einem Join oder Dependent Subquery definiere. Und solch eine Definition ist schon ein Algorithmus (Lade Datan aus Tabelle A und verknüpfe diese mit Tabelle B anhand der Kritierien X=Y).
Ich hätte jetzt man an Prolog gedacht, bin mir da aber auch nicht ganz sicher, weil ich zu wenige Internas weiß, wie ein Prolog-Befehl ausgeführt wird und dadurch optimiert werden muss. Auf Grund des Cut-Befehls denke ich aber auch, dass hier wiederum auch vom Entwickler eine gewisse Algorithmik implementiert wird.

Daaron schrieb:
Was Datenstrukturen angeht ist C aber wirklich fieser als die meisten anderen Sprachen. Ich sag nur doppelt verkettete Listen und variable Arrays.
aber auch nur, weil man es selbst implementieren muss, wenn man keine fertige Library nutzt. Diese beiden Datenstrukturen sind ja per se nicht schwieriger in C nur weil es C ist, sondern nur weil sie dort noch nicht in der Standardbibliothek vorhanden sind.

Pilstrinker schrieb:
Und lass dich hier nicht verrückt machen: C ist relativ einfach zu lernen.
  • und aus dem Grund hat auch jede davon inspirierte Sprache die Pointerarithmetik übernommen... NICHT :lol:
  • und aus dem Grund hat auch jede davon inspirierte Sprache die manuelle Speicherverwaltung übernommen... NICHT :lol:
Lässt man diese beiden weg, ist C wirklich so leicht, wie jeder andere Sprache. Aber gerade das sind die beiden Punkten mit denen Anfänger am meisten Probleme haben. Und auch bei erfahrenen Entwicklern immernoch die größte Fehlerursache ist (Buffer Overflows, Speicherschutzverletzungen, Memory Leaks, you know ;)).
 
Zuletzt bearbeitet:
Das Zeug mag für einen erfahrenen Programmierer (in C) kein Akt sein, es ist aber für einen Neuling durchaus eine Herausforderung.
 
Ich will es mal so formulieren:
- C ist einfach zu erlernen
- C ist schwierig anzuwenden
C ist eine sehr minimalistische Sprache, sprich geringer Sprachumfang, deswegen einfach zu erlernen.
Weil C so minimalistisch ist, muss man ständig das Rad neu erfinden, was nicht nur zeitaufwändig ist, sondern auch schwierig zu debuggen ist, insbesondere was Speichermanagement angeht, da ein zufälliger (uninitialisierter) Wert auf den ersten Blick kaum von einer gültigen Speicheradresse zu unterscheiden ist.
Die Grundlagen von Speichermanagement (*/free/malloc) sind auf einer Seite erklärt, nur das Anwenden....

Und: Überall wo ein C++ Compiler verfügbar ist, sollte man dies gegenüber C bevorzugen - weil einem doch einiges abgenommen wird. Man muss nicht jeden Scheiß selber programmieren, weswegen trotz deutlich größerem Sprachumfang, im Einsatz C++ wieder einfacher macht als C - obwohl es ja eine Obermenge (*) ist. Auch wenn man von Templates gehört haben muss, std::vector/.. ist dann eben doch eine Nummer einfacher als da selber was zusammenzufrickeln. Oder auch Strings, ganz hässlich unter C. Was über Laufzeiten Algorithmen sollte man sich lieber aus einem Algobuch (**) holen und nicht durch den Zwang diese zu implementieren, obwohl man keine Ahnung davon hat. Davon abgesehen sind verkettete Listen in C++ schöner dank Templates... Insbesondere ist die Wahl eine einfache, weil in C++ das Motto ist: Alles kann, nichts muss. Man kann in C++ eben auch C programmieren, wenn einem danach ist.

Und C++ kann sein Gesicht äußerst wandeln, wenn man die passenden Bibliotheken verwendet. Bsp. Qt, wer das Fenster löscht, der löscht auch die darin enthaltenen Widgets (Textfelder, etc.), weil das ganze Baumartig aufgebaut ist. Da braucht einen Speichermanagement auch nicht zu interessieren. Oder Bsp. OpenCV: Man kann die Matrizen/Bilder einfach immer per Value kopieren, da cv::Mat im Prinzip ein großer Smartpointer ist und die eigentliche Matrix nicht kopiert wird. Rumhantieren mit Pointern überflüssig.

Ist das ein Plädoyer für C++? Nein. Sprachen wählt man anhand der Anwendung aus. Wer eine GUI Anwendung schreibt die hauptsächlich in der Event-Schleife rumhängt und nichts tut und somit Effizienz egal ist, der wird sich mit C++ vermutlich kein gefallen tun. Beim Erlernen ist die Wahl der Sprache unerheblich, solange der gewählten Sprache nicht grundlegende Konzepte fehlen (bspw. OOP bei C).

Achja, was Tutorials angeht: C++ Bücher sind nicht umsonst kaum unter 500 Seiten Umfang, eher 1000 Seiten, zu bekommen. Tutorials sind ganz nett um zu sehen, ob's einem gefällt. Der Weg an einem vernünftigen Buch lässt sich aber kaum umgehen - wenn man's ernst meint.

(*) Abgesehen von ein paar minimalen Unterschieden, die wenig relevant sind, wenn man nicht gerade ein ganz fürchterlichen K&R C Stil pflegt...
(**) Danach sollte man aber einen Praktiker fragen. So glaubt der Theoretiker doch tatsächlich, bspw. weil verkettete Listen und Vektoren beide beim linearen Zugriff die gleiche theoretische Laufzeit haben, das beide in etwa gleich schnell wären - ein absoluter Trugschluss. Selbst wenn Vektoren unterlegen scheinen in der Theorie - unter Umständen sind sie trotzdem schneller (bspw. einfügen an beliebiger(zufälliger) Stelle).
 
geisterfahrer schrieb:
Danach sollte man aber einen Praktiker fragen. So glaubt der Theoretiker doch tatsächlich, bspw. weil verkettete Listen und Vektoren beide beim linearen Zugriff die gleiche theoretische Laufzeit haben, das beide in etwa gleich schnell wären - ein absoluter Trugschluss. Selbst wenn Vektoren unterlegen scheinen in der Theorie - unter Umständen sind sie trotzdem schneller (bspw. einfügen an beliebiger(zufälliger) Stelle).

Tut mir leid, aber die Aussage ist von vorne und hinten falsch und möchte ich korrigieren, nicht dass sich jemand den Mist noch merkt. Der Theoretiker erkennt sowohl Unterschiede in der Effizienz, eventuell sogar genauer als der Praktiker.
Der Theoretiker nutzt dafür die Komplexitätstheorie und hat dadurch Angaben über die Laufzeit (rechte Tabelle) der einzelnen Operationen auf einer Datenstruktur. Der Theoretiker weiß also sehr genau, welche Operation auf einer Datenstrukturen welche Komplexität hat. Die Aussage über das Unwissen des Theoretikers sind also absolut falsch, der Theoretiker kann (was deine Aussage nicht beinhaltet) für deine letzte Aussage an Hand der Komplexität sogar sogar berechnen für welche Größe des Vectors bzw. verketteten Liste das Einfügen an beliebiger Stelle am effizientesten ist.
 
Ok, da muss ich genauer werden:
Verkettete Listen liegen, weil nach und nach Speicher angefordert verstreut im Speicher. Also n und n+1 liegen nicht hintereinander im Speicher. Einfache Modelle besagen: Um beim Vektor von n zu n+1 zu kommen, erhöht man die Speicheradresse um eins und schon ist man beim nächsten Element, also konstante Laufzeit O(1). Bei verketteten Liste folgt man eben dem next-Zeiger, also O(1). Die Praxis sieht aber ganz anders aus: Weil n und n+1 im Speicher hintereinanderliegen hat der Prozessor bereits n+1 in den L1-Cache geladen, so das bei der nächsten Iteration nicht langsam auf den Speicher zugegriffen werden muss. Bei einer verketteten Liste hingegen, wegen nicht zusammenhängenden Speicher, hat der Prozessor n+1 nicht im L1-Cache liegen, sondern muss aus dem Speicher geladen werden, was gut und gerne mal eben Faktor 100 langsamer sein kann. Deswegen ist lineares durchiterieren auf einer verketteten Liste viiiieeel lansgamer als auf einem Vektor, auch wenn einfache Tabellen, wie die von dir verlinkte sagen: Gleiche Laufzeit.
Und da kommt dann auch das Einfügen an beliebiger (zufälliger) Stelle ins Spiel: Wenn bei der verketteten Liste was eingefügt werden soll, muss sie da erstmal hiniterieren (extrem langsam), während ein Vektor da in konstanter Zeit hinspringt. Das Einfügen ist dann zwar langsamer, aber bis der Vorteil durch das schnelle hinnavigieren aufgebraucht ist, dauert es eine Weile, weil lange zusammenhängende Datenbereiche eine sehr schnelle Operation ist. Wer hingegen in die von dir verlinkte Tabelle schaut sieht: Oh, Linked list ist schneller, also nehm ich das. Stimmt eben in der angegebenen Tabelle nicht, man muss immer den Prozessor auf dem das ganze läuft mit betrachten.

http://www.baptiste-wicht.com/2012/11/cpp-benchmark-vector-vs-list/3/
Hier sieht man bspw. dass das zufällige Einfügen bei n=10000 wenn ein Element 32 Byte groß ist (Byte! nicht Bit, also bspw. eine Datenstruktur die acht ints/floats enthält, also gar nicht mal so winzig), der Vektor bedeutend schneller ist, was bei einfachen theoretischen Modellen eben nicht der Fall ist. Da das alles schon recht groß ist, sind die Anwendungsfälle für eine verkettete Liste bedeutend kleiner, als der Blick in die Tabelle mit den Komplexitäten vermuten lässt. Man muss eben beides Wissen, die Komplexitäten wie sie in einer Algorithmen-Grundlagenvorlesung vorgestellt werden und wie das ganze in der Praxis aussieht.
 
Diese Dinge lassen sich genauso berechnen, jeder Informatiker in einem Betriebssystemkurs (deine Theoretiker) hat schon berechnet, wieviele Speichermisses das Iterierieren eines Arrays unter den Vorraussetzungen x auftreten.

Dann hat der Theoretiker eben nachher die Kennzahl der Komplexität sowie der Speichermisses, und schwups kann der Theoretiker wieder annähernd bestimmen, was effizienter ist. Je nachdem sind eben Benchmarks nötig, wenn man die Komplexität und Speichermisses irgendwie vergleichen muss.

Ich wollte eben nur ausdrücken, dass die pauschale Aussage falsch ist, dass ein Theoretiker da auf Grund von Zahlen die falsche Entscheidung trifft. Er trifft nur die falsche, wenn er nicht genug Zahlen zum Entscheiden hat.
 
Zuletzt bearbeitet:
Haha Sry das ich nciht geantwortet habe... war leider nicht in der Lage online zu gehen. Also danke für eure Antworten habe mit euren hilfreichen links angefangen C zu lernen :D Danke liebes CB FORUM
 
Musicsniper schrieb:
[...]Ich wollte anfangen programmieren zu lernen[...]
Ich wollte hier nur noch mal anmerken, dass Programmieren zu lernen und die Sprache XY zu lernen nicht unbedingt das selbe Paar Schuhe ist!
 
Die Berechenbarkeit hat auf praktischen Systemen ihre Grenzen, da im Zusammenspiel mit anderen Anwendungen, die ebenfalls auf dem gleichen Computer laufen, das ganze System sich ziemlich stochastisch verhält (und damit "Er trifft nur die falsche, wenn er nicht genug Zahlen zum Entscheiden hat." immer zutrifft). Wie der Speicher, den man per new anfordert, verteilt ist, hängt ja auch davon ab, wie andere Applikationen Speicher anfordern und natürlich von der Speicherverwaltung selbst. Um das ganze halbwegs berechenbar zu machen, sind viel zu starke Annahmen zu machen, so dass das ganze mit der Realität nichts mehr zu tun hat. Mal davon abgesehen, ist es irrsinnig für eine praktische Umsetzung den Aufwand zu treiben, da ist Ausprobieren der präzisere und schnellere Weg.
Außerdem möchte noch ein Wort fett markieren in meinem alten Beitrag:
Danach sollte man aber einen Praktiker fragen
Nach der Theorie kommt eben die Praxis - und die kann sich eben leicht anders verhalten als erwartet. Es ging mir nicht um Theorie vs. Praxis, sondern darum, das man von beidem was gehört haben sollte. Davon abgesehen, fallen bei mir Betriebssystem-Vorlesungen nicht gerade in Kategorie Theorie, sondern läuft an einigen Unis eher unter dem Label praktische Informatik. Die Trennlinie zwischen Theorie und Praxis ist blöd zu ziehen, denn wenn der Theoretiker tägliche sich um Theorie kümmert, ist es für ihn tägliche Praxis ;-) Alles eine Sache des eigenen Standpunktes.
 
nullPtr schrieb:
Ich wollte hier nur noch mal anmerken, dass Programmieren zu lernen und die Sprache XY zu lernen nicht unbedingt das selbe Paar Schuhe ist!

Glaub, das ist der erste gute Hinweis hier...
Eigentlich sollte man direkt mit Programmablaufplänen und ner Pseudosprache anfangen, anstatt mit ner bestimmten Sprache und irgendwelchen Tutorials.
 
geisterfahrer schrieb:
Und C++ kann sein Gesicht äußerst wandeln, wenn man die passenden Bibliotheken verwendet. Bsp. Qt, wer das Fenster löscht, der löscht auch die darin enthaltenen Widgets (Textfelder, etc.), weil das ganze Baumartig aufgebaut ist. Da braucht einen Speichermanagement auch nicht zu interessieren. Oder Bsp. OpenCV: Man kann die Matrizen/Bilder einfach immer per Value kopieren, da cv::Mat im Prinzip ein großer Smartpointer ist und die eigentliche Matrix nicht kopiert wird. Rumhantieren mit Pointern überflüssig.

Ähnliches kannst du sogar mit der Standardbibliothek und std::shared_ptr / std::weak_ptr erreichen. Für explizite delete-Aufrufe gibt es in einem modernen C++-Programm eigentlich heute kaum noch eine Entschuldigung. Klar muß man trotzdem immer die Auswirkungen des Speicherhandlings im Auge behalten, selbst bei geschicktem Einsatz von shared-pointer-ähnlichen Konstrukten (oder Vermeidung des free stores wo immer möglich und stattdessen Ausweichen auf den Stack), aber wenn man's gescheit angeht, wird einem vieles schon vom Compiler abgenommen, so daß man C++ heute eigentlich so bequem wie C# programmieren kann.

Ansonsten stimme ich deinem Beitrag vollstens zu.
 
Zurück
Oben