Allein die Tatsache, dass du hier fragen musst, zeigt, dass es dir an Erfahrung mangelt. (Das ist NICHT böse gemeint, sondern nur eine Feststellung! Jeder hat mal klein angefangen, ich auch!)

Normalerweise ist es für Einsteiger ohne besagte Erfahrung sehr riskant, eigene Websites mit PHP zu entwickeln, weil sie sich überhaupt nicht über gängige Sicherheitslücken im Klaren sind, und unter Garantie auch in kleinere / einfachere Seiten, entsprechend ausnutzbare Fehler einbauen werden.

Von daher würde ich in deinem Falle für eine fertige Lösung plädieren.

Aaaaaber, WP ist mit gaaaaaaaanz weitem Abstand das CMS (was selbst eigentlich kein CMS sein will), welches am häufigsten gehackt wird. Das passiert in größerem Umfang alle paar Wochen oder spätestens Monate. Oft sind daran schlampig programmierte Plug-Ins schuld, oft aber auch wieder nicht, und es handelt sich wirklich um schwere Fehler in der Kern-Software.

Fazit: Du hast die Wahl zwischen Teufel und Beelzebub. :)

Egal wofür du dich entscheidest, du kannst sicher davon ausgehen, dass deine Website gehackt werden wird. Und das sogar - wenn du Pech hast - relativ zeitnah.

Bei WP oder einer anderen fertigen Lösung, kannst du die Schuld zwar teilweise auf andere schieben, aber das bringt dir die geklauten Nutzerdaten auch nicht zurück, bzw. musst du dann so oder so deine gesamte Website neu aufsetzen, um sicher zu stellen, dass keine Seiten trojanisiert wurden und munter Malware an die Besucher verteilen.

Was auch immer du tust, mache dir VORHER einen detaillierten Plan, was du tun wirst, wenn es soweit ist, dass deine Website gehackt wird:

  • Wie wirst du registrierte Nutzer informieren?
  • Haust du eine Art Pressemitteilung raus, die du als Textbausteine ja auch schon mal vorbereiten kannst?
  • Automatisierst du ein Rückspielen deiner Webpräsenz aus einem "sauberen" Backup?
  • ... Es gibt unzählige Fragen, über die du dir bei Zeiten Gedanken machen solltest.

Die einzige Möglichkeit, die Gefahr "gehackt" zu werden, auf ein erträgliches Maß zu senken, ist a) Profis für viel Geld anstellen oder b) selbst zum Profi werden. Aber da Punkt b) viele Jahre Zeit in Anspruch nehmen wird, bleibt dir nur Punkt a) oder du musst - wie oben erwähnt - mit einem erhöhten Risiko leben.

Sei dir auf jeden Fall der Gefahr bewusst, ob du etwas dagegen unternimmst, oder nicht. Wordpress installieren und ab dann "Augen zu" wird nicht funktionieren. Außerdem gibt es mit der neuen DSGVO empfindliche Strafen, auch für Blogbetreiber, wenn sich diese nicht entsprechend um die Sicherheit kümmern.

Ich weiß, das war jetzt nicht die Antwort, die du haben wolltest, aber du konntest hoffentlich etwas mitnehmen. :)

Schönen Tag noch, und trotzdem viel Erfolg mit deiner Website! :)
...zur Antwort

Vorweg: Du meinst keine Variablen-, sondern Literal-Suffixe. Zu Variablensuffixen gibt es auch viel zu erzählen, aber das ist ein anderes Thema ...

Literalsuffixe sind - gerade bei "float" - extrem wichtig!

Wenn du einen double-Literal nutzt, um eine float-Variable zu initialisieren oder einen neuen Wert zuzuweisen (oder umgekehrt), dann kommt es intern zu einem impliziten Casting, der in sehr vielen Fällen einige Bits Datenverlust mit sich führt.

Demonstration:
#include <ios> // boolalpha
#include <iostream> // cout, endl

int main(void) {
	using namespace ::std;

	cout << boolalpha;

	float a = 0.1234f;
	cout << "a: " << (a == 0.1234f) << endl;

	float b = 0.1234;
	cout << "b: " << (b == 0.1234) << endl;
}

Die Ausgabe lautet:

a: true
b: false

Und das nur, wegen dem ollen Suffix! Gemein, oder? Guck dir bitte ganz genau an, welche Literale über ein angehängtes "f" verfügen, und welche nicht!

Der obige Effekt ist übrigens einer der Gründe dafür, warum man Gleitpunktzahlen niemals direkt mit "==" auf Gleichheit prüfen sollte, aber das nur am Rande ...

Wie du siehst, ist dieses "sinnlose" Suffix doch manchmal gar nicht sooooooooo "sinnlos". :)

Fazit:

Wenn du innerhalb von Berechnungen / Algorithmen schwer auffindbare Fehler vermeiden willst, nutze immer die Suffixe (falls vorhanden), die zu deinen Variablentypen passen.

Das gilt insbesondere bei C++ noch viel stärker, als bei C, allein schon wegen der neuen universellen Initialisierung, der Überladung aus dem Beispiel von Isendrak oder noch extremer bei der Programmierung mit Templates. (Nichts dieser exklusiven C++ Features existiert bei C.)

Meine und die Antworten der anderen decken übrigens nicht alle Gründe FÜR die Literalsuffixe ab, es gibt dazu noch mehr zu wissen, aber ich will das hier jetzt nicht zu sehr in die Länge ziehen. (Habe unter der Antwort von PeterLustig1999 schon einen Roman verfasst ... sorry!) ><

Also dann ... schönen Tag noch! :)
...zur Antwort

Du verwendest grundsätzlich die Datentypen, die am besten geeignet sind. Und was genau "geeignet" bedeutet, hängt vom Einzelfall ab. :)

