logo

Punteros de C++

Los punteros son representaciones simbólicas de direcciones. Permiten que los programas simulen llamadas por referencia, así como también creen y manipulen estructuras de datos dinámicas. Iterar sobre elementos en matrices u otras estructuras de datos es uno de los usos principales de los punteros.

La dirección de la variable con la que está trabajando se asigna a la variable de puntero que apunta al mismo tipo de datos (como un int o una cadena).



matriz de cadenas en lenguaje c

Sintaxis:

datatype *var_name; int *ptr; // ptr can point to an address which holds int data>
Cómo funciona el puntero en C++

¿Cómo utilizar un puntero?

  • Definir una variable de puntero
  • Asignar la dirección de una variable a un puntero usando el operador unario (&) que devuelve la dirección de esa variable.
  • Accediendo al valor almacenado en la dirección mediante el operador unario (*) que devuelve el valor de la variable ubicada en la dirección especificada por su operando.

La razón por la que asociamos el tipo de datos con un puntero es que sabe en cuántos bytes se almacenan los datos . Cuando incrementamos un puntero, aumentamos el puntero según el tamaño del tipo de datos al que apunta.

Punteros en C++C++
// C++ program to illustrate Pointers #include  using namespace std; void geeks() {  int var = 20;  // declare pointer variable  int* ptr;  // note that data type of ptr and var must be same  ptr = &var;  // assign the address of a variable to a pointer  cout << 'Value at ptr = ' << ptr << '
';  cout << 'Value at var = ' << var << '
';  cout << 'Value at *ptr = ' << *ptr << '
'; } // Driver program int main()  {   geeks();   return 0; }>

Producción
Value at ptr = 0x7ffe454c08cc Value at var = 20 Value at *ptr = 20>

Referencias y sugerencias

Hay 3 formas de pasar argumentos de C++ a una función:



  • Llamada por valor
  • Llamada por referencia con un argumento de puntero
  • Llamada por referencia con un argumento de referencia
C++
// C++ program to illustrate call-by-methods #include  using namespace std; // Pass-by-Value int square1(int n) {  // Address of n in square1() is not the same as n1 in  // main()  cout << 'address of n1 in square1(): ' << &n << '
';  // clone modified inside the function  n *= n;  return n; } // Pass-by-Reference with Pointer Arguments void square2(int* n) {  // Address of n in square2() is the same as n2 in main()  cout << 'address of n2 in square2(): ' << n << '
';  // Explicit de-referencing to get the value pointed-to  *n *= *n; } // Pass-by-Reference with Reference Arguments void square3(int& n) {  // Address of n in square3() is the same as n3 in main()  cout << 'address of n3 in square3(): ' << &n << '
';  // Implicit de-referencing (without '*')  n *= n; } void geeks() {  // Call-by-Value  int n1 = 8;  cout << 'address of n1 in main(): ' << &n1 << '
';  cout << 'Square of n1: ' << square1(n1) << '
';  cout << 'No change in n1: ' << n1 << '
';  // Call-by-Reference with Pointer Arguments  int n2 = 8;  cout << 'address of n2 in main(): ' << &n2 << '
';  square2(&n2);  cout << 'Square of n2: ' << n2 << '
';  cout << 'Change reflected in n2: ' << n2 << '
';  // Call-by-Reference with Reference Arguments  int n3 = 8;  cout << 'address of n3 in main(): ' << &n3 << '
';  square3(n3);  cout << 'Square of n3: ' << n3 << '
';  cout << 'Change reflected in n3: ' << n3 << '
'; } // Driver program int main() { geeks(); }>

Producción
address of n1 in main(): 0x7fffa7e2de64 address of n1 in square1(): 0x7fffa7e2de4c Square of n1: 64 No change in n1: 8 address of n2 in main(): 0x7fffa7e2de68 address of n2 in square2(): 0x7fffa7e2de68 Square of n2: 64 Change reflected in n2: 64 address of n3 in main(): 0x7fffa7e2de6c address of n3 in square3(): 0x7fffa7e2de6c Square of n3: 64 Change reflected in n3: 64>

En C++, de forma predeterminada, los argumentos se pasan por valor y los cambios realizados en la función llamada no se reflejarán en la variable pasada. Los cambios se realizan en un clon realizado por la función llamada. Si desea modificar la copia original directamente (especialmente al pasar un objeto o matriz enorme) y/o evitar la sobrecarga de la clonación, utilizamos el paso por referencia. El paso por referencia con argumentos de referencia no requiere ninguna sintaxis torpe para hacer referencia y desreferenciar.

Nombre de matriz como punteros

Un formación nombre contiene la dirección del primer elemento de la matriz que actúa como un puntero constante. Significa que la dirección almacenada en el nombre de la matriz no se puede cambiar. Por ejemplo, si tenemos una matriz llamada val entonces vale y &valor[0] se pueden utilizar indistintamente.

C++
// C++ program to illustrate Array Name as Pointers #include  using namespace std; void geeks() {  // Declare an array  int val[3] = { 5, 10, 20 };  // declare pointer variable  int* ptr;  // Assign the address of val[0] to ptr  // We can use ptr=&val[0];(both are same)  ptr = val;  cout << 'Elements of the array are: ';  cout << ptr[0] << ' ' << ptr[1] << ' ' << ptr[2]; } // Driver program int main() { geeks(); }>

Producción
Elements of the array are: 5 10 20>
Representación de datos en memoria.

Si el puntero ptr se envía a una función como argumento, se puede acceder a la matriz val de manera similar. Puntero vs matriz



Expresiones de puntero y aritmética de puntero

