Principiante C ++ variable local sin inicializar

Tengo una función:

VOID GetOSVersion(PDWORD major, PDWORD minor, PDWORD build) { OSVERSIONINFO osver; ZeroMemory(&osver, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); if(major) *major = osver.dwMajorVersion; if(minor) *minor = osver.dwMinorVersion; if(build) *build = osver.dwBuildNumber; } 

Y quería invocarlo así:

 PDWORD major; PDWORD minor; PDWORD build; GetOSVersion(major, minor, build); 

Me sale un error: variable local no inicializada: para todos los tres argumentos. En mi cabeza fue como: declaro major, minor, build, y se completan en la función. El espacio ya está asignado para ellos durante las primeras tres líneas del código de invocación.

Seguramente me falta algo aquí. ¿Alguien podría explicar esto por mí?

el problema está ahí:

 DWORD major; DWORD minor; DWORD build; GetOSVersion(&major, &minor, &build); 

Fijar:

 VOID GetOSVersion(PDWORD major, PDWORD minor, PDWORD build) { OSVERSIONINFO osver = {}; osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); if(major) *major = osver.dwMajorVersion; if(minor) *minor = osver.dwMinorVersion; if(build) *build = osver.dwBuildNumber; } DWORD major = 0; DWORD minor = 0; DWORD build = 0; GetOSVersion(&major, &minor, &build); 

PDWORD es un puntero a DWORD. Los tres parámetros son parámetros de salida. En C / C ++, es un uso común: si desea devolver más de un valor de una función, necesita pasar el puntero (o referencia también en el caso de c ++) a una variable:

 int var = 0; if(some_function_that_can_fail_and_write_result(&var)) ;//do something 

En su caso, está pasando un puntero no inicializado a una función por valor. Es lo mismo que:

 void foo(int parameter); // ... int a; foo(a); 

Tienes muchas maneras:

Pase el puntero no inicializado por referencia:

 VOID GetOSVersion(PDWORD& major, PDWORD&, PDWORD&) { //... major = new DWORD(osver.dwMajorVersion); } // usage: PDWORD major; GetOSVersion(major, ....); //... delete major; 

Pase todos los parámetros por referencia:

 VOID GetOSVersion(DWORD& major, DWORD&, DWORD&) { //... major = osver.dwMajorVersion; } // usage: DWORD major = 0; GetOSVersion(major, ....); 

Use su versión de GetOSVersion (), pero con la solución en esta respuesta al principio

Está cometiendo el error que muchos cometen cuando se trata de funciones que requieren argumentos de puntero.

Cuando una función requiere un puntero como argumento, no significa que declara a ciegas un puntero y lo pasa a la función. Lo que la función está pidiendo es una address-of una entidad válida existente.

 DWORD major, minor, build; GetOSVersion(&major, &minor, &build); 

Los DWORD anteriores son válidos, y todo lo que se hace es pasar la dirección de estas variables a la función.

El otro error que está relacionado con esto (no es un error, ya que dará los resultados deseados, pero sigue siendo un “error”) es declarar un puntero, hacer que apunte a un lugar válido, y luego pasarlo a la función. En otras palabras:

 PDWORD major, minor, build; major = new DWORD; minor = new DWORD; build = new DWORD; GetOSVersion(major, minor, build); delete major; delete minor; delete build; 

He visto el código escrito de esta manera. Esto indica que el progtwigdor no tiene una comprensión clara de lo que significa cuando una función requiere un puntero como argumento. El progtwigdor cree que se debe declarar un puntero, hacer que apunte a algún lugar válido y luego pasar este puntero. Sí, obtiene los resultados sin fallar, pero es una pérdida de tiempo llamar al asignador.

Entonces, la forma más fácil es el primer ejemplo anterior. Simplemente declare tipos que no sean punteros y simplemente pase la dirección.

Probablemente quisiste tener tus declaraciones de variables y llamar a tu función así

 DWORD major; DWORD minor; DWORD build; GetOSVersion(&major, &minor, &build); 

Utiliza punteros para hacer referencia a los parámetros de salida, por lo tanto, estos deben señalarlos a direcciones de memoria válidas. Puede referirse a esas variables para obtener un puntero válido utilizando el operador ‘address-of’ ( & ) como se muestra arriba.


Con c ++ puede usar parámetros de referencia, lo que aclarará un poco las cosas

 VOID GetOSVersion(DWORD& major, DWORD& minor, DWORD& build) { OSVERSIONINFO osver; ZeroMemory(&osver, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); // Note there's no check needed if the pointers are valid! major = osver.dwMajorVersion; minor = osver.dwMinorVersion; build = osver.dwBuildNumber; } DWORD major; DWORD minor; DWORD build; GetOSVersion(major, minor, build); 

No es necesario llamar al new() asignador (y molestarse con la gestión de asignación de memoria dinámica correcta) con cualquiera de las muestras anteriores en primer lugar.

Esos son punteros. No están apuntando a ningún recuerdo que hayas asignado. No se “llenan” en la función, se acostumbran a acceder a la memoria (no inicializada).

Probablemente no recibas un error sino una advertencia (pero es posible que hayas configurado tu comstackdor para tratar las advertencias como errores).

Si se ejecuta, su progtwig segmentará la falla porque está escribiendo en la memoria apuntada por ellos, pero como no están inicializados, contienen direcciones inválidas / aleatorias.

Solución posible

 PDWORD major = new DWORD; PDWORD minor = new DWORD; PDWORD build = new DWORD; 

asumiendo que PDWORD se define como *DWORD .

¡No olvides las eliminaciones!

editar: en realidad, es mucho más sensato asignarlos a la stack: consulte la respuesta del usuario2451677.