2010-06-05 14 views
8

Ich habe viele Programmierer lesen und schreiben gelesen, wenn Programmierung in C/C++ gibt es viele Probleme im Zusammenhang mit Speicher. Ich plane zu lernen, in C/C++ zu programmieren. Ich habe Anfängerkenntnisse in C/C++ und möchte ein kurzes Beispiel sehen, warum C/C++ Probleme mit der Speicherverwaltung haben kann. Liefern Sie bitte einige Proben.Warum C/C++ Speicherproblem?

+10

einfach, weil Sie Speicher selbst zuordnen und freigeben müssen. –

+0

Wie wird es Problem, wenn Sie einen Speicher reservieren und es freigeben ? – LinuxNewbie

+2

Sie machen Fehler :) –

Antwort

16

Es gibt viele Möglichkeiten, den Speicher in C oder C++ zu beschädigen oder zu verlieren. Diese Fehler gehören zu den am schwierigsten zu diagnostizierenden Fehlern, da sie oft nicht leicht reproduzierbar sind.

Zum Beispiel ist es einfach, Speicher, den Sie zugewiesen haben, nicht freizugeben. Zum Beispiel wird dies eine „doppelte frei“, versuchte a zweimal zu befreien und andernfalls b zu befreien:

char *a = malloc(128*sizeof(char)); 
char *b = malloc(128*sizeof(char)); 
b = a; 
free(a); 
free(b); // will not free the pointer to the original allocated memory. 

Ein Beispiel Pufferüberlauf, der folgt beliebigen Speicher korrumpiert. Es ist ein Pufferüberlauf, weil Sie nicht wissen, wie lange str ist. Wenn es länger als 256 Bytes ist, dann schreibt es diese Bytes irgendwo im Speicher, möglicherweise überschreiben Sie Ihren Code, möglicherweise nicht.

void somefunc(char *str) { 
    char buff[256]; 
    strcpy(buff, str); 
} 
+0

Danke, das ist eine gute Probe. Das werde ich mir merken. – LinuxNewbie

+2

+1 für C ODER C++! – AndrejaKo

+0

Ich habe mich zurückhalten, die C++ diese Antwort zu bearbeiten weg, da es reinen C-Code in ... –

3

Der Grund dafür, dass dies in C/C++ häufig als etwas bezeichnet wird, ist, dass viele moderne Sprachen Speicherverwaltung und Speicherbereinigung durchführen. In C/C++ ist dies nicht der Fall (zum Guten oder zum Schlechten). Sie müssen Speicher manuell zuordnen und freigeben. Wenn dies nicht ordnungsgemäß durchgeführt wird, führt dies zu einem Speicherverlust, der in einer Sprache, die die Speicherverwaltung für Sie übernimmt, nicht möglich wäre.

+0

Wenn der Programmierer den Speicher zuweist und auflöst, warum benötigt er eine Garbage Collection? – LinuxNewbie

+1

@LinuxNewbie: Er tut es nicht! C++ führt keine automatische Speicherbereinigung durch. Sehen Sie hier: http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29 – nico

+2

"Sie müssen Speicher manuell zuordnen und freigeben" -> Nicht unbedingt.Es gibt Werkzeuge, die die Notwendigkeit ausplanen Speicher manuell, zum Beispiel 'boost :: shared_ptr ' reduzieren. – fredoverflow

3

Eines der allgemeinen Speicherverwaltungsprobleme in C und C++ hängt mit dem Fehlen von Grenzen bei der Überprüfung von Arrays zusammen. Im Gegensatz zu Java (zum Beispiel) überprüfen C und C++ nicht, um sicherzustellen, dass der Array-Index innerhalb der tatsächlichen Array-Grenzen liegt. Aus diesem Grund ist es leicht, Speicher versehentlich zu überschreiben. Zum Beispiel (C++):

char *a = new char[10]; 
a[12] = 'x'; 

Es wird keine Kompilierung oder Laufzeitfehler mit dem obigen Code in Verbindung gebracht werden, mit der Ausnahme, dass der Code-Speicher überschreiben, die nicht sein sollte.

+0

Danke für dieses Beispiel. – LinuxNewbie

+0

„Es wird keine Kompilierung oder Laufzeitfehler mit dem obigen Code in Verbindung gebracht werden“ -> können Sie [intelligentere Speicherroutinen] verwenden (http://stackoverflow.com/questions/2835416/critique-my-non-intrusive-heap-debugger) – fredoverflow

+0

Viele Compiler und Betriebssysteme ausgeben Fehler für diesen zur Laufzeit, wie AV unter Windows und Debug-Behauptungen in der CRT für Visual Studio;) Puffer überlaufen zur Laufzeit zu erfassen. – Puppy