Als grobe Richtlinien kannst du folgende Hinweise beachten, die sich wohlgemerkt nicht ausschließlich auf die reinen Typen beziehen:

  • Keine Gleitkommatypen als Zählvariablen in Schleifen verwenden.
  • Niemals Gleitpunkttypen mit "==" vergleichen.
  • Variablen (egal welchen Typs) immer als "const" deklarieren, falls diese später nicht mehr geändert werden. Das gleiche gilt für Funktionsparameter. "Recycling" von Variablen vermeiden.
  • Ganzzahltypen immer so klein wie möglich wählen, aber so, dass der höchstmögliche Wert des vorliegenden Anwendungsfalls immer noch darin Platz findet.
  • Vorzeichenbehaftete Typen nur dann nutzen, wenn Vorzeichen auch benötigt werden.
  • Bei einer Division von Vorzeichenbehafteten Ganzzahlen nicht nur darauf prüfen, ob der Divisor Null ist, sondern auch, ob dieser den Kleinstmöglichen Wert darstellt. (Im Falle von "int" wäre das dann INT_MIN aus <limits.h>)
  • "char" oder "int" (auch als "unsigned") verwenden, wenn es auf Geschwindigkeit ankommt. (siehe dazu auch die [u]int_fastX_t Typdefinitionen aus <stdint.h>)
  • Einen Index mit kleinem Typen (z. B. "unsigned char") in eine Tabelle einem "dicken" Zeiger vorziehen, vor allem, wenn es sehr viele davon gibt. (z. B. Bitmaps mit Farbpalette)
  • Eventuell Festkomma-Aritmetik mit stinknormalen Integern in Betracht ziehen.
  • Falls nötig, Bibliotheken für sehr große Typen mit beliebiger Genauigkeit nutzen. (gibt es sowohl für Ganz- als auch Gleitpunktzahlen)
  • Unter Umständen mit Nibbles und Shifting / Maskierungen arbeiten, wenn es auf Speicherplatz ankommt. (Denke auch an Dinge wie BCD-Zahlen.)
  • Nicht vergessen, dass es auch (nicht Standard-C) Minifloats (oft 8 oder 16 Bit breit) und Gleitpunkttypen mit erweiterter Genauigkeit (meist 80 oder 128 Bit breit) gibt, je nach Compiler- und Plattform-Unterstützung.
  • Nutze für weitestgehende Plattformunabhängigkeit die Typdefinitionen aus <stdint.h>, falls du nicht auf ein eingeschränktes Subset von C angewiesen bist.
  • Verwende NIEMALS wchar_t von C++. (falls du nach C irgendwann mal auf C++ umsattelst)
  • Die Schlüsselwörter "auto", "volatile" und "register" nicht nutzen, es sei denn, du weißt genau, dass diese veraltet sind, was sie bedeuten, und kannst Nebeneffekte einschätzen.
  • Lerne die Eigenheiten und Unterschiede von / zwischen Zeigern und Arrays.
  • Beschäftige dich damit, was Speicherklassen sind, wie Paging funktioniert, was W^X oder ASLR heißt, was ein Program-Break ist und denke immer daran, dass es neben Stack und Heap auch noch allerhand "andere" Segmente gibt.
  • Informiere dich, was ptrdiff_t aus <stddef.h> mit void-Zeigern zu tun hat.
  • Setze das "restrict" Schlüsselwort sinnvoll ein, wenn du mit Puffern arbeitest.

... das sind aber alles keine feststehenden Naturgesetze, und u. U. kann / sollte / darf / muss man dagegen verstoßen. Mit der Zeit wirst du ein Gefühl dafür bekommen.

Viele der obigen Punkte werden ich jetzt vermutlich erschlagen, aber du musst diese (noch lange nicht vollständige!) Liste ja auch nicht an einem Abend durchackern. :)

Ich weiß, dass Code-Beispiele mehr als tausend Worte sagen, aber ich habe jetzt keine Zeit mehr, mir zu jedem der obigen Punkte ein Snippet aus den Fingern zu saugen. Falls noch Fragen offen sind, und ich nicht auf Kommentare reagieren sollte (habe in letzter Zeit viel zu tun) stell hier einfach direkt auf GF noch eine weitere Frage zu dem Thema ... irgendjemand wird dir schon Antworten. :)

Viel Spaß! :)
...zur Antwort

Aus diesem Grunde hat sich für Ein- und Ausgaben doch die Überladung der Shiftoperatoren eingebürgert:

#include <iostream> // cout, endl
#include <fstream> // ofstream

#include <ostream>

namespace gfx {

struct Point {
  int x;
  int y;
};

::std::ostream & operator << (::std::ostream & os, const Point & p) {
  return os << "Point { " << p.x << ", " << p.y << " }";
}

} // namespace

int main(void) {
	using namespace ::std;

	gfx::Point offset { 123, 456 };

	offset.x += 1111;
	offset.y += 5222;

	cout << offset << endl;

	ofstream ofs { "point.log" };
	ofs << offset << endl;
}

Das Programm gibt dir folgenden Text aus:

Point { 1234, 5678 }

Die selbe Ausgabe findet sich in der Datei "point.log". Der Grund, warum du also niemals direkt in ::std::cout schreiben solltest ist, weil du dich damit der Flexibilität beraubst, deine Ausgabe jederzeit beliebig umleiten zu können!

Der Vorteil dabei ist, dass du jede Form von Ausgabestrom nutzen kannst. Spezielle Ausgabefunktionen sollte man i. d. R. niemals schreiben, es sei denn, es gibt einen wirklich guten (!) Grund dafür. (z. B. eine Ausgabe in einem speziellen JSON- oder XML-Format, oder binäre Ausgabe)

Außerdem sollte die Ausgabe bei überladenem Shift-Operator so knapp wie möglich sein, und nicht mit einem Zeilentrenner abschließen, sodass der Aufrufer jederzeit selbst entscheiden kann, wie er die textuelle Repräsentation deiner speziellen Typen in seine eigene Ausgabe einbauen möchte.

Apropos "Repräsentation": Bei Python wird ordentlich zwischen str() und repr() unterschieden. So etwas muss man in C++ per Hand nachbauen, ist aber sehr angenehm, wenn man die Formatierung für interne Logs und Endbenutzer aufteilen möchte. Trotzdem empfiehlt sich natürlich immer ein "vernünftiger" Logging-Framework bei "richtigen" Projekten ... aber naja ...

Viel Spaß noch beim Programmieren! :)
...zur Antwort

Die Codeformatierung hier auf GF hat deinen Code so versaut, dass alle bisherigen Antwortenden deine Frage komplett missverstanden haben.

Ich wette, dein Code sollte eigentlich so aussehen:

char * s = "Hello, world!";

Und das ist kein gültiges C oder C++, sodass dir jeder vernünftige Compiler eine Warnung bzw. Fehlermeldung ausgeben wird! Soweit also kein Wunder! ;)

Der Grund dafür ist, dass "Hello, world!" ein konstanter Literal ist. Dieser wird vom Compiler in einem Speicherbereich abgelegt, der nicht schreibbar, bzw. nur lesbar ist. (Das ist zwar genau genommen Plattform- und Compilerabhängig, erspart einem aber viel Kopfzerbrechen, wenn man das im Hinterkopf behält.)

Die Adresse des String-Literals "Hello, World!" kann also nur einem Zeiger zugewiesen werden, der auf "unveränderliche" (aka "konstante") Speicherbereiche zeigt.

Deshalb ist nur (!) das hier richtig:

const char * s = "abc";

Falls du hingegen - was oft vorkommt - den String nach der Zuweisung auch noch bearbeiten / verändern willst, solltest du den konstanten Literal "Hello, world!" dazu nutzen, um ein Array mit automatischer Größe zu initialisieren:

char s[] = "abc";

Jetzt könntest du ganz legitim irgendwo in deinem Code ...

s[0] = 'd':
s[1] = 'e';
s[2] = 'f';

... schreiben, sodass dein String jetzt "def" enthält. Das geht, weil der Compiler so ein Array eben NICHT im Speicher für unveränderliche Werte ablegt.

Beachte bitte auch, dass das Array nicht die Größe 3, sondern die Größe 4 hat, da implizit ein abschließendes Nullzeichen '\0' an der vierten Position mit Index 3 (s[3]) steht.

Das ist einer der vielen gravierenden Unterschiede zwischen Zeigern und Array, die von Einsteigern gerne mal durcheinander gebracht werden. Du bist also nicht der einzige, mit diesem Problem. :)

Beachte bitte auch, dass "const char *" ein "Zeiger auf ein konstantes Zeichen" und kein "Zeiger auf ein Zeichen", geschweige denn ein "konstanter Zeiger auf ein Zeichen" oder ein "konstanter Zeiger auf ein konstantes Zeichen" ist! ;)

Wenn du jetzt verwirrt bist, hier ein paar Beispiele:

