2009-11-02 24 views
10

Tengo un puntero de char que se usaría para almacenar una cadena. Se usa más adelante en el programa.inicialización de punteros de char

he declarado e inicializado como esto:

char * p = NULL; 

Me pregunto si esto es una buena práctica. Estoy usando gcc 4.3.3.

+3

¿Cuál es tu pregunta? –

+1

Supongo que pregunta si debería inicializar esa "cadena" a NULL (o 0), a "" o no inicializarla en absoluto. –

+0

, requiere alguna precaución aquí, NULL es _usually_ 0 pero de acuerdo a la norma podría ser diferente: 'La NULL macro, que se define en cualquiera de , , , , , o , es una definida implementación Constante de puntero nulo C++ en esta Norma Internacional'. Definitivamente me quedaré con NULL, además de que es más "orientado a tipos" y más descriptivo en el código fuente que 0. – RedGlyph

Respuesta

10

Sí, es una buena idea. Google Code Style recomienda:

  1. Para inicializar todas las variables, incluso si no los necesita en este momento.
  2. Inicialice los punteros por NULL, int por 0 y float por 0.0 - solo para una mejor legibilidad.

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

Por cierto, es una guía de estilo C++. No nos dice qué (si acaso) dice Google sobre C. –

+0

@onebyone: Aún así, es una buena práctica inicializar los punteros a NULL y luego establecerlos en NULL después de liberarlos. Hace que sea más fácil probarlos antes de desreferenciarlos, especialmente en código complejo. Esto es cierto en C o C++. –

+0

@onebyone tienes razón, soy desarrollador de C++ y vi la sintaxis de C++ en la pregunta =) Pero O piensas que la regla sobre NULL también es una buena práctica para C. – f0b0s

4

Es una buena práctica inicializar todas las variables.

3

No puede almacenar una cadena en un puntero.

Su definición de mgt_dev_name es buena, pero debe apuntarla a un lugar con espacio para su cadena. O bien malloc() que espacia o usa una matriz de caracteres previamente definida.

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

No sé si esto es lo que estaba preguntando, pero es lo que quería saber. Específicamente, cómo inicializar a NULL y luego asignar espacio para una cadena. –

3

Si estás preguntando si es necesario, o si es una buena idea para inicializar la variable a NULL antes de instalarla a otra cosa más adelante: No es necesario inicializar a NULL, que ganó' t hacer alguna diferencia para la funcionalidad de su programa.

Tenga en cuenta que en la programación, es importante comprender cada línea de código: por qué está allí y qué está haciendo exactamente. No hagas cosas sin saber lo que significan o sin entender por qué lo haces.

+1

En realidad, debería inicializarlo en NULL. Técnicamente, incluso señalar a la memoria que no pertenece a su programa lo hace mal formado, por lo que al establecerlo en NULL, lo evita. (Y es una buena práctica de codificación) – GManNickG

+1

Pero es más propenso a errores de no inicializar variables, según yo. –

+0

@GMan - Pero si está inicializando la variable a algún otro valor unas líneas más tarde, sin hacer nada con la variable intermedia, es innecesario. – Jesper

0

Hay varias buenas respuestas a esta pregunta, uno de ellos ha sido aceptado. Voy a responder de todos modos con el fin de ampliar los aspectos prácticos.

Sí, es una buena práctica inicializar los punteros a NULL, así como establecer punteros a NULL después de que ya no se necesiten (es decir, se liberen).

En cualquier caso, es muy práctico poder probar un puntero antes de desreferenciarlo. Digamos que tiene una estructura que se parece a esto:

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

A continuación, escribe una aplicación que genera varios hilos, todos los cuales operan en una sola estructura foo asignado (con seguridad) a través del uso de la exclusión mutua.

El subproceso A obtiene un bloqueo en foo, incrementa el contador y comprueba si hay un valor en ch.No encuentra uno, por lo que no asigna (ni modifica) el contexto. En cambio, almacena un valor en ch para que el hilo B pueda hacer este trabajo en su lugar.

Subproceso B Ve que el contador se ha incrementado, toma nota de un valor en ch pero no está seguro si el subproceso A ha hecho algo con el contexto. Si el contexto se inicializó como NULL, el hilo B ya no tiene que importar qué hilo A hizo, sabe que el contexto es seguro para la desreferencia (si no es NULO) o asignar (si es NULO) sin fugas.

El hilo B hace su trabajo, el hilo A lee su contexto, lo libera y luego lo reinicializa a NULO.

El mismo razonamiento se aplica a las variables globales, sin el uso de subprocesos. Es bueno poder probarlos en varias funciones antes de desreferenciarlos (o intentar asignarlos causando una fuga y un comportamiento indefinido en su programa).

Cuando se pone tonto es cuando el alcance del puntero no va más allá de una sola función. Si tiene una función única y no puede realizar un seguimiento de los punteros dentro de ella, generalmente esto significa que la función debe volver a factorizarse. Sin embargo, no hay nada de malo en inicializar un puntero en una sola función, aunque solo sea para mantener hábitos uniformes.

