Recientemente comencé a aprender C ++, y como la mayoría de las personas (según lo que he estado leyendo) estoy luchando con los punteros.
No en el sentido tradicional, entiendo lo que son, y por qué se usan, y cómo pueden ser útiles, sin embargo, no puedo entender cómo sería útil incrementar los punteros, ¿alguien puede dar una explicación de cómo incrementar un puntero es un concepto útil y idiomático C ++?
Esta pregunta surgió después de que comencé a leer el libro Un recorrido por C ++ de Bjarne Stroustrup, me recomendaron este libro, porque estoy bastante familiarizado con Java, y los chicos de Reddit me dijeron que sería un buen libro de 'cambio' .
Respuestas:
Cuando tiene una matriz, puede configurar un puntero para apuntar a un elemento de la matriz:
Aquí
p
apunta al primer elemento dea
, que esa[0]
. Ahora puede incrementar el puntero para señalar el siguiente elemento:Ahora
p
apunta al segundo elemento,a[1]
. Puede acceder al elemento aquí usando*p
. Esto es diferente de Java, donde tendría que usar una variable de índice entero para acceder a elementos de una matriz.Incrementar un puntero en C ++ donde ese puntero no apunta a un elemento de una matriz es un comportamiento indefinido .
fuente
El aumento de punteros es idiomático C ++, porque la semántica de puntero refleja un aspecto fundamental de la filosofía de diseño detrás de la biblioteca estándar C ++ (basada en STL de Alexander Stepanov )
El concepto importante aquí es que el STL está diseñado alrededor de contenedores, algoritmos e iteradores. Los punteros son simplemente iteradores .
Por supuesto, la capacidad de incrementar (o sumar / restar) punteros se remonta a C. Se pueden escribir muchos algoritmos de manipulación de cadenas en C simplemente usando la aritmética de punteros. Considere el siguiente código:
Este código usa aritmética de puntero para copiar una cadena en C terminada en nulo. El ciclo termina automáticamente cuando encuentra el nulo.
Con C ++, la semántica de puntero se generaliza al concepto de iteradores . La mayoría de los contenedores estándar de C ++ proporcionan iteradores, a los que se puede acceder a través de las funciones
begin
yend
miembro. Los iteradores se comportan como punteros, en el sentido de que pueden incrementarse, desreferenciarse y, a veces, disminuirse o avanzarse.Para iterar sobre un
std::string
, diríamos:Incrementamos el iterador al igual que incrementaríamos un puntero a una cadena en C simple. La razón por la que este concepto es poderoso es porque puede usar plantillas para escribir funciones que funcionarán para cualquier tipo de iterador que cumpla con los requisitos de concepto necesarios. Y este es el poder de la STL:
Este código copia una cadena en un vector. La
copy
función es una plantilla que funcionará con cualquier iterador que admita el incremento (que incluye punteros simples). Podríamos usar la mismacopy
función en una cadena en C simple:Podríamos usar
copy
en unostd::map
o unostd::set
o cualquier contenedor personalizado que admita iteradores.Tenga en cuenta que los punteros son un tipo específico de iterador: iterador de acceso aleatorio , lo que significa que admiten el incremento, la disminución y el avance con el operador
+
y-
. Otros tipos de iteradores solo admiten un subconjunto de semántica de puntero: un iterador bidireccional admite al menos incrementos y decrementos; un iterador directo admite al menos incrementos. (Todos los tipos de iteradores admiten la desreferenciación). Lacopy
función requiere un iterador que al menos admita el incremento.Puede leer sobre diferentes conceptos de iterador aquí .
Por lo tanto, incrementar los punteros es una forma idiomática de C ++ de iterar sobre una matriz C, o acceder a elementos / compensaciones en una matriz C.
fuente
La aritmética del puntero está en C ++ porque estaba en C. La aritmética del puntero está en C porque es un modismo normal en ensamblador .
Hay muchos sistemas en los que el "registro de incremento" es más rápido que "cargar el valor constante 1 y agregar al registro". Además, bastantes sistemas le permiten "cargar DWORD en A desde la dirección especificada en el registro B, y luego agregar sizeof (DWORD) a B" en una sola instrucción. En estos días puede esperar que un compilador optimizador solucione esto por usted, pero esta no era realmente una opción en 1973.
Esta es básicamente la misma razón por la que las matrices C no tienen límites de verificación y las cadenas C no tienen un tamaño incrustado en ellas: el lenguaje se desarrolló en un sistema donde cada byte y cada instrucción contaban.
fuente