char * s; // Zeiger auf Zeichen: beide veränderbar
const char * s; // Zeiger auf konst. Zeichen: nur Zeiger veränderbar
char * const s; // konst. Zeiger auf Zeichen: nur Zeichen veränderbar
const char * const s; konst. Zeiger auf konst. Zeichen: nichts änderbar

Ein guter Trick dabei ist, die Definition rückwärts (!) zu lesen. Die vierte Zeile vom vorherigen Beispiel würdest du dann lesen als: "s ist ein konstanter Zeiger auf eine char-Konstante".

Merk dir diese Eselsbrücke, denn sie wird dir die Arbeit oft stark erleichtern! (Bei Arrays und Funktionszeigern funktioniert das nicht ganz so einfach, aber das würde jetzt den Rahmen sprengen, also lassen wird das jetzt mal unter den Tisch fallen.)

Falls dir das jetzt alles noch nicht schlüssig erscheint, keine Sorge! Lern einfach weiter, und irgendwann macht es dann schon "Klick".

Fazit: Strings, die du nicht mehr verändern willst, als konstante Zeiger deklarieren, ansonsten als Array. So einfach ist das! ;)

Schönen Tag noch! :)

PS: Die obigen Aussagen beziehen sich größtenteils auf den reinen C-Teil von C++. Wenn du irgendwann mal fortgeschritten bist, solltest du - wie andere schon geschrieben haben - für Strings die entsprechende Klasse aus der STL nutzen, also ::std::string aus <string>.

Trotzdem ist es natürlich enorm wichtig, erst mal die Basics zu kennen und zu verstehen, wozu natürlich auch die Unterschiede zwischen Zeigern und Arrays zählen. :)

...zur Antwort

Alle genannten Sprachen verfügen über exzellent ausgearbeitete Features und mächtige (Standard-) Bibliotheken, aber für µC wäre es auch heutzutage ratsam, sich mit C und Assembler auseinander zu setzen.

Assembler allein schon deshalb, weil du dein Kompilat damit disassemblieren, und die Funktionsweise prüfen kannst. Gerade bei Embedded-Sachen finden sich dort z. B. auch gerne mal richtige Compiler-Fehler wider, bei denen man sich ohne Assemblerkenntnisse totgesucht hätte.

Ansonsten ist C sehr schlank und mit vernünftigen Herangehensweisen auch sehr sicher und effizient zu programmieren. Auf großen Rechnern bevorzuge ich C++, aber gerade im Embedded-Bereich fehlen dir u. U. sehr sehr sehr viele Features, die du von C++ her kennst (keine Exceptions, keine dynamische Speicherreservierung, es fehlt ein großer Teil der Standardbibliothek, usw.).

C++ kannst du nutzen, wenn du dicke fette Mikrocontroller nutzt, aber vor allem die kleineren und günstigeren von TI, Atmel, ehemals Microchip, usw. usf. sind oft viel zu schwachbrüstig, um darauf "richtigen" C++ Code ausführen zu können.

Wenn aber überhaupt erst mal ein C++ Compiler für deine Plattform existiert, und du dich aber mit einer sehr kleinen Teilmenge der gängigen C++ Features zufrieden geben kannst, können gerade moderne C++ Compiler wunderbar effizienten Code erzeugen, der deutlich effizienter ist und weniger Speicher benötigt, als vergleichbarer C-Code. (Dafür brauchst du aber nach Möglichkeit MINDESTENS einen C++11 Compiler, IDEAL wäre aber ein C++17 Compiler, evtl. bereits teilweise mit features von C++20.)

Alle anderen genannten Sprachen (Python, C# und Java) sind für eingebettete Systeme nicht geeignet und Spezialfälle für C# oder Java konnten sich in den letzten Jahrzehnten nicht durchsetzen und dümpeln seitdem vor sich hin, bzw. sind schon relativ frühzeitig ausgestorben.

Allerdings ist Python quasi DIE Standardsprache um einige gängige Debugger zu steuern bzw. zu automatisieren, und zusammen mit einem ISP kannst du z. B. den GDB damit in die mächtigste "Debugmaschine" verwandeln, die man sich vorstellen kann.

Für Java und C# sehe ich hier keine Anwendungsmöglichkeiten, aber das ist auch nicht weiter schlimm, da diese Sprachen für andere Dinge konzipiert wurden.

Falls du etwas zu viel Zeit und ausreichend Lust hast, solltest du dir diese beiden aber ebenfalls mal ansehen, da diese eine extrem große Standardbibliothek mitbringen, die unvergleichbar mächtiger ist, als das, was standardmäßig mit C oder gar C++ kommt. Allein Python kommt hier in die Nähe ... aber wie gesagt, vergleichen kann man diese ganzen Sprachen eigentlich nicht, da sie einfach zu unterschiedlich sind.

Fazit: Wenn du Embeddedkram machen willst, dann lerne auf jeden Fall C! Da wirst du nicht drum herum kommen, egal für welchen Mikrocontroller du dich entscheidest. C ist in dem Bereich einfach die ungeschlagene Nummer Eins.

Falls es sich um einen relativ mächtigen µC handelt, guck dir an, ob sich C++ sinnvoll einsetzen lässt. Und damit du überhaupt weißt, was intern passiert, und nicht bei jedem Fehler im Netz fragen musst, lerne auf jeden Fall auch die Architektur und den Assembler-Dialekt deiner Plattform.

(Die Programmierung von eingebetteten Systemen funktioniert etwas anders, als Desktop-Programme. Falls dein Englisch ausreicht, besorge dir mal das Buch "Making Embedded Systems" vom O'Reilly Verlag ... aber lerne vorher erst mal richtig C, damit du überhaupt weißt, worum es in dem Buch geht.)

Und wenn du dich irgendwann mal eingefummelt hast, könntest du Python nebenbei lernen, um deine Entwicklungswerkzeuge zu automatisieren, aber das ist jetzt kein Primärziel.

C# und Java brauchst du dabei vorläufig erst mal nicht, zumindest nicht in deinem Falle für das ganze Embedded-Zeug. Trotzdem kannst / solltest du die auch mal irgendwann lernen, weil dich Kenntnisse darin allgemein weiterbringen werden und es einfach praktisch ist, gewisse Anforderungen in Java / C# zu erschlagen, für die diese Sprachen einfach das beste Werkzeug darstellen.

Viel Spaß! :)
...zur Antwort

Ein neues Fenster kannst du mit der Kommandozeilen-Option "--new-window" erzeugen, aber intern startet Chrome viele Prozesse, die alle untereinander kommunizieren, auch wenn du mehrere Chrome-Fenster offen hast.

Ein Trennen ist zwar möglich, aber zu aufwändig, um es dir hier zu erklären.

Nachtrag: Es gibt noch den "--single-process" Kommandozeilen-Switch, aber das hat auch seine Tücken. :)

...zur Antwort
Wie viel Erfahrung um mit Programmieren Geld zu verdienen?

Hallo zusammen,