La única vez que he visto un caso de 'feo' de depender de un puntero inicializado (antes y después de su uso) está en algo como esto:

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

No sólo se dereferencing un tipo de puntero hizo juegos de palabras mal visto en plataformas estrictas, el código anterior hace que sea aún más peligroso(), porque los que llaman tendrán algún delirio de seguridad. No puede confiar en una práctica 'al por mayor' a menos que esté seguro de que todas las operaciones están de acuerdo.

Probablemente mucha más información de la que realmente quería.

3

Otra opción es no definir la variable hasta el lugar en su código donde tiene acceso a su valor inicial. Así que en lugar de hacerlo:

char *name = NULL; 

... 

name = initial_value; 

que cambiaría a que:

... 

char *name = initial_value; 

El compilador entonces intentará evitar que se hace referencia a la variable en la parte del código en el que no tiene ningún valor. Dependiendo de las especificaciones de su código, esto no siempre es posible (por ejemplo, el valor inicial se establece en un ámbito interno pero la variable tiene una vida útil diferente), mover la definición lo más tarde posible en el código evita errores.

Dicho esto, esto solo está permitido comenzando con el estándar c99 (también es válido C++). Para habilitar las características de C99 en gcc, se tendrá que hacer, ya sea:

gcc -std=gnu99 

o si no desea que las extensiones del CCG a la norma:

gcc -std=c99 
3

No, no es una buena práctica , si entendí tu contexto correctamente.

Si su código realmente depende de que el mgt_dev_name tenga el valor inicial de un puntero nulo, entonces, por supuesto, incluir el inicializador en la declaración es una muy buena idea. Es decir.si lo tiene que hacer esto de todos modos

char *mgt_dev_name; 

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

entonces siempre es una mejor idea de utilizar la inicialización en lugar de asignación

char *mgt_dev_name = NULL; 

Sin embargo, la inicialización sólo es bueno cuando se puede inicializar el objeto con una significativoútil valor. Un valor que realmente necesitará En general, esto solo es posible en idiomas que permiten declaraciones en cualquier punto del código, C99 y C++ son buenos ejemplos de tales idiomas. En el momento en que necesita su objeto, normalmente ya conoce el inicializador apropiado para ese objeto, por lo que puede generar fácilmente una declaración elegante con un buen inicializador.

En C89/90, por el contrario, las declaraciones solo se pueden realizar al principio del bloque. En ese punto, en general, no tendrá inicializadores significativos para todos sus objetos. ¿Debería inicializarlos con algo, cualquier cosa (como 0 o NULL) simplemente para tenerlos inicializados? ¡¡¡No!!! Nunca hagas cosas sin sentido en tu código. No mejorará nada, independientemente de lo que puedan decirle varias "guías de estilo". En realidad, la inicialización sin sentido podría cubrir errores en su código, dificultando su descubrimiento y reparación.

Tenga en cuenta que incluso en C89/90 siempre es beneficioso esforzarse por una mejor localidad de declaraciones. Es decir. una conocida pauta de buenas prácticas dice: siempre haga que sus variables sean lo más locales posible. No acumule todas las declaraciones de objeto locales al principio de la función, sino que muévalas al principio del bloque más pequeño que abarque toda la vida del objeto lo más posible. Algunas veces incluso podría ser una buena idea introducir un bloqueo ficticio, de otro modo innecesario, solo para mejorar la localidad de las declaraciones. Seguir esta práctica te ayudará a proporcionar buenos inicializadores útiles para tus objetos en muchos casos (si no en la mayoría). Pero algunos objetos permanecerán sin inicializar en C89/90 solo porque no tendrá un buen inicializador para ellos en el momento de la declaración. No intente inicializarlos con "algo" solo por el hecho de tenerlos inicializados. Esto no logrará absolutamente nada bueno, y en realidad podría tener consecuencias negativas.

Tenga en cuenta que algunas herramientas de desarrollo modernas (como MS Visual Studio 2005, por ejemplo) capturarán el acceso en tiempo de ejecución a variables no inicializadas en la versión de depuración del código. Es decir, estas herramientas pueden ayudarlo a detectar situaciones cuando accede a una variable antes de que tenga la oportunidad de adquirir un valor significativo, lo que indica una falla en el código. Pero al realizar una inicialización prematura incondicional de sus variables, básicamente se elimina esa capacidad de la herramienta y se barren estos errores debajo de la alfombra.

0

estilos preferidos:

en C: char * c = NULL;

en C++: char * c = 0;

0

Mi razonamiento es que si no inicializa con NULL, y luego olvida inicializar por completo, la tipos de errores que obtendrá en su código cuando la eliminación de referencias es mucho más difícil de rastrear debido a la posible basura almacenada en la memoria en ese punto. Por otro lado, si se inicializa al NULL, la mayoría de las veces obtendrá un segmentation fault, lo cual es mejor, considerando la alternativa.

0

Inicializar variables incluso cuando no las necesita inicializar de inmediato es una buena práctica.Por lo general, inicializamos punteros a NULL, int a 0 y flota a 0.0 como una convención.

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