Un conjunto limitado de aritmética Las operaciones se pueden realizar en punteros que son:

  • incrementado ( ++ )
  • disminuido (-)
  • se puede agregar un número entero a un puntero ( + o += )
  • un número entero se puede restar de un puntero ( – o -= )
  • diferencia entre dos punteros (p1-p2)

( Nota: La aritmética de punteros no tiene sentido a menos que se realice en una matriz).

C++
// C++ program to illustrate Pointer Arithmetic #include  using namespace std; void geeks() {  // Declare an array  int v[3] = { 10, 100, 200 };  // declare pointer variable  int* ptr;  // Assign the address of v[0] to ptr  ptr = v;  for (int i = 0; i < 3; i++) {  cout << 'Value at ptr = ' << ptr << '
';  cout << 'Value at *ptr = ' << *ptr << '
';  // Increment pointer ptr by 1  ptr++;  } } // Driver program int main() { geeks(); }>

Producción
Value at ptr = 0x7ffe5a2d8060 Value at *ptr = 10 Value at ptr = 0x7ffe5a2d8064 Value at *ptr = 100 Value at ptr = 0x7ffe5a2d8068 Value at *ptr = 200>
Representación de datos en memoria.

Notación de puntero avanzada

Considere la notación de puntero para las matrices numéricas bidimensionales. considere la siguiente declaración

int nums[2][3] = { { 16, 18, 20 }, { 25, 26, 27 } };>

En general, nums[ i ][ j ] es equivalente a *(*(nums+i)+j)

clase vs objeto en java
Notación de puntero en C++

Punteros y literales de cadena

Los literales de cadena son matrices que contienen secuencias de caracteres terminadas en nulo. Los literales de cadena son matrices de tipo carácter más un carácter nulo de terminación, y cada uno de los elementos es de tipo const char (ya que los caracteres de la cadena no se pueden modificar).

látex derivado parcial
>

Esto declara una matriz con la representación literal de geek y luego se asigna un puntero a su primer elemento a ptr. Si imaginamos que geek está almacenado en las ubicaciones de memoria que comienzan en la dirección 1800, podemos representar la declaración anterior como:

Punteros y literales de cadena

Como los punteros y las matrices se comportan de la misma manera en las expresiones, se puede utilizar ptr para acceder a los caracteres de una cadena literal. Por ejemplo:

char ptr = 0; char x = *(ptr+3); char y = ptr[3];>

Aquí, tanto x como y contienen k almacenado en 1803 (1800+3).

Punteros a punteros

En C++, podemos crear un puntero a un puntero que a su vez puede apuntar a datos u otro puntero. La sintaxis simplemente requiere el operador unario (*) para cada nivel de direccionamiento indirecto al declarar el puntero.

char a; char *b; char ** c; a = ’g’; b = &a; c = &b;>

Aquí b apunta a un carácter que almacena 'g' y c apunta al puntero b.

Punteros vacíos

Este es un tipo especial de puntero disponible en C++ que representa la ausencia de tipo. punteros vacíos son punteros que apuntan a un valor que no tiene tipo (y por lo tanto también una longitud indeterminada y propiedades de desreferenciación indeterminadas). Esto significa que los punteros nulos tienen una gran flexibilidad ya que pueden apuntar a cualquier tipo de datos. Esta flexibilidad tiene su recompensa. Estos indicadores no se pueden desreferenciar directamente. Primero deben transformarse en algún otro tipo de puntero que apunte a un tipo de datos concreto antes de desreferenciarlos.

C++
// C++ program to illustrate Void Pointer #include  using namespace std; void increase(void* data, int ptrsize) {  if (ptrsize == sizeof(char)) {  char* ptrchar;  // Typecast data to a char pointer  ptrchar = (char*)data;  // Increase the char stored at *ptrchar by 1  (*ptrchar)++;  cout << '*data points to a char'  << '
';  }  else if (ptrsize == sizeof(int)) {  int* ptrint;  // Typecast data to a int pointer  ptrint = (int*)data;  // Increase the int stored at *ptrchar by 1  (*ptrint)++;  cout << '*data points to an int'  << '
';  } } void geek() {  // Declare a character  char c = 'x';  // Declare an integer  int i = 10;  // Call increase function using a char and int address  // respectively  increase(&c, sizeof(c));  cout << 'The new value of c is: ' << c << '
';  increase(&i, sizeof(i));  cout << 'The new value of i is: ' << i << '
'; } // Driver program int main() { geek(); }>

Producción
*data points to a char The new value of c is: y *data points to an int The new value of i is: 11>

Punteros no válidos

Un puntero debe apuntar a una dirección válida pero no necesariamente a elementos válidos (como en el caso de las matrices). Estos se denominan punteros no válidos. Los punteros no inicializados también son punteros no válidos.

int *ptr1; int arr[10]; int *ptr2 = arr+20;>

Aquí, ptr1 no está inicializado, por lo que se convierte en un puntero no válido y ptr2 está fuera de los límites de arr, por lo que también se convierte en un puntero no válido. (Nota: los punteros no válidos no necesariamente generan errores de compilación)

Punteros NULL

A puntero nulo es un puntero que no apunta a ninguna parte y no solo a una dirección no válida. A continuación se muestran dos métodos para asignar un puntero como NULL;

fecha java a cadena
int *ptr1 = 0; int *ptr2 = NULL;>

Ventajas de los punteros

  • Los punteros reducen el código y mejoran el rendimiento. Se utilizan para recuperar cadenas, árboles, matrices, estructuras y funciones.
  • Los punteros nos permiten devolver múltiples valores de funciones.
  • Además de esto, los punteros nos permiten acceder a una ubicación de memoria en la memoria de la computadora.

Artículos relacionados:

  • Puntero opaco
  • Punteros cercanos, lejanos y enormes

Cuestionarios:

  • Conceptos básicos del puntero
  • Puntero avanzado