Also erstmal was zu mir. Ich studiere Informatik und habe viel Spaß am Programmieren gefunden. An der Uni haben wir Java Programmierung in 2 Semestern. Es ist sogar so, dass ich seit gut einem Monat viel mehr Zeit in dieses Fach investiere, als eigentlich für das Modul nötig. Da ich im "Selbststudium vor Beginn des eigentlichen Studiums, ehr gescheitert bin, mir Java selbst beizubringen, hatte ich mir vorgenommen ( und auch eingehalten) mindestens 1h täglich zu programmieren sobald das Studium anfängt, so als "gute Angewohnheit". Da ich, beim Versuch es mir selbst beizubringen oft viel zu lange nichts dazwischen gemacht habe. Das ich das ganze auch so durchgezogen habe, verdank ich irgendwo unseren Wöchentlichen Abgaben. Unserem Kurs bin ich auch in etwa 2 Wochen im voraus, da unser Prof. die kompletten Vorlesungen als Video online hochlädt (Wir können also das ganze Semester theoretisch vorarbeiten, da von letztem Jahr alle Vorlesungen für uns online sichtbar sind) Nun, das ist auch eigentlich nicht das Thema, aber hat mich zu folgenden Fragen geführt.

  1. Ist man nach dem was man von der Uni lernt in Punkto Programmierung ( Bei uns Modul in 2 Semestern ) in der Lage auch Geld damit Privat zu verdienen? Wie weit qualifiziert das? Bei uns mit der Sprache Java.

  2. Wie viel Erfahrung bzw. Zeit braucht man beim Programmieren um sich etwas dazu zuverdienen? Also sagen wir mal ich bleib bei 1-2h täglich die ich investiere, hin und wieder auch mal mehr. Was sagt eure Erfahrung? Wie lang bräuchte ich dann ca. um gut, besser oder wirklich gut zu werden? Ich weiß sowas ist schwer zu sagen. Eine kleine Einschätzung wär mich schon genug.

Theoretisch wenn ich mal nach dem zweiten Semester anfange nebenbei für Leute was zu programmieren würde ich ich mich als Student schon über 100 Euro mehr im Monat freuen. Je nach dem wie sich mein "Spaß" hier entwickelt überlege ich sogar auf einen Studiengang zu wechseln der seinen Fokus auf programmieren legt. Jedenfalls ist es das erste mal, seit dem ich Klavier spielen gelernt habe, dass mir etwas wirklich Spaß macht und ich sozusagen freiwillig jeden Tag etwas Zeit investiere ohne das Gefühl zu haben es wäre "Doof".

3. Gibt es vielleicht sogar Selbstständige Programmierer unter euch? Was sagt ihr, wie viel Aufwand in lernen man stecken muss bevor man vielleicht davon Leben kann? Seinen ersten Euro verdienen kann? Ist zwar eine sehr pauschale Frage, aber ich erwarte auch keine Präzise Antwort! :-)

Gruß Capcord

...zur Frage

Momentan habe ich keine Zeit für ellenlange Ausführungen, deshalb halte dich erst mal an die Antwort von "regex9", welche die wichtigsten Punkte sehr gut zusammen fasst. Von mir jetzt nur so viel:

An die Uni geht man eigentlich nicht zum Programmieren lernen, sondern eher um sich Theorie, ein solides Gesamtbild und v. a. ein wenig Mathematik anzueignen.

M. E. n. haben Bachelor-Studenten starke Defizite im Punkto "Programmieren", wenn sie sich nicht schon vorher mit spätestens 12 Jahren damit befasst haben. Und die nötige Erfahrung um das alles auszugleichen, sammelst du nicht mal so nebenbei während des Studiums ... zu einem kleinen Teil natürlich schon, aber sei dir sicher, dass NACH deinem Studium noch mindesten 90% von dem kommen werden, was du bisher zum Thema "Programmieren" gelernt hast. :)

Aber wenn dir das so großen Spaß macht, solltest du natürlich dran bleiben, und immer schön experimentieren! Vernachlässige dabei aber andere Kurse nicht! Vor allem Mathe!!!

Zum "Programmieren" gehört weit mehr, als Code in eine IDE einzugeben, und auf "Build" zu klicken.

Wie lang bräuchte ich dann ca. um gut, besser oder wirklich gut zu werden?

Das hängt von der Person, der Sprache und vielen weiteren Faktoren ab. Ganz grob geraten würde ich sagen: Bei Java ein Jahr um einen ganz akzeptablen Überblick zu erhalten, bei täglich mehreren Stunden Übung, Lesen und Lernen.

"besser" ist Definitionssache, aber "wirklich gut" dauert mit Sicherheit 15 bis 20 Jahre. Ich habe früher auch immer gedacht, dass ich "gut" bin, aber wenn ich mir meinen alten Code angesehen habe, dachte ich mir immer, dass ich damals wohl doch nicht soooo gut war, es dafür aber heute bin. Und das wiederholte sich die Jahre immer und immer wieder. :)

Erst nach so 18 Jahren fing es an, dass ich mir meinen alten Code angesehen habe, und mir Dacht: "Wow, das ist ja wirklich schick!". Seit dem 22sten Jahr kommt das noch wesentlich häufiger vor, und ich würde sagen, dass ist ein Indiz dafür "gut" zu sein. Trotzdem lerne ich ständig weiter und es kommt immer mehr hinzu. Ein Ende ist noch lange nicht in Sicht, und wird realistisch betrachtet wohl auch nie erreicht werden.

Aber wie gesagt, das hängt von jedem selbst ab. Guck dir einfach alle paar Monate oder Jahre deinen eigenen alten Code an, und wenn dir dabei schlecht oder schwindelig wird, dann heißt das, dass du "Anfänger" bist. :)

Wenn du dir nur dabei denkst: "Na hoffentlich sieht den Code keiner mehr außer mir. Heute würde ich das auf jeden Fall besser machen.", dann bist du fortgeschritten. :)

Und wenn du denkst: "Na, das ist ja elegant gelöst. Man, sieht der Code gut aus.", dann könnte es sein, dass du schon zu den "Besseren" gehörst. :)

Ach und ... bleib auf dem Laufenden! Dazu musst du ständig viel lesen. Momentan verbringe ich täglich 3 bis 5 Stunden mit dem Lesen von aktueller Fachliteratur und anschließendem Experimentieren.

Momentan lese ich "Clean C++", "Modern C++ Programming Cookbook" und "C++ STL Cookbook" parallel, und werde damit wohl in zwei Wochen durch sein. Ich lese auch oft uralte Bücher, die ich schon drei mal gelesen habe, einfach weil man im Laufe der Zeit viel vergisst und auffrischen muss.

Wie du siehst, liegt mein Fokus momentan nicht auf Java, aber trotzdem habe ich vor kurzem auch etwas dünnere Büchlein, die Neuerungen Java 8 und 9 betreffend, gelesen.

Du solltest auch über den Tellerrand schauen, und auch als Java Programmierer andere Sprachen lernen. (Groovy, Scala, Clojure und Kotlin bieten sich zwar an, aber auch Scheme, Haskell, Erlang, D, Rust, usw. bringen neue Einblicke!)

Trotzdem bleib erst mal bei Java, lerne die Sprache richtig und hab Spaß dabei!

Übrigens würde ich dir SEHR die aktuelle Ausgabe der beiden Teile von "Java ist auch eine Insel" ans Herz legen. Dieses Buch ist exzellent und deckt so ziemlich alle Themenbereiche ab, die in deinen Univorlesungen unter den Tisch fallen. FALLS du wirklich gut in Java werden willst, kommst du um die Insel vermutlich nicht drum herum. Wenn ich du wäre, würde ich JETZT sofort auf Amazon eine Bestellung auf geben. (Nein, keine Angst, ich werde nicht vom Rheinwerk-Verlag bezahlt! Aber die Insel ist im Deutschsprachigen Raum sicherlich das beste Javabuch im Bezug auf Preis / Leistung / Umfang / Didaktik und Aktualität!)