7

Grundsätzlich müssen Sie in diesen Sprachen jedes Speicherbit manuell anfordern, das bei der Kompilierung keine lokale Variable ist, und Sie müssen es manuell freigeben, wenn Sie es nicht mehr benötigen. Es sind Bibliotheken (sog. Smartpointer), die diesen Prozess bis zu einem gewissen Grad automatisieren können, aber nicht überall anwendbar sind. Darüber hinaus sind dem Zugriff auf den Speicher über Zeigerarithmetik absolut keine Grenzen gesetzt.

manuelle Speicherverwaltung kann auf eine Reihe von Fehlern führen:

  • Wenn Sie vergessen, etwas Speicher freizugeben, müssen Sie eine Speicher
  • undicht Wenn Sie mehr Speicher, als Sie für eine bestimmte angeforderte Zeiger haben Sie einen Pufferüberlauf.
  • Wenn Sie Speicher freigeben und halten eine „baumelnde Zeiger“, um es verwenden, haben Sie nicht definiertes Verhalten (in der Regel das Programm abstürzt)
  • Wenn Sie Ihren Zeiger arithmetics verkalkuliert, Sie haben einen Absturz oder beschädigte Daten

Und viele dieser Probleme sind sehr schwer zu diagnostizieren und zu debuggen.

+0

Können Sie mir zeigen, wie Sie ein bisschen Speicher anfordern können? malloc benötigt eine ganze Anzahl von Bytes! –

+0

@Pete: Nun, die Tatsache, dass Sie sie in Bündeln von 8 bekommen, widerspricht nicht meiner Aussage, dass Sie sie manuell anfordern müssen, oder? –

+0

Also habe ich * jeden * Kontinent besucht, weil ich (über) 1/8 von ihnen besucht habe? –

5

Ich plane, in C/C++

Was genau meinst du damit Sie programmieren lernen? Möchten Sie lernen, in C zu programmieren, oder möchten Sie lernen, in C++ zu programmieren? Ich würde nicht empfehlen, beide Sprachen gleichzeitig zu lernen.

Aus Sicht des Benutzers ist Speicherverwaltung in C++ viel einfacher als in C, da das meiste von Klassen verkapselt ist, zum Beispiel std::vector<T>. Aus konzeptioneller Sicht ist die Speicherverwaltung von C sehr viel einfacher. Grundsätzlich gibt es nur malloc und free :)

+0

Eigentlich habe ich eine Idee von einem kleinen Dienstprogramm, also dachte ich mir, das mit C zu machen (nicht C++. Ich denke, C++ ist ein bisschen weit von mir und betrachtet jetzt die OOP-Konzepte und das Design). Dann plane ich, dieses Dienstprogramm in C++ zu konvertieren, was mir die Möglichkeit gibt, C++ zu lernen. Ich plane (hoffe), meinen Nutzen in 9 ~ 11 Monaten zu beenden. – LinuxNewbie

+0

@Linux: Learning C als Sprungbrett zu C++ ist * nicht * empfohlen von [Stroustrup] (http://www.research.att.com/~bs/bs_faq.html#prerequisite). – fredoverflow

+1

@LinuxNewbie: C++ ist sehr viel einfacher als C, weil diese OOP-Konzepte Sie davor bewahren, eine absolute Menge Arbeit zu erledigen. – Puppy

2

Wenn neue verwendet wird, um einen Speicherblock zu erhalten, kann die vom Betriebssystem reservierte Größe größer sein als Ihre Anforderung, aber nie kleiner. Aus diesem Grund und der Tatsache, dass delete nicht sofort den Speicher an das Betriebssystem zurückgibt, wenn Sie den gesamten Speicher untersuchen, den Ihr Programm verwendet, können Sie glauben, dass Ihre Anwendung schwerwiegende Speicherlecks aufweist. Die Überprüfung der Anzahl der Bytes, die das gesamte Programm verwendet, sollte daher nicht zur Erkennung von Speicherfehlern verwendet werden. Nur wenn der Speichermanager ein großes und kontinuierliches Speicherwachstum anzeigt, sollten Sie Speicherlecks vermuten.

5

Ich kann ehrlich sagen, dass ich keine Probleme mit der Speicherzuweisung beim Programmieren in C++ habe. Das letzte Mal, dass ich ein Speicherleck hatte, war vor über 10 Jahren, und war wegen Blindheit meinerseits. Wenn Sie Code unter Verwendung von RAII, Standardbibliotheksbehältern und einem kleinen Maß an gesundem Menschenverstand schreiben, existiert das Problem wirklich nicht.

1

Eine Sache, die bisher nicht erwähnt wurde, ist die Leistung und warum Sie Speicher manuell verwalten möchten. Das Verwalten von Speicher ist schwierig, insbesondere, wenn ein Programm komplexer wird (besonders wenn Sie Threads verwenden und wenn die Lebensdauer von Speicherstücken komplex wird (dh wenn es schwierig wird, wenn Sie es nicht genau bestimmen können) Information)) auch mit leistungsfähigen modernen Programmierwerkzeugen wie Valgrind.

