Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pointers and Pointer Arithmethics in C #788

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 176 additions & 0 deletions tutorials/learn-c.org/es/Pointer Arithmetics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@

Tutorial
---------

Anteriormente aprendiste qué es un puntero y cómo manipularlo. En este tutorial aprenderá las operaciones aritméticas con punteros.
Hay múltiples operaciones aritméticas que se pueden aplicar en punteros C: ++, —, -, +

### Incrementar un puntero con (++)
Al igual que cualquier variable, la operación ++ aumenta el valor de esa variable. En nuestro caso aquí, la variable es un puntero, por lo tanto, cuando aumentamos su valor, estamos aumentando la dirección en la memoria a la que apunta ese puntero.
Combinemos esta operación con una matriz en nuestro ejemplo:

#include <stdio.h>

int main()
{
int intarray[5] = {10,20,30,40,50};

int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] tiene valor %d - y dirección @ %x\n", i, intarray[i], &intarray[i]);


int *intpointer = &intarray[3]; //apunta al 4º elemento del array
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprimir la dirección del 4º elemento

intpointer++; //ahora incrementa la dirección del puntero para que apunte al 5º elemento del array
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprimir la dirección del 5º elemento

return 0;
}

Disminuyendo un puntero con (- -)
Al igual que en nuestro ejemplo anterior, aumentamos la dirección apuntada del puntero en uno usando el operador ++, podemos disminuir la dirección apuntada en uno usando el operador de decremento (- -).

```
#include <stdio.h>

int main()
{
int intarray[5] = {10,20,30,40,50};

int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] tiene valor %d - y dirección @ %x\n", i, intarray[i], &intarray[i]);


int *intpointer = &intarray[4]; //señala el 5º elemento de la matriz
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 5º elemento

intpointer--; //ahora disminuye la dirección del punto para que apunte al 4º elemento del array
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 4º elemento

return 0;
}
```
### Agregar punteros con (+)
Anteriormente aumentamos en uno la dirección a la que apunta un puntero. También podemos aumentarlo en un valor entero como:

```
#include <stdio.h>

int main()
{
int intarray[5] = {10,20,30,40,50};

int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] tiene valor: %d - y dirección @ %x\n", i, intarray[i], &intarray[i]);


int *intpointer = &intarray[1]; //señala el 2º elemento de la matriz
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 2º elemento

intpointer += 2; //ahora desplaza por dos la dirección del punto para que apunte al 4º elemento del array
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 4º elemento

return 0;
}
```
Observe cómo en la salida la dirección cambió 8 pasos en la memoria. Quizás te preguntes ¿por qué?

La respuesta es simple: debido a que nuestro puntero es un puntero int y el tamaño de una variable int es de 4 bytes, la memoria se puede desplazar en 4 bloques. En nuestro código cambiamos 2 (agregamos +2) a la dirección inicial para que sean 2 x 4 bytes = 8.

### Restar punteros con (-)
De manera similar podemos restar:

#include <stdio.h>

int main()
{
int intarray[5] = {10,20,30,40,50};

int i;
for(i = 0; i < 5; i++)
printf("intarray[%d] tiene valor: %d - y dirección @ %x\n", i, intarray[i], &intarray[i]);

int *intpointer = &intarray[4]; //apunta al 5º elemento de la matriz
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 5º elemento

intpointer -= 2; //ahora desplaza en dos la dirección del punto para que apunte al 3er elemento de la matriz
printf("dirección: %x - tiene valor %d\n", intpointer, *intpointer); //imprime la dirección del 3er elemento

return 0;
}
nuevamente la dirección se desplaza en bloques de 4 bytes (en el caso de int).

### Otras operaciones
Hay más operaciones como comparación >, <, ==. La idea es muy similar a comparar variables, pero en este caso estamos comparando direcciones de memoria.

Ejercicio
----
Copie las últimas tres direcciones de intarray en parray, que es una matriz de punteros a un int.

Código de Tutorial
-------------
#include <stdio.h>

int main() {
int intarray[5] = {10,20,30,40,50};
//-----------------------^
int *pointer = &intarray[2];

// Array de 3 punteros
int *parray[3];

// Copia las tres últimas direcciones de intarray en parray
// Usar parray y puntero
int i;
for (i = 0; i < 3; i++) {
// Inserte aquí el código
}

// Código de prueba
for (i = 0; i < 3; i++) {
if (parray[i] == &pointer[i]) {
printf("Coinciden!\n");
} else {
printf("Fallan");
}
}

return 0;
}

Salida Esperada
---------------
¡Coinciden!
¡Coinciden!
¡Coinciden!

Solución
--------
#include <stdio.h>