https://www.amazon.de/Java-auch-eine-Insel-Java-Entwickler/dp/3836258692/ref=sr_1_1?ie=UTF8&qid=1512526422&sr=8-1

... und evtl. auch etwas später noch dazu:

https://www.amazon.de/Java-SE-9-Standard-Bibliothek-Handbuch-Entwickler/dp/3836258749/ref=pd_bxgy_14_2?_encoding=UTF8&psc=1&refRID=ZWR8MHABA3NACKRC9TB6

Naja, egal ... ich muss jetzt weg. Schönen Tag noch! :)

Disclaimer: Hab keine Zeit mehr zum Korrekturlesen. Etwaige Tippfehler schiebe ich hiermit offiziell auf die schlechte Verbindung meiner Funktastatur! ;)

...zur Antwort
Neben Stack und Heap gibt es auch noch die Bss- und Data-Segmente (und weitere, die hier keine Rolle spielen)!

Deshalb kannst du ein riiieeesiges, dickes, fettes Array auch "halb-statisch" in deiner Übersetzungseinheit (in diesem Falle der Quelltext-Datei) deklarieren und zum initialisieren memset() nutzen.

Falls du das nicht verstehst, keine Angst! Guck dir einfach folgendes Beispiel an:

#include <stdio.h> /* printf */
#include <stdlib.h> /* EXIT_SUCCESS */
#include <string.h> /* memset */

#define WDT 3000
#define HGT 3000

static char arr[HGT][WDT];

int main(void) {
memset(arr, 'X', HGT * WDT);

printf("Value test: '%c'\n", arr[123][456]);

return EXIT_SUCCESS;
}

Dabei wird das Kompilat auch nicht unnötig aufgeblasen, und die resultierende Datei ist - zumindest bei mir - rund 8KB groß ... also kein Unterschied zu "Hello World". :)

Das liegt daran, dass dein Array im Bss-Segment landet, und zur Laufzeit - noch vor main() - automatisch alloziert wird.

Wenn du die Definition zu ...

static char arr[HGT][WDT] = { {'X'} };

... änderst, dann landet das Array im Datensegment, wobei das Array nicht mehr vor main() alloziert, sondern aus dem Kompilat direkt in den Speicher gemappt wird. Dementsprechend ist bei mir das ausführbare Programm auch nicht mehr nur 8 KB, sondern über 9 MB groß.

Aber da du sowieso das gesamte Array mithilfe von memset() mit 'X'en füllen willst, und nicht wie in der Zeile oben nur das erste Element, wäre diese Variante Blödsinn, und das Bss-Segment - so wie im Miniprogrämmchen weiter oben - vorzuziehen.

So große statische Arrays im Datensegment eignen sich eigentlich nur für vorberechnete Tabellen, deren Berechnung zur Laufzeit (oder bei C++ auch zur Kompilierzeit) zu aufwändig wäre.

Das "static" Schlüsselwort vor der Definition sorgt übrigens dafür, dass das Array nicht global in anderen Quelltextdateien sichtbar ist und somit u. a. Namenskonflikte vermieden werden können.

Variante 2 mit "echtem" dynamischem Speicher:

Wenn du unbedingt malloc() verwenden willst, geht das z. B. so:

#include <stdio.h> /* printf */
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS, size_t */
#include <string.h> /* memset */

#define WDT 3000
#define HGT 3000

int main(void) {
int result = EXIT_FAILURE;

const size_t size = HGT * WDT;
char * ptr = malloc(size);

char c = '\0';

if (ptr) {
memset(ptr, 'X', size);

c = *(ptr + 123 * WDT + 456);
printf("Value test: '%c'\n", c);

free(ptr);
result = EXIT_SUCCESS;
}

return result;
}

Beachte hierbei, dass es sich um einen Zeiger und nicht mehr um ein zwei dimensionales Array handelt. Dabei gibt es tatsächlich wichtige Unterschiede, aber die kannst du jetzt erst mal ignorieren (lernst du später irgendwann sowieso).

Der Speicherbereich wird erst initialisiert, nachdem sichergestellt wurde, dass die Speicherallokation erfolgreich verlief, d. h. der Zeiger nicht NULL ist. Am Ende wird der Speicher wieder frei gegeben (was man unbedingt IMMER tun sollte).

Dazwischen wird auf den Speicherbereich anders zugegriffen, als auf ein 2D-Array, aber wenn du es dir genau ansiehst, wirst du verstehen, wie es funktioniert. Wenn nicht, mach dir keinen Kopf! Das wirst du in den nächsten Wochen vermutlich sowieso lernen. :)

Auch bei dieser Version ist die kompilierte Programmdatei natürlich wieder nur knapp 8KB groß, da der Speicher ja in keinem Segment, sondern zur Laufzeit auf dem Heap reserviert wird.

So, und zum Schluss noch ein Hinweis: Du kannst dem Compiler auch sagen, dass er (bzw. die Programmdatei zur Laufzeit) besonders viel Speicher für den Stack reservieren soll. Damit ist es dann auch möglich, dein großes 2D-Array auf den Stack zu packen, ohne dass dein Programm abstürzt.

Allerdings ist diese Methode m. M. n. sehr unsauber, und deshalb schreibe ich jetzt nicht, wie das geht. Wer es dennoch wissen will, der sollte die Dokumentation seines Compilers konsultieren. :)

Fazit: Du kannst Speicher also auf dem Stack, auf dem Heap oder in verschiedenen Segmenten (hier Data und Bss) reservieren. All diese Varianten haben große Vor- und auch große Nachteile. Wann du welche Methode nutzen solltest, wirst du mit der Zeit automatisch lernen, also mach dir keine Gedanken, wenn das Ganze im Moment noch undurchsichtig wirkt.

Also dann ... viel Spaß! :)
...zur Antwort
Kann man grundsätzlich nicht sagen.

Kommt drauf an, welche Art von Daten vorliegen!

Im besten Falle wird das Ergebnis kleiner als 1MB, im schlechtesten Falle größer als deine 24 GB Ausgangsdaten.

Fazit: Die Frage ist unmöglich zu beantworten ohne deine Dateien genau zu kennen. :)

...zur Antwort
Viren im eigentlichen Sinne gibt es tatsächlich seit Windows Vista nicht mehr! :)

Es gibt allerdings eine ganze Reihe weiterer Kategorien an Schadsoftware, allen voran Trojaner in allen Geschmacksrichtungen.

Kaspersky kann allerdings nur weniger als die Hälfte aller aktuell im Umlauf befindlichen Schadprogramme entdecken, teilweise auch nur ein Viertel.

Kaspersky nennt eines seiner Produkte "Total Security", was schon an Irreführung grenzt.

Antivirensoftware funktioniert größtenteils nicht und wenn dir das klar ist, kein Problem. Aber denke bitte nicht, dass du zu 99% vor allen möglichen "Bedrohungen" geschützt bist. Geld ausgeben lohnt sich dafür sowieso nicht.

Lass dich nicht veräppeln und dir das Geld aus der Tasche ziehen! :)

Wenn du dich wirklich effektiv schützen willst, geht das mit Kaspersky nicht. Nimm lieber einen AdBlocker und nutze eine VM oder Sandbox. Das ist a) kostenlos, und schützt dich b) tatsächlich zu 99,9% auch vor aktueller und unbekannter Schadsoftware.

