¿Cuál es el propósito de asignar una cantidad específica de memoria para matrices en C ++?

Soy un estudiante que toma una clase sobre Data Structures en C ++ este semestre y me encontré con algo que no entiendo muy bien esta noche. Digamos que debía crear un puntero a una matriz en el montón:

int* arrayPtr = new int [4]; 

Puedo acceder a esta matriz usando la syntax del puntero

 int value = *(arrayPtr + index); 

Pero si tuviera que agregar otro valor a la posición de memoria inmediatamente después del final del espacio asignado para la matriz, entonces podría acceder a ella

 *(arrayPtr + 4) = 0; int nextPos = *(arrayPtr + 4); //the value of nextPos will be 0, or whatever value I previously filled that space with 

La posición en la memoria de * (arrayPtr + 4) está más allá del final del espacio asignado para la matriz. Pero por lo que yo entiendo, lo anterior aún no causaría ningún problema. Así que, aparte de ser un requisito de C ++, ¿por qué incluso dar a los arrays un tamaño específico al declararlos?

Cuando pasa el final de la memoria asignada, en realidad está accediendo a la memoria de algún otro objeto (o memoria que está libre en este momento, pero que podría cambiar más adelante). Por lo tanto, le causará problemas. Especialmente si intentas escribirle algo.

Puedo acceder a esta matriz usando la syntax del puntero

int value = * (arrayPtr + index);

Sí, pero no lo hagas Utilice arrayPtr[index]

La posición en la memoria de * (arrayPtr + 4) está más allá del final del espacio asignado para la matriz. Pero por lo que yo entiendo, lo anterior aún no causaría ningún problema.

Entiendes mal. Oh, muy mal. Estás invocando un comportamiento indefinido y un comportamiento indefinido no está definido. Puede funcionar durante una semana, luego romper un día la próxima semana y te quedarás preguntándote por qué. Si no conoce el tamaño de la colección de antemano, use algo dynamic como un vector lugar de una matriz.

Sí, en C / C ++ puede acceder a la memoria fuera del espacio que afirma haber asignado. A veces. Esto es lo que se conoce como comportamiento indefinido .

Básicamente, le ha dicho al comstackdor y al sistema de administración de memoria que desea espacio para almacenar cuatro enteros, y el sistema de administración de memoria asignó espacio para almacenar cuatro enteros. Te dio un puntero a ese espacio. En la contabilidad interna del administrador de memoria, esos bytes de RAM ahora están ocupados, hasta que usted llame delete[] arrayPtr; .

Sin embargo, el administrador de memoria no ha asignado ese byte siguiente para usted. No tiene ninguna forma de saber, en general, cuál es el siguiente byte o a quién pertenece.

En un progtwig de ejemplo simple como su ejemplo, que solo asigna unos pocos bytes, y no asigna nada más, es probable que el siguiente byte pertenezca a su progtwig y no esté ocupado. Si esa matriz es la única memoria dinámicamente asignada en su progtwig, entonces es probable , tal vez sea seguro ejecutar el final.

Pero en un progtwig más complejo, con múltiples asignaciones de memoria dinámica y desasignaciones, especialmente cerca de los bordes de las páginas de memoria, realmente no hay una buena forma de saber qué contiene cualquier byte fuera de la memoria que solicitó. Entonces cuando escribes en bytes fuera de la memoria que pediste en new podrías estar escribiendo básicamente cualquier cosa.

Aquí es donde entra el comportamiento indefinido . Debido a que no sabes qué hay en ese espacio en el que escribiste, no sabes qué sucederá como resultado. Aquí hay algunos ejemplos de cosas que podrían suceder:

  • La memoria no fue asignada cuando escribiste. En ese caso, los datos están bien, y nada malo parece suceder. Sin embargo, si una asignación de memoria posterior utiliza ese espacio, se perderá todo lo que haya intentado colocar allí.

  • La memoria fue asignada cuando le escribiste. En ese caso, felicitaciones, simplemente sobrescribió algunos bytes aleatorios de alguna otra estructura de datos en otro lugar de su progtwig. Imagine reemplazar una variable en algún lugar de uno de sus objetos con datos aleatorios, y considere lo que eso significaría para su progtwig. Tal vez una lista en otro lado ahora tiene un recuento incorrecto. Tal vez una cadena ahora tiene algunos valores aleatorios para los primeros pocos caracteres, o ahora está vacía porque reemplazó esos caracteres con ceros.

  • La matriz se asignó al borde de una página, por lo que los siguientes bytes no pertenecen a su progtwig. La dirección está fuera de la asignación de su progtwig. En este caso, el sistema operativo detecta que usted accede a la memoria aleatoria que no es suya, y finaliza su progtwig inmediatamente con SIGSEGV .

Básicamente, un comportamiento indefinido significa que estás haciendo algo ilegal, pero debido a que C / C ++ está diseñado para ser rápido, los diseñadores del lenguaje no incluyen una verificación explícita para asegurarte de no romper las reglas, como otros lenguajes (por ejemplo, Java). , C #). Simplemente enumeran el comportamiento de romper las reglas como indefinido, y luego las personas que hacen los comstackdores pueden tener el resultado más simple, un código más rápido, ya que no se realizan verificaciones de límites de matriz, y si rompe las reglas, es su propio problema.

Entonces sí, esto a veces funciona, pero nunca confíes en él.

No causaría ningún problema en una configuración puramente abstracta, donde solo se preocupe si la lógica del algoritmo es sólida. En ese caso, no hay ninguna razón para declarar el tamaño de una matriz en absoluto. Sin embargo, su computadora existe en el mundo físico y solo tiene una cantidad limitada de memoria. Cuando asigna memoria, le pide al sistema operativo que le permita usar parte de la memoria finita de la computadora. Si vas más allá de eso, el sistema operativo debería detenerte, generalmente matando tu proceso / progtwig.

Sí, debe escribirlo como arrayptr [índice] porque la posición en la memoria de * (arrayptr + 4) está más allá del final del espacio que ha asignado para la matriz. Es la falla en C ++ que el tamaño de la matriz no se puede extender una vez asignada.