int main() {
int intarray[5] = {10,20,30,40,50};
//-----------------------^
int *pointer = &intarray[2];

int *parray[3];

int i;
for (i = 0; i < 3; i++) {
parray[i] = pointer + i;
}

for (i = 0; i < 3; i++) {
if (parray[i] == &pointer[i]) {
printf("¡Coinciden!\n");
} else {
printf("Falla\n");
}
}

return 0;
}
112 changes: 112 additions & 0 deletions tutorials/learn-c.org/es/Pointers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@

Tutorial
--------
Los punteros también son variables y juegan un papel muy importante en el lenguaje de programación C. Se utilizan por varias razones, tales como:

* Strings
* Asignación de memoria dinámica
* Envío de argumentos a funciones por referencia
* Construcción de estructuras de datos complicadas
* Apuntar a funciones
* Construcción de estructuras de datos especiales (es decir, árbol, intentos, etc.)

Y muchos más.

### ¿Qué es un puntero?

Un puntero es esencialmente una variable entera simple que contiene una **dirección de memoria** que apunta a un valor, en lugar de contener el valor real en sí.

La memoria de la computadora es un almacén secuencial de datos y un puntero apunta a una parte específica de la memoria. Nuestro programa puede usar punteros de tal manera que los punteros apunten a una gran cantidad de memoria, dependiendo de cuánto decidamos leer a partir de ese momento.

### Cadenas como punteros

Ya hemos hablado de las cadenas, pero ahora podemos profundizar un poco más y comprender qué son realmente las cadenas en C (que se llaman C-Strings para diferenciarlas de otras cadenas cuando se mezclan con C++).

La siguiente línea:

char * nombre = "John";

hace tres cosas:

1. Asigna una variable local (pila) llamada ` nombre` , que es un puntero a un solo carácter.
2. Hace que la cadena "John" aparezca en algún lugar de la memoria del programa (después de compilarlo y ejecutarlo, por supuesto).
3. Inicializa el argumento ` nombre ` para señalar dónde reside el carácter ` J ` (que es seguido por el resto de la cadena en la memoria).

Si intentamos acceder a la variable ` nombre` como una matriz, funcionará y devolverá el valor ordinal del carácter ` J` , ya que la variable ` nombre` en realidad apunta exactamente al comienzo de la cadena.

Como sabemos que la memoria es secuencial, podemos asumir que si avanzamos en la memoria al siguiente carácter, recibiremos la siguiente letra de la cadena, hasta llegar al final de la cadena, marcado con un terminador nulo. (el carácter con el valor ordinal de 0, anotado como ` \0 ` ).

### Desreferenciación

La desreferenciación es el acto de hacer referencia a dónde apunta el puntero, en lugar de a la dirección de memoria. Ya estamos usando la desreferenciación en matrices, pero aún no lo sabíamos. El operador de corchetes - ` [0] ` por ejemplo, accede al primer elemento de la matriz. Y dado que las matrices son en realidad punteros, acceder al primer elemento de la matriz es lo mismo que desreferenciar un puntero. La desreferenciación de un puntero se realiza utilizando el operador de asterisco ` * ` .

Si queremos crear una matriz que apunte a una variable diferente en nuestra pila, podemos escribir el siguiente código:

/* definir una variable local a */
int a = 1;
/* define una variable de puntero y apúntala a usando el operador & */
int * pointer_to_a = &a;
printf("El valor a es %d\n", a);
printf("El valor de a también es %d\n", *pointer_to_a);

Observe que usamos el operador ` & ` para señalar la variable ` a` , que acabamos de crear.

Luego nos referimos a él utilizando el operador de desreferenciación. También podemos cambiar el contenido de la variable desreferenciada:

int a = 1;
int * pointer_to_a = &a;

/* cambiemos la variable a */
a += 1;

/* ¡acabamos de cambiar la variable nuevamente! */
*pointer_to_a += 1;
/* imprimirá 3 */
printf("El valor de a ahora es %d\n", a);

Ejercicio
--------
Cree un puntero a la variable local ` n ` llamada ` pointer_to_n ` y utilícelo para aumentar el valor de ` n ` en uno.

Código del tutorial
-------------
```
#include <stdio.h>

int main() {
int n = 10;

/* tu código va aquí */

/* código de prueba */
if (pointer_to_n != &n) return 1;
if (*pointer_to_n != 11) return 1;

printf("Listo!\n");
return 0;
}
```
Resultado esperado
---------------
¡Listo!

Solución
--------
```
#include <stdio.h>

int main() {
int n = 10;

int * pointer_to_n = &n;

*pointer_to_n += 1;

/* testing code */
if (pointer_to_n != &n) return 1;
if (*pointer_to_n != 11) return 1;

printf("Done!\n");
return 0;
}
```