Nochmal zur Erinnerung: Bei Kaspersky liegt die Trefferquote zwischen 25% und 45%!

Naja, schönen Tag noch! :)

PS: Ähnliche Fragen kommen hier fast täglich, und ich habe schon X mal darauf geantwortet. Für technische Details, lies dir folgende Frage, und meine Antwort darunter durch:

https://www.gutefrage.net/frage/wie-kann-das-sein-antivirus-erkennt-selbstgemachten-keylogger-nicht

Oder meine Antwort hier:

https://www.gutefrage.net/frage/was-haltet-ihr-von-der-behauptung-deinstallieren-sie-ihren-virenschutz-sofort-denn-er-ist-gefaehrlich-die-ich-auf-chipde-gefunden-hab

PPS: Viele Menschen lesen die Antiviren-Tests in den gängigen Computerzeitschriften und denken, sie wüssten bescheid.

Ich möchte zum Schluss nochmal darauf hinweisen, dass ich seit Jahrzehnten beruflich Schadsoftware analysiere und Software auf Sicherheitslücken untersuche.

Ich weiß auch bis ins Detail, wie Antivirensoftware arbeitet und dass es trivial einfach ist, eine Erkennung leicht umgehen zu können (Stichwort "Heuristik", die noch nie funktioniert hat, und auch nie funktionieren wird).

Ich schreibe das, weil ich mir anschließende Diskussionen mit sog. "Power Usern" ersparen will, die ihre Lieblings-Antiviren-Software verteidigen, weil sie auf Werbung oder Artikel in der Computer-BILD rein gefallen sind.

...zur Antwort

Eigentlich steht alles schon im Link von regex9's Antwort, aber es ist im einfachsten, mehrdimensionale Arrays als Pointer auf das erste Element zu übergeben, und danach die Größe jeder einzelnen Dimension.

Vorweg: Das, was du vor hast geht nicht, da es keine Refenzen auf mehrdimensionale Arrays mit mindestens einer unbekannten Dimension geben kann. Für Referenzen müssen alle Größen bekannt sein. Ansonsten gehen natürlich Referenzen auf Zeiger, oder Referenzen auf Zeiger auf Zeiger auf Zeiger auf Zeiger usw., aber das wäre etwas sinnlos. Dazu später mehr ...

Wenn es wirklich eine Referenz sein muss, dann am besten nur, wenn dem Compiler im aktuellen Gültigkeitsbereich auch die Dimensionsgrößen bekannt sind. (Der Punkt ist enorm wichtig!)

Das geht am übersichtlichsten mit Templates, bläht aber den Code etwas auf, wenn du eine Million unterschiedlicher Größenkombinationen hast.

Beide Möglichkeiten sind in folgendem Code zusammen gefasst (Beachte dabei bitte, WIE auf die einzelnen Arrayelemente innerhalb der jeweils innerersten Schleife zugegriffen wird und wie die Argumente an die beiden Funktionen am Ende von Main übergeben werden!):

#include <iostream> // cout, endl
#include <string>

#include <cstdlib> // size_t

void dump_table(
const ::std::string * const table,
const size_t rows, const size_t cols
) {
using namespace ::std; // cout, endl

cout << "PTR";
cout << "[" << rows << "][" << cols << "]" << endl;

for (size_t row = 0; row < rows; ++row) {
cout << '#' << row << ':';

for (size_t col = 0; col < cols; ++col) {
cout << ' ' << *(table + row * rows + col);
}

cout << endl;
}
}

template <size_t ROWS, size_t COLS>
void dump_table(
const ::std::string (& table)[ROWS][COLS]
) {
using namespace ::std; // cout, endl

cout << "REF";
cout << "[" << ROWS << "][" << COLS << "]" << endl;

for (size_t row = 0; row < ROWS; ++row) {
cout << '#' << row << ':';

for (size_t col = 0; col < COLS; ++col) {
cout << ' ' << table[row][col];
}

cout << endl;
}
}

int main(void) {
constexpr size_t rows = 3;
constexpr size_t cols = 4;

const ::std::string table [rows][cols] {
{"a", "b", "c", "d"},
{"e", "f", "g", "h"},
{"i", "j", "k", "l"}
};

dump_table(table); // ref
dump_table(&table[0][0], rows, cols); // ptr
}

Das ist nicht das, was du gefragt hast, aber wenn du WIRKLICH ein zweidimensionales Array mit unbekannter Größe mindestens einer Dimension per Referenz übergeben willst / musst / sollst, dann geht das nicht. Du benötigst für alle Dimensionen eine Größeninformation (zur Kompilierzeit!).

Ich weiß zwar nicht, warum man so ein Knickei haben wollen würde, aber so würde es als Pointer-Variante mit unbekannter erster Dimension aussehen:

template <size_t COLS>
void dump_table(
const ::std::string (* const table)[COLS],
const size_t rows
) {
using namespace ::std; // cout, endl

cout << "UGLY";
cout << "[" << rows << "][" << COLS << "]" << endl;

for (size_t row = 0; row < rows; ++row) {
cout << '#' << row << ':';

for (size_t col = 0; col < COLS; ++col) {
cout << ' ' << table[row][col];
}

cout << endl;
}
}

Der Aufruf in main() sähe dann - an den Code aus dem ersten Code-Schnipsel angelehnt - so aus:

dump_table(table, rows); // ugly

Also quasi eine unschöne Mischung aus den ersten beiden vernünftigen Varianten. Würde ich so aber nicht machen wollen.

Merk dir einfach:

Du KANNST keine Referenz auf ein mehrdimensionales Array mit mindestens einer unbekannten Dimension definieren! Sind hingegen alle Dimensionsgrößen bekannt, geht das komfortabel mit einem Template oder zur Not mit magischen Werten:

void dump_table(const ::std::string (& table)[3][4]);

Ein Template ist aber ordentlicher, sicherer und zuverlässiger, vor allem, wenn der Code später mal geändert wird.

Fazit: So wie in dem Beispiel aus deiner Frage, geht es nicht als Referenz, da die Größe der ersten Dimension unbekannt ist!

Schönen Tag noch! :)
...zur Antwort

Deine Frage ist gar nicht so leicht zu beantworten. Das liegt aber weniger am gestellten Problem selbst, sondern weil ich nicht einschätzen kann, auf welchem Lernstand du dich befindest, und welche Features der Programmiersprache für dich nachvollziehbar sind. :)

Außerdem gibt es gerade bei C unendlich viele Aspekte, die berücksichtigt werden wollen, vor allem den Stil, Entwurfsmuster und Paradigmen betreffend. (Soll dein Code auf einem eingebetteten System laufen, oder eher auf einer Workstation? Im Folgenden gehe ich mal realistischerweise von einem Desktop-Computer aus.)

Trotzdem versuche ich es mal, möchte allerdings noch auf etwas hinweisen: In der Standardbibliothek findest du zwar die Funktionen srand() und rand(), mit denen man angeblich (!) Pseudozufallszahlen erzeugen können soll, allerdings ist die im Standard seit jeher vorgeschriebene Implementierung eines deterministischen Pseudozufallszahlengenerators qualitativ äußerst dürftig und erzeugt ausgesprochen schlechte Zufallszahlen. (Die sind sogar so dermaßen schlecht, dass immer dieselbe Person gewinnen wird, falls du damit ein "Würfelspiel" schreiben würdest!)