Also warum sollten Sie Speicher manuell verwalten möchten, ein paar Gründe: --To zu verstehen, wie es funktioniert/zu --To Garbage Collection/automatische Speicherverwaltung implementieren müssen Sie manuell --Mit einer niederen Ebene Dinge wie einen Kernel brauchen Sie die Flexibilität, die manuelle Steuerung des Speichers geben kann. - Am wichtigsten, wenn Sie manuelle Speicherverwaltung richtig machen, können Sie eine große Beschleunigung/weniger Speicher Overhead (bessere Leistung), ein damit verbundenes Problem mit Garbage Collection (obwohl es besser als bessere Garbage Collectors wie der Hotspot jvm eins geschrieben werden) ist, dass Sie die Speicherverwaltung nicht kontrollieren können, so dass es schwer ist, Sachen mit Echtzeit-Sachen zu erledigen (Fristen für bestimmte Ziele wie Auto-Bremsen und Schrittmacher garantieren, spezielle Echtzeit-GCs ausprobieren) und Programme, die mit Benutzern interagieren, könnten ein wenig einfrieren Bit oder Lag (das würde für ein Spiel saugen).

Eine Menge von "Modern C++" (es wurde gesagt, dass C++ kann als mehrere Sprachen gedacht werden, je nachdem, wie Sie es verwenden) im Gegensatz zu C mit Klassen (oder X und Y C++ -Funktion) verwenden einen Kompromiss durch häufig mit einfachen optionalen GC/automatische Speicherverwaltung (beachten Sie, dass optional GC kann bei der Speicherverwaltung dann obligatorisch sein, da, wenn es obligatorisch ist ein einfacheres System) Funktionen und und einige manuelle Speicherverwaltung. Abhängig davon, wie Sie dies tun, kann es einige Vorteile und Nachteile der Verwendung von GC und manuelle Speicherverwaltung haben. Optional GC ist auch mit einigen C-Bibliotheken verfügbar, aber es ist weniger üblich mit C als C++.

+0

+1 Mit Fähigkeiten in der manuellen Speicherarbeit können Sie wirklich verstehen, wie die GC-Systeme funktionieren ... und wann Sie es besser selbst tun sollten. – Rusty

2

Es ist offensichtlich, dass Sie den Speicher freigeben müssen, der nicht mehr verwendet wird oder in Zukunft nicht mehr verwendet wird. Sie müssen jedoch am Anfang des Programms festlegen, dass der Speicherbedarf statisch oder variiert ist. Wenn es dynamisch ist, nehmen Sie genug Speicher für Ihre Programmarbeit, dass Ihr Programm möglicherweise zusätzlichen Speicher verbraucht.

also müssen Sie den Speicher freigeben, der nicht verwendet wird, und diese Zeit erstellen, wenn sie benötigt wird. wie

struct student 
{ 
char name[20]; 
int roll; 
float marks; 
}s[100]; 

Hier nehme ich an 100 Schüler in der Klasse. Student kann mehr als 100 oder weniger 100. Wenn mehr als 100 dann Ihr Programm Informationen verlieren oder weniger 100 dann Programm wird ausgeführt, aber die Verschwendung von Speicher, kann es groß sein.

so erstellen wir normalerweise einen Datensatz dynamisch zum Zeitpunkt der Ausführung. wie

struct student *s; 

s=(struct student *)malloc(sizeof(struct student)); 

scanf("%s %d %f",s->name,s->roll,s->marks); 

nicht, wenn in Gebrauch, dann löschen Sie es momery Raum bilden.

Das ist eine gute Methode für die Programmierung, wenn Sie nicht aus dem Speicher entfernen, dann auf einmal kann es Ihren Speicherstapel voll und es kann hängen.