Incremento del puntero de matriz más allá del último elemento
arrays pointers (5)
Me estaba divirtiendo un poco con la programación en C y los punteros de matriz.
¿Alguien puede explicar qué sucede cuando avanzo un puntero de matriz más allá del tamaño de la matriz?
Parece que estoy accediendo a la celda de memoria que está directamente después de la matriz, pero solo quiero estar seguro.
- ¿Estos números significan algo?
- ¿Por qué el último número es un cero?
- ¿Debería un programa poder acceder a la memoria que no ha asignado?
¡Muchas preguntas!
int arr[] = { 1, 2, 3, 4, 5 };
int *xPtr = arr;
for(int i = 0; i < 10; i++) {
printf("current pointer is %d/n", *xPtr++);
}
Resultados en:
current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5
current pointer is 0
current pointer is 127926431
current pointer is -759946469
current pointer is -492049712
current pointer is 32766
Esta fue la única forma en que encontré para iterar correctamente a través de la matriz. ¿Es esto correcto?
int arraySize = sizeof(arr) / sizeof(int);
for(int i = 0; i < arraySize; i++) {
printf("current pointer is %d/n", *xPtr++);
}
Resultados en:
current pointer is 1
current pointer is 2
current pointer is 3
current pointer is 4
current pointer is 5
C no verifica los límites de la matriz. Entonces, incluso si accede a una matriz más allá de su tamaño declarado, no dará ningún error. Las respuestas a sus preguntas, según yo:
- No, los números son puramente basura.
- El último número puede ser cualquier cosa (basura incluyendo cero). Según el estándar ISO C, se llama Comportamiento indefinido.
- ¡No, no debería! ¡Pero C es un lenguaje de la época en que los compiladores eran lentos e incluso guardar 3-4 instrucciones en la Asamblea significaba mucho!
Cuando incrementa el puntero más allá del tamaño de la matriz, sí, está accediendo a la memoria justo después de la matriz. Contendrá cualquier valor aleatorio llamado valor basura .
Estos valores basura no son de utilidad en su programa y debe evitar acceder a ellos utilizando el siguiente bucle for como se menciona en su respuesta:
int arraySize = sizeof(arr) / sizeof(int);
for(int i = 0; i < arraySize; i++)
{
printf("current pointer is %d/n", *xPtr++);
}
Estos valores no significan nada. Son solo valores que ya estaban almacenados en esa ubicación de memoria en particular antes de acceder a ella.
Déjame guiarte a través de un ejemplo. Considere una matriz 2D y un puntero apuntando a ella
int a[2][2];
int *p = &a[0][0];
Ahora, observe detenidamente los índices.
Si intenta
p+0
apuntará a
a[0][0]
,
p+1
apuntará a
a[0][1]
.
Pero si prueba
p+2
ahora, apuntará a
a[1][0]
ya que esta es solo la siguiente ubicación de memoria.
Y más allá de
p+3
es decir, de
p+4
todos los valores serán basura.
Depende de dónde se declare la matriz (más precisamente la ubicación de almacenamiento de la matriz). Si declaró que cualquier tipo de matriz sin inicialización es global o estática, por defecto se inicializa a cero; de lo contrario, si lo declara dentro de cualquier función, es decir, auto sin inicialización, contendrá el valor basura. Aquí en su programa, cuando accede a una ubicación en la memoria fuera de los límites de la matriz, el valor que obtiene el programa es un valor basura. Porque de forma predeterminada, cada ubicación de memoria contiene valor de basura. Al inicializar una matriz, se asigna un bloque de memoria con los valores que proporcionó. La segunda cosa es que no hay mejor iteración de matriz; Depende totalmente de ti.
Al incrementar un puntero, se incrementa por el tamaño del objeto al que apunta, apuntando al siguiente elemento de la matriz. Como por ejemplo:
data_type arr[10];
El incremento del puntero se realizará por sizeof (data_type). En C el acceso a la memoria no asignada puede generar excepciones / advertencias.
Está accediendo a la memoria fuera de la matriz. La matriz tiene solo 5 elementos, y aumenta el puntero más allá de eso, y lo desreferencia. En realidad, hay dos tipos de cosas malas aquí: está desreferenciando fuera de la matriz, pero también está aumentando el puntero más de un paso más allá del final de la matriz. Ninguno de los dos está permitido.
Este es un comportamiento indefinido, por lo que podría pasar cualquier cosa. En este caso, parece que simplemente está obteniendo el contenido de la memoria después de la matriz, interpretada como ints. En el contexto de su programa C, son solo valores basura, porque una vez que tiene un comportamiento indefinido en C, todas las apuestas están desactivadas, el programa podría haberse bloqueado o algo peor.
Si desea darle sentido a un programa que tiene UB, debe compilarlo y luego mirar el código de ensamblaje de esa compilación en particular. Solo tenga en cuenta que la próxima vez que lo compile, el resultado podría ser diferente (modificadores del compilador, actualizaciones del compilador o de la biblioteca, una computadora diferente ...), y el nuevo código de ensamblaje podría tener un comportamiento totalmente diferente (porque el código C tenía UB). En general, esto no es útil, UB es UB y rara vez tiene sentido intentar razonar sobre lo que hace.
C no tiene comprobación de límites de matriz, por lo que el compilador de C no realiza ninguna comprobación. En un sistema operativo de PC moderno con protección de memoria, el sistema operativo matará el programa si intenta acceder a la memoria que no se le proporciona, pero tiene una resolución aproximada (por ejemplo, páginas de 4 KB), y puede haber mucha memoria perteneciente a su programa de todos modos, por lo que el sistema operativo podría no notar nada malo para megabytes después de la matriz.
La segunda versión se ve bien.
Solo recuerde que
sizeof
funciona así solo para matrices reales, no para punteros, y no para parámetros de matriz de funciones (porque en realidad son punteros, no matrices, a pesar de la sintaxis).
*xPtr++
comprender el incremento del puntero
*xPtr++
funciona incrementando el tamaño del objeto al que apunta.
En el caso de que sea un
int
, cada operación hace un incremento del tamaño de
sizeof(int)
dependiendo del tamaño de
int
en su sistema.
Como su matriz tiene solo 5 elementos, en una máquina con 4 bytes
int
, no puede incrementarla más de 5 cuentas.
Más allá de eso, está accediendo a la memoria que no está asignada para la matriz y accediendo al valor desde esas ubicaciones invoca un comportamiento indefinido.
Su segundo enfoque parece correcto, con una solución simple use el tipo de retorno de
sizeof()
de
int
a
size_t
aunque se produce una conversión implícita en la asignación
size_t arraySize = sizeof(arr) / sizeof(int);
for(size_t i = 0; i < arraySize; i++) {
printf("current pointer %p and value is %d/n", (void*)xPtr, *xPtr++);
}