Es ist aber total einfach, einen wirklich überdurchschnittlichen Zufallszahlen-Generator selbst zu schreiben, indem man auf gängige Xor-Shift-Implementierungen zurück greift. Deshalb implementiert folgender Code einen solchen Mini-Pseudo-Zufallszahlen-Generator, der exzellente Ergebnisse liefert. (Hinweis für Interessierte: Er besteht sogar die statistischen Tests der dieharder-Testsuite!)

Unter dem Code gibt es noch eine ganze Latte weiterer Anmerkungen, aber hier erst mal das Miniprogramm, welches zehn zufällige Strings ausgibt:

#include <stdio.h> /* printf() */
#include <stdlib.h> /* EXIT_SUCCESS, size_t */
#include <time.h> /* clock(), time() */

typedef unsigned prng;

prng prng_rand(prng state) {
state ^= state << 13;
state ^= state >> 17;
state ^= state << 5;

return state;
}

#define PRNG_INIT() \
prng_init((prng)(time(NULL) ^ clock()))

prng prng_init(const prng seed) {
const prng pi_hex = 0x40490FDB;

return prng_rand(pi_hex ^ seed);
}

#define PRNG_RAND(state, max) \
((state) = prng_rand(state), (state) % (max))

#define PRNG_CHAR(state) \
('a' + PRNG_RAND((state), 26))

prng prng_cstr(prng state, char * cstr, size_t len) {
if (cstr && len) {
--len;

for (size_t i = 0; i < len; ++i) {
cstr[i] = PRNG_CHAR(state);
}

cstr[len] = '\0';
}

return state;
}

#define PRNG_CSTR(state, cstr, len) \
(state) = prng_cstr((state), (cstr), (len))

#define BUFLEN 8

int main(void) {
char cstr[BUFLEN] = {'\0'};
prng state = PRNG_INIT();

for (size_t i = 0; i < 10; ++i) {
PRNG_CSTR(state, cstr, BUFLEN);

printf("#%lu: '%s'\n", i, cstr);
}

return EXIT_SUCCESS;
}

Wie gesagt, noch einige Anmerkungen und Disclaimer bzgl. des Codes:

  • EXIT_SUCCESS aus <stdlib.h> könntest du auch durch "0" ersetzen, aber ich denke, es verdeutlich die Intention des Entwicklers besser.
  • size_t sollte in Schleifen für den Index anstelle von "int" verwendet werden. Ich weiß nicht, ob du das schon gelesen hast, aber bei großen Arrays wäre mit einem normalen "int" bei knapp 2GB Schluss und dir würde dein Programm danach abstürzen. Mithilfe von size_t kannst du auf so viel RAM zugreifen, wie du niemals im Leben haben wirst. :)
  • "prng" zeigt die Absicht auf, die hinter einer Variablen steht, "unsigned" hingegen nur den Typen. Normalerweise würde ich bei nur wenig komplexeren Typen auch in C einen objektorientierten Ansatz wählen (Ja, das geht tatsächlich in C und nicht nur in C++!), aber hier geht es nur um einen "unsigned", also wollen wir mal nicht mit Kanonen auf Spatzen schießen. :)
  • Alle Funktionen für unseren "Pseudo Random Number Generator" beginnen mit dem Präfix "prng_", da C ja leider keine Namensräume kennt. In einem "richtigen" Projekt würde ich ein sprechenderes Präfix wählen, aber hier reicht das völlig aus. Wie gesagt, Kanonen und Spatzen und so ... :)
  • Viele Leute werden sagen "Makros sind böse", und damit haben sie tatächlich oft recht, aber eben nicht immer. Und im obigen Falle verhindern die Hilfsmakros, dass man vergisst den Status des Generators zu aktualisieren. Alternativ hätte man auch eine globale oder eine statische lokale Variable nehmen können, aber das würde ich in diesem Falle als noch ekliger als Makros erachten. Das ist ein bisschen wie die Wahl zwischen Pest und Cholera und unter anderen Umständen würde ich sicher eine Referenz per Zeiger, globale Variable oder im Idealfall gar ein vernünftiges opakes Objekt bevorzugen, aber wie ich eingangs schon erwähnt habe, muss man immer anhand der Anforderungen abwägen.
  • Parameter sollten normalerweise immer const sein, sofern sie nicht weiter verwendet werden, aber um unnötige lokale Variablen zu sparen, habe ich die Parameter an einigen Stellen "recycled".
  • Ich gehe mal davon aus, dass du deinen Code mit einem Compiler kompilierst, der halbwegs aktuelles C kennt, und Variablendeklarationen nicht am Funktionsanfang erwartet. Der obige Code lässt sich zwar auch sehr leicht an C89 anpassen, aber C99 bzw. C11 ist häufig schon angenehmer.
  • Die Funktion prng_cstr() ist so geschrieben, dass man möglichst nichts kaputt machen kann, es keine Überläufe gibt und das Ergebnis ordentlich nullterminiert ist. Vielleicht sieht die Funktion noch etwas kompliziert für dich aus, aber wenn du weiter übst, wirst du sie vermutlich spätestens in ein paar Wochen problemlos verstehen.
  • Der Code ist auf Einfachheit und nocht auf Portabilität ausgelegt. Das betrifft insbesondere den Teil im Makro PRNG_CHAR(), welches einen einzigen zufälligen Buchstaben erzeugt. Der Code aus den anderen Antworten mit dem langen Stringliteral "abcdefghijklmnopqrstuvwxyz" ist hier deutlich Portabler! Aber da man heutzutage kaum noch auf eine Nicht-ASCII-Plattform stoßen wird, ist die Berechnung mit Offset von 'a' aus vermutlich auch akzeptabel. Merke dir aber bitte, dass Annahmen zum Zeichensatz laut C-Standard niemals portabel sein werden!
  • Ich weiß, dass der obige Code-Schnipsel nicht dein Problem erschlägt, aber es ist auch nicht meine Absicht, dir deine Ideen zu entwickeln. Programmieren lernen musst du selbst und der Quelltext von oben wird dich hoffentlich etwas weiter bringen, inspirieren, anregen oder interessieren.

Naja, es gibt noch weitere Kleinigkeiten, aber ich glaube, das reicht jetzt so langsam. Vermutlich überfordert dich der obige Code und die Anmerkungen etwas, aber mach dir da nichts draus! Einfach immer schön weiter lernen, dann verstehst du automatisch irgendwann alles! :)

Schönen Abend noch! :)
...zur Antwort

Kleine Randbemerkung (leicht OT): Die Begriffe "Yuri" und "Yaoi" sind so veraltet, dass sie in Japan seit weit über 10 Jahren kein Mensch mehr nutzt. Ich höre das immer nur in der westlichen Welt, aber direkt in Japan klingen die beiden Wörter wie "aus Großmutters Zeiten". :)

Auf keiner Manga-Messe und in keinem Buchladen, innerhalb von Japan, wird man diese Kategorien unter diesen beiden Namen heutzutage noch finden können. :)

...zur Antwort

