2010-02-19 13 views
11

al asignar memoria dinámica en el montón usando un puntero,Asignación dinámica de memoria pregunta

char *buffer_heap = new char[15]; 

que estaría representada en la memoria como:

ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þþþ 

¿Por qué no haya un terminador NULL carácter al final en lugar de ýýýý «« «« «« «« þþþ?

+3

En primer lugar, dice que esto es aún una cadena? Para el compilador, solo quieres 15 bytes sin formato de memoria. Si quieres una cadena, usa 'std :: string'. Entonces, ¿qué es esta información? Es lo que sea que haya estado allí. La mayoría de los compiladores realmente completarán estos datos con datos de depuración u otra información, por lo que cuando use datos no inicializados, es probable que tenga un patrón consistente. – GManNickG

+8

No sé por qué las personas votan negativamente, es una pregunta completamente válida. El hecho de que el OP malinterprete algo no significa que debemos castigarlo por ello. – GManNickG

+0

Relacionados: http://stackoverflow.com/questions/2029651/how-do-you-initialise-a-dynamic-array-in-c http://stackoverflow.com/questions/958549/dynamically-allocated-char Puede Por mi vida encontrar un duplicado exacto, pero * juro * que hay uno ... – dmckee

Respuesta

22

Í es byte 0xCD, que el asignador de depuración de Windows escribe en sus 15 bytes de memoria para indicar que se trata de una memoria de montón no inicializada. La pila no inicializada sería 0xCC. La idea es que si alguna vez lees la memoria e inesperadamente obtienes este valor, puedes pensar: "mmm, probablemente he olvidado inicializar esto". Además, si lo lee como un puntero y lo desreferencia, Windows bloqueará su proceso, mientras que si un buffer no inicializado estuviera lleno de valores aleatorios o arbitrarios, a veces por casualidad obtendría un puntero válido, y su código podría causar todo tipos de problemas C++ no dice qué valores contiene la memoria no inicializada, y los asignaturas sin depuración no perderán tiempo llenando la memoria con valores especiales para cada asignación, por lo que nunca debe confiar en que ese valor esté allí.

Esto va seguido de 4 bytes de ý (byte 0xFD), que el asignador de depuración de Windows usa para indicar una región fuera de límites al final de un búfer. La idea es que si alguna vez te encuentras en el depurador escribiendo en una región que se ve así, puedes pensar "mmm, probablemente haya invadido mi memoria intermedia aquí".Además, si el valor ha cambiado cuando se libera el búfer, el asignador de memoria puede advertirle que su código es incorrecto.

«es byte 0xAB y þ es 0xFE. Es de suponer que estos también tienen la intención de llamar la atención (no son punteros plausibles o compensaciones, por lo que no forman parte de la estructura del montón). No sé lo que significan, posiblemente más datos de guardia como el 0xFD.

Finalmente, supongo que ha encontrado 0 byte, el decimosexto byte más allá del final de su búfer de 15 bytes (es decir, el recuento de 31 bytes desde el inicio).

Hacer la pregunta como "C++" sin mencionar que estás en Windows sugiere que así es como se comporta C++. No lo es, es cómo se comporta una implementación de C++, con opciones de compilador particulares y/o DLL vinculados. C++ no le permite leer más allá del final del búfer, Microsoft solo está siendo amable con usted y le permite salirse con la suya sin que se cuelgue o empeore.

+3

+1 por ser elaborado acerca de cada código hexadecimal, particularmente para decir sobre los trucos del depurador; también para explicar sobre la disciplina de etiquetado – legends2k

+0

Agregué la etiqueta visual-C++ porque tiene razón, la pregunta lo necesitaba. El OP probablemente no sabía que esto era un comportamiento específico de implementación. – Omnifarious

6

No ha inicializado esa memoria. Solo está viendo lo que ya estaba allí ...

1

Si bien cada cadena de estilo C se representa como una secuencia de caracteres, no todas las secuencias de caracteres son cadenas.

Normalmente, el \ 0 aparece cuando asigna directamente un literal de cadena, o cuando lo agrega usted mismo. Y solo tiene sentido si trata esa matriz como una cadena con funciones que tienen en cuenta el \ 0.

Si solo asigna la memoria y no la inicializa, está llena de elementos aleatorios. Puede haber un 0 allí o no, tendrás que poner algo significativo allí en un paso posterior. Depende de ti si quieres hacer que algo sea una cadena o no.

+0

¿por qué siempre se dice "sí" «« «« «« «« þþþ? – cpx

+3

@ Dave17: No hay * siempre * los mismos datos allí. Haz un ciclo para hacer 100 nuevas asignaciones de char [15] y mira. Si * es * siempre el mismo, entonces podría ser un patrón de depuración utilizado por su compilador. –

+0

Estoy usando VS-2005, probé con 1000 caracteres nuevos y sigue siendo el mismo. – cpx

1

Porque char es un tipo nativo, no está inicializado. Así es C++ (es un legado de C).

Basta con aceptar eso y 0 terminan usted mismo:

char *buffer_heap = new char[15]; 
*buffer_heap = '\0'; 

o si desea toda la memoria intermedia inicializado:

std::fill(buffer, buffer + 15, 0); 
4

Es necesario inicializarlo. tipos incorporados se pueden inicializar a cero mediante una llamada explícita al constructor por defecto:

char *b = new char[15](); 
1

Sólo será inicializado si asigna un tipo que ha inicializado. De lo contrario, si quiere algunos valores significativos allí, tendrá que escribirlos en usted mismo.

Por otro lado, la mejor respuesta es que simplemente no deberías hacer esto en primer lugar. Olvida que existe new[] y no mires atrás.

+0

Solo para usuarios avanzados: recuerde que 'new []' existe, pase un rato averiguando cómo anular la ubicación y el arreglo nuevo y elimínelo, luego simplemente use un vector de todos modos. –

+0

@Steve: o como dice la antigua línea sobre optimización: regla n. ° 1: no lo haga. Regla n. ° 2 (solo para programadores avanzados): no lo hagas ahora. –

+0

Regla # 3 (para programadores super-avanzados): deja de jugar y envía lo sangriento ;-) –

0

En GNU C++ (g ++) en Linux, este programa sale bastante rápido:

#include <algorithm> 
#include <iterator> 
#include <vector> 
#include <cstddef> 
#include <cstdlib> 
#include <iostream> 

namespace { 

class rand_functor { 
public: 
    int operator()() const { return ::std::rand(); } 
}; 

} 

int main() 
{ 
    using ::std::cout; 
    using ::std::vector; 
    using ::std::ostream_iterator; 
    using ::std::generate; 
    using ::std::equal; 
    using ::std::copy; 

    char *tmp = new char[1000]; 
    // This just fills a bunch of memory with random stuff, then deallocates it 
    // in the hopes of making a match more likely. 
    generate(tmp, tmp+1000, rand_functor()); 
    delete[] tmp; 
    vector<char *> smalls; 
    smalls.push_back(new char[15]); 
    do { 
     smalls.push_back(new char[15]); 
    } while (equal(smalls[0], smalls[0]+15, smalls[smalls.size() - 1])); 
    cout << "  In one allocation I got: ["; 
    copy(smalls[0], smalls[0]+15, ostream_iterator<char>(cout)); 
    cout << "]\nAnd in another allocation I got: ["; 
    copy(smalls[smalls.size() - 1], smalls[smalls.size() - 1]+15, 
     ostream_iterator<char>(cout)); 
    cout << "]\n"; 
    cout << "It took " << smalls.size() << " allocations to find a non-matching one.\n"; 
    return 0; 
} 
Cuestiones relacionadas