2009-11-02 13 views
10

Ich habe einen Char-Zeiger, der zum Speichern einer Zeichenfolge verwendet werden würde. Es wird später im Programm verwendet.char-Zeiger initialisieren

Ich habe wie diese deklariert und initialisiert:

char * p = NULL; 

ich gerade fragen, ob dies eine gute Praxis ist. Ich benutze gcc 4.3.3.

+3

Was ist Ihre Frage? –

+1

Ich denke, er fragt, ob er diese "Zeichenkette" auf NULL (oder 0), auf "" initialisieren oder gar nicht initialisieren soll. –

+0

Einige Vorsicht hier gebraucht wird, NULL ist _usually_ 0, aber nach der Norm es anders sein könnte: 'Das Makro NULL, in jeder definiert , , , , , oder , ist eine Implementierung definiert C++ Nullzeigerkonstante in diesem Internationalen Standard'. Ich würde definitiv bei NULL bleiben, außerdem ist es "typorientierter" und beschreibender im Quellcode als 0. – RedGlyph

Antwort

10

Ja, es ist eine gute Idee. Google Code Style empfiehlt:

  1. alle auch Ihre Variablen zu initialisieren, wenn Sie sie nicht brauchen gerade jetzt.
  2. Initialize Zeiger von NULL, int 's von 0 und float' s von 0,0 - nur für bessere Lesbarkeit.

    int i = 0; 
    double x = 0.0; 
    char* c = NULL; 
    
+1

Übrigens, das ist ein C++ Style Guide. Es sagt uns nicht, was (wenn überhaupt) Google über C. sagt. –

+0

@onebyone: Sogar noch, es empfiehlt sich, Zeiger auf NULL zu initialisieren und sie dann auf NULL zu setzen, nachdem sie freigegeben wurden. Es erleichtert das Testen vor der Dereferenzierung, insbesondere bei komplexem Code. Dies gilt für C oder C++. –

+0

@onebyone Sie haben Recht, ich bin C++ - Entwickler und sah C++ - Syntax in der Frage =) Aber O denke, die Regel über NULL ist eine gute Übung für C zu. – f0b0s

4

Es empfiehlt sich, alle Variablen zu initialisieren.

3

Sie können keine Zeichenfolge in einem Zeiger speichern.

Ihre Definition von mgt_dev_name ist gut, aber Sie müssen es irgendwo mit Platz für Ihre Zeichenfolge zeigen. Entweder malloc() das Leerzeichen oder verwenden Sie ein zuvor definiertes Array von Zeichen.

char *mgt_dev_name = NULL; 
char data[4200]; 

/* ... */ 

mgt_dev_name = data; /* use array */ 

/* ... */ 

mgt_dev_name = malloc(4200); 
if (mgt_dev_name != NULL) { 
    /* use malloc'd space */ 
    free(mgt_dev_name); 
} else { 
    /* error: not enough memory */ 
} 
+0

Ich weiß nicht, ob das ist, was er gefragt hat, aber es ist was ich wissen wollte. Insbesondere, wie auf NULL initialisiert wird und später Speicherplatz für eine Zeichenfolge zugewiesen wird. –

3

Wenn Sie sich fragen, ob es notwendig ist, oder ob es eine gute Idee, um die Variable NULL zu initialisieren, bevor Sie es auf etwas gesetzt sonst später: Es ist nicht notwendig, es zu NULL zu initialisieren, es gewann‘ t machen Sie einen Unterschied für die Funktionalität Ihres Programms.

Beachten Sie, dass es beim Programmieren wichtig ist, jede Codezeile zu verstehen - warum sie da ist und was genau sie tut. Tu Dinge nicht, ohne zu wissen, was sie bedeuten oder ohne zu verstehen, warum du sie tust.

+1

Eigentlich sollte er es auf NULL initialisieren. Technisch gesehen macht es sogar schlecht, wenn Sie auf Speicher zeigen, der nicht zu Ihrem Programm gehört. Wenn Sie also NULL setzen, vermeiden Sie das. (Und es ist eine gute Programmierpraxis) – GManNickG

+1

Aber es ist mehr fehleranfällig, Variablen nicht zu initialisieren, nach mir. –

+0

@GMan - Aber wenn er die Variable ein paar Zeilen später auf einen anderen Wert initialisiert, ohne etwas mit der Variablen dazwischen zu tun, ist das unnötig. – Jesper

0

Es gibt mehrere gute Antworten auf diese Frage, von denen angenommen wurde. Ich werde trotzdem antworten, um die praktischen Aspekte zu erweitern.