Noch eine Randbemerkung zu den anderen Antworten: Das hängt auch noch zusätzlich extrem stark a) vom verwendeten Dateisystem bzw. dessen Konfiguration und b) von der Größe der einzelnen Dateien ab, sofern du nicht Block- sondern Datei-weise kopierst. (unter "Spiegeln" würde ich normalerweise Blockweises klonen verstehen, aber darunter verstehen viele etwas anderes)

  1. Wenn du beispielsweise eine einzige Datei mit 10GB Größe über SATA von Platte A auf Platte B kopierst, wird es (Pi mal Daumen) unabhängig vom Dateisystem ca. 3 Minuten dauern. (grobe Schätzung)
  2. Falls du hingegen eine Million Dateien mit jeweils ca. 10 KB kopierst (was an reinen Daten im Endeffekt wieder 10GB sind), hängt die Geschwindigkeit extrem stark vom Dateisystem ab, und wird u. U. mehrere Stunden in Anspruch nehmen.

Aus diesem Grunde kopiere / sichere ich Dateisysteme mit vielen kleinen Futzeldateien normalerweise Blockweise. :)

...zur Antwort

Einfach mal "-$" probieren, bzw. das "-" (Minus) durch das Unicode-Zeichen des von dir benutzen Bindestrich-Symbols ersetzen.

Bei den meisten Dialekten regulärer Ausdrücke steht das "$" für das Zeilenende. ("\n" wird in den meisten Fällen nicht funktionieren)

Falls zwischen dem Bindestrich und dem Zeilenende noch evtl. vorhandene Leerzeichen akzeptiert werden sollen, einfach "-\s*$" probieren. (Bei Notepad++ das Backslash evtl. escapen!)

Viel Spaß! :)
...zur Antwort

Ja, braucht man, wenn man z. B. wissen will, warum ein System abstürzt, weil man über die serielle Schnittstelle Fehlermeldungen auch dann auslesen kann, wenn das System schon so kaputt ist, dass Textausgabe auf dem Monitor nicht mehr funktioniert.

Oder wenn du Treiber und Kernel auf einem zweiten Rechner debuggen willst.

Ein anderer Anwendungsfall sind viele Industrieanlage und Steuerungen, die ebenfalls oft über den seriellen Port programmiert werden. Das trifft auch auf viele (ISP-)Programmiergeräte für µCs oder Eproms zu.

Außerdem ist die Programmierung der seriellen Schnittstelle - verglichen mit USB - wesentlich einfacher und schlanker, ohne größere Bibliotheken zu benötigen, und das reicht für viele Anwendungsfälle aus.

Den Parallelport nehme ich ebenfalls für IC-Programmer, wobei hier die neueren natürlich auch mit USB arbeiten. :)

...zur Antwort
Das hängt sehr von der Sprache ab, vor allem ob ein Garbage Collector zum Einsatz kommt, oder nicht!

Funktionen sollten - wie triopasi bereits geschrieben hat - sowieso nicht so lang sein, dass man temporäre Variablen über innere Gültigkeitsbereiche einführen muss, um nicht den Überblick zu verlieren.

Bei Java ist es wenig sinnvoll, aber bei C++ ist es völlig anders:

std::vector<int> iv;

// tue etwas mit "iv" ...

{
std::vector<int> tmp;

using std::swap;
swap(iv, tmp);
}

// "iv" ist jetzt garantiert leer

Bei C++ ergibt es also durchaus Sinn, und das vermutlich größte und wichtigste Konzept - nämlich RAII - fußt auf der Zerstörung von Objekten beim Verlassen des Gültigkeitsbereichs.

Fazit: Bei Java sinnlos, bei C++ hin und wieder wirklich sehr sinnvoll bis notwendig! Hängt also ausschließlich von der Sprache ab. :)

PS: Ich habe mir jetzt C++ und Java rausgepickt, aber viele Programmiersprachen verhalten sich nochmal völlig anders. Zum Beispiel ...

var foo = function() {
var a = 123;

{
var b = 456;
}

// var b existiert auch hier!
};

... hat JavaScript einen Funktionsscope, und Variablen innerhalb von Blöcken verhalten sich, als wären sie außerhalb deklariert. (Mal abgesehen vom relativ neuen "let" Schlüsselwort seit ES6, aber egal ...)

Bei C# ist das mit IDisposable + using wieder etwas anders aber das würde jetzt zu weit führen.

Disclaimer: Die obigen Beispiele sind allesamt an den Haaren herbei gezogen, und wenn man ordentlich programmiert, braucht man solche inneren Blöcke eigentlich nicht.

Normalerweise ist es sinnvoller alles ordentlich in kurze Minifunktionen auszulagern und Referenzen zu übergeben!

...zur Antwort
Normalerweise führt der schnellste Weg eine Software zu knacken, zu manipulieren oder zu reversen über die Programmiersprache und Bibliotheken, in der diese Software selbst geschrieben ist.

Das gilt auch für Spiele!

Wenn dein Spiel also Unity als Engine benutzt, und selbst in C# geschrieben ist, dann solltest du dort ansetzen. Wenn es hingegen in C++ mit der Unreal-Engine geschrieben ist, schreibst du dir deine Werkzeuge auch damit.

Für Browsergames reicht oft schon der Inspektor, Greasemonkey oder andere Werkzeuge aus. Früher hat auch oft ein Actionscript-Decompiler geholfen, aber da Flash ja nicht mehr sonderlich verbreitet ist, reichen heute Deobfuscatoren für JS oder CSS oftmals völlig aus. Bei der Kommunikation kann man einfach AJAX-Anfragen abfangen, JSON oder XML manipulieren und weiter senden.

Bei Java reicht oft ein Decompiler bzw. Disassembler aus, bzw. man kann sehr einfach eigene Interfaces mit dem daraus erlangten Wissen schreiben, und dann mittels Reflection im Speicher rumwüten, wie man lustig ist. :)

Bei Android APKs oder anderen App-Formaten ist das Ganze ebenfalls sehr sehr einfach.

Allerdings sollte man unbedingt Kenntnisse in Assembler mitbringen, falls es sich nicht gerade um einen JVM- bzw. IL-Code handelt.

Fertige Programme, bzw. Spiele kannst du über einen Debugger manipulieren, aber da die sowieso fast immer ihre Debugging-Symbole gestrippt haben sollten, kommst du hier ohne Assembler nicht weiter.

Dann gibt es noch unendlich viele Werkzeuge, die - einem Debugger ähnlich - zur Laufzeit auf Speicherbereiche von anderen Prozessen zugreifen können, und dort Werte manipulieren. Für Spiele ist die Cheat-Engine ganz beliebt.

Naja, wie du siehst, gibt es (fast) unendlich viele Ansätze. Such dir einen davon aus, der zu deinem anvisierten Spiel passt! :)

Viel Spaß! :)

PS: Kopierschutzmaßnahmen und Dinge wie Denuvo verhindern oftmals eine Manipulation bzw. das Cheaten. Diese Dinge sind dann meist vergleichsweise schwer zu umgehen und man sitzt gerne auch mal mehrere Monate an einer Lösung.

PPS: Ich spiele selbst zwar keine Spiele, aber ich höre immer, dass Cheater den anderen Spielern den Spaß verderben. Nimm also bitte Rücksicht auf deine Mitspieler! Zu Übungszwecken ist die Entwicklung von Cheats sehr gut zum Lernen geeignet. Genauso wie das Schreiben von Malware oder Trojanern. Aber man sollte so viel Verstand haben, und auf keinen Fall seine Mitmenschen mit diesen Dingen belästigen!

...zur Antwort
Weitere Inhalte können nur Nutzer sehen, die bei uns eingeloggt sind.