Ja, es ist eine gute Vorgehensweise, Zeiger auf NULL zu initialisieren, sowie Zeiger auf NULL zu setzen, nachdem sie nicht mehr benötigt werden (d. H. Freigegeben).

In jedem Fall ist es sehr praktisch, in der Lage zu sein, einen Zeiger vor der Dereferenzierung zu testen. Nehmen wir an Sie eine Struktur haben, die wie folgt aussieht:

struct foo { 
    int counter; 
    unsigned char ch; 
    char *context; 
}; 

Sie dann eine Anwendung schreiben, die mehrere Threads laicht, die alle auf einer zugewiesenen foo Struktur betreiben (sicher) durch die Verwendung der gegenseitigen Ausgrenzung.

Thread A erhält eine Sperre auf foo, erhöht Zähler und prüft auf einen Wert in ch.Es findet keinen, also wird der Kontext nicht zugeordnet (oder geändert). Stattdessen speichert es einen Wert in ch, so dass Thread B diese Arbeit stattdessen ausführen kann.

Thread B Sieht, dass der Zähler inkrementiert wurde, notiert einen Wert in ch, ist sich aber nicht sicher, ob Thread A irgendetwas mit Kontext getan hat. Wenn Kontext als NULL initialisiert wurde, muss sich Thread B nicht länger darum kümmern, was Thread A getan hat, er weiß, dass der Kontext sicher ist, um zu dereferenzieren (wenn nicht NULL) oder zuzuweisen (wenn NULL), ohne zu lecken.

Thread B erledigt sein Geschäft, Thread A liest seinen Kontext, gibt ihn frei und initialisiert ihn dann auf NULL.

Die gleiche Argumentation gilt für globale Variablen ohne die Verwendung von Threads. Es ist gut, sie in verschiedenen Funktionen testen zu können, bevor Sie sie dereferenzieren (oder versuchen, sie zuzuweisen, was zu einem Leck und einem undefinierten Verhalten in Ihrem Programm führt).

Wenn es albern ist, wenn der Umfang des Zeigers nicht über eine einzige Funktion hinausgeht. Wenn Sie eine einzelne Funktion haben und die Zeiger darin nicht verfolgen können, bedeutet das normalerweise, dass die Funktion neu berechnet werden sollte. Es ist jedoch nichts falsch daran, einen Zeiger in einer einzigen Funktion zu initialisieren, und sei es nur, um einheitliche Gewohnheiten beizubehalten.

Das einzige Mal, dass ich ein ‚hässlich‘ Fall von unter Berufung auf eine initialisierte Zeiger in (vor und nach dem Gebrauch) so etwas wie dies gesehen haben:

void my_free(void **p) 
{ 
    if (*p != NULL) { 
     free(*p); 
     *p = NULL; 
    } 
} 

ist nicht nur dereferencing eine Art Zeiger punned auf strengen Plattformen verpönt, macht der obige Code frei() sogar noch gefährlicher, weil Anrufer eine Täuschung der Sicherheit haben werden. Sie können sich nicht auf eine "Großhandels" -Praxis verlassen, es sei denn, Sie sind sich sicher, dass jede Operation damit einverstanden ist.

Wahrscheinlich viel mehr Informationen, als Sie eigentlich wollten.

3

Eine weitere Option besteht darin, die Variable erst an der Stelle in Ihrem Code zu definieren, an der Sie Zugriff auf den Anfangswert haben. Also lieber dann tun:

char *name = NULL; 

... 

name = initial_value; 

ich ändern würde, dass auf:

... 

char *name = initial_value; 

Der Compiler wird Sie dann verhindert, dass der Variable in dem Teil des Codes verweisen, wo es keinen Wert hat. Abhängig von den Besonderheiten Ihres Codes ist dies möglicherweise nicht immer möglich (der Anfangswert wird beispielsweise in einem inneren Bereich festgelegt, die Variable hat jedoch eine andere Gültigkeitsdauer). Durch die Verschiebung der Definition im Code werden Fehler so lange wie möglich vermieden.

Das heißt, das ist nur erlaubt, beginnend mit dem c99-Standard (es ist auch gültig C++). Um c99 Funktionen in gcc zu aktivieren, müssen Sie entweder tun:

gcc -std=gnu99 

oder wenn Sie nicht auf die Standard-gcc Erweiterungen wollen:

gcc -std=c99 
3

Nein, es ist keine gute Praxis wenn ich deinen Kontext richtig verstanden habe.

Wenn Ihr Code tatsächlich von der mgt_dev_name mit dem Anfangswert eines Null-Pointer abhängt, dann ist natürlich, einschließlich der Initialisierer in die Deklaration eine sehr gute Idee. I.e.wenn Sie würde das sowieso tun

char *mgt_dev_name; 

/* ... and soon after */ 
mgt_dev_name = NULL; 

dann ist es immer eine bessere Idee Initialisierung zu verwenden, anstatt Abtretungs

char *mgt_dev_name = NULL; 

Allerdings ist die Initialisierung nur gut, wenn Sie Ihr Objekt mit einem initialisieren sinnvollnützlich Wert. Ein Wert, den Sie tatsächlich benötigen. Im Allgemeinen ist dies nur in Sprachen möglich, die Deklarationen an beliebigen Stellen im Code erlauben, wobei C99 und C++ gute Beispiele für solche Sprachen sind. Zu dem Zeitpunkt, zu dem Sie Ihr Objekt benötigen, kennen Sie normalerweise bereits den entsprechenden Initialisierer für dieses Objekt und können daher leicht eine elegante Deklaration mit einem guten Initialisierer erstellen.

In C89/90 dagegen können Deklarationen nur am Anfang des Blocks platziert werden. An diesem Punkt haben Sie im Allgemeinen keine sinnvollen Initialisierer für alle Ihre Objekte. Sollten Sie sie nur mit etwas initialisieren, alles (wie 0 oder NULL), nur um sie initialisiert zu haben? Nein!!! Tue niemals bedeutungslose Dinge in deinem Code. Es wird nichts verbessern, unabhängig davon, was verschiedene "Style Guides" Ihnen vielleicht sagen. In Wirklichkeit könnte eine sinnlose Initialisierung tatsächlich Fehler in Ihrem Code abdecken, wodurch es schwieriger wird, sie zu finden und zu beheben.

Beachten Sie, dass es auch in C89/90 immer vorteilhaft ist, nach einer besseren Lokalität der Deklarationen zu streben. I.e. Eine bewährte Good-Practice-Richtlinie besagt: Machen Sie Ihre Variablen immer so lokal wie möglich. Stapeln Sie nicht alle lokalen Objektdeklarationen am Anfang der Funktion, sondern verschieben Sie sie an den Anfang des kleinsten Blocks, der die gesamte Lebensdauer des Objekts so eng wie möglich umschließt. Manchmal könnte es sogar eine gute Idee sein, einen fiktiven, ansonsten unnötigen Block einzuführen, nur um die Lokalität der Deklarationen zu verbessern. Wenn Sie diese Vorgehensweise befolgen, können Sie Ihren Objekten in vielen (wenn nicht in den meisten Fällen) nützliche Initialisierer zur Verfügung stellen. Aber einige Objekte bleiben in C89/90 uninitialisiert, nur weil Sie zum Zeitpunkt der Deklaration keinen guten Initialisierer für sie haben. Versuchen Sie nicht, sie mit "etwas" zu initialisieren, nur um sie initialisieren zu lassen. Dies wird absolut nichts Gutes erreichen und könnte sogar negative Konsequenzen haben.

Beachten Sie, dass einige moderne Entwicklungstools (wie MS Visual Studio 2005 zum Beispiel) den Laufzeitzugriff auf nicht initialisierte Variablen in der Debug-Version des Codes erfassen. Diese Tools können Ihnen helfen, Situationen zu erkennen, in denen Sie auf eine Variable zugreifen, bevor sie einen aussagekräftigen Wert erhalten haben, der auf einen Fehler im Code hinweist. Durch die bedingungslose vorzeitige Initialisierung Ihrer Variablen können Sie jedoch diese Fähigkeit des Tools im Wesentlichen zunichte machen und diese Fehler unter den Teppich kehren.

0

Bevorzugte Stile:

in C: char * c = NULL;

in C++: char * c = 0;

0

Meine Begründung ist, dass, wenn Sie nicht mit NULL Sie initialisieren, und dann vergessen ganz, die initialisieren Arten von Fehlern, die Sie in Ihrem Code bekommen, wenn die Dereferenzierung viel schwieriger zu verfolgen ist, weil der potentielle Müll zu diesem Zeitpunkt im Speicher gehalten wird. Auf der anderen Seite, wenn Sie auf NULL initialisieren, die meiste Zeit erhalten Sie nur eine segmentation fault, die besser ist, wenn man die Alternative berücksichtigt.

0

Das Initialisieren von Variablen, auch wenn sie nicht sofort initialisiert werden müssen, ist eine gute Vorgehensweise.Normalerweise initialisieren wir Zeiger auf NULL, int auf 0 und schweben als Konvention auf 0.0.

int* ptr = NULL; 
int i = 0; 
float r = 0.0;