DMarlon Studio

Lección 1 · 1 de 20

Punteros a punteros y aritmética · C

Recorra arrays en C con aritmética de punteros, reste punteros y use un puntero a puntero para que una función cambie a dónde apunta otro.

C · Punteros a punteros y aritmética en DMarlon Studio: el código del ejemplo y su salida en la terminal

La aritmética de punteros cuenta en elementos, no en bytes: si p apunta a prices[0], p + 2 apunta a prices[2] y *(p + 2) es lo mismo que prices[2]. El compilador multiplica por el tamaño del tipo, y por eso (char *)(p + 1) - (char *)p da 8, los bytes de un double.

Restar dos punteros del mismo array da cuántos elementos hay entre ellos, con el tipo ptrdiff_t (se escribe con %td). (prices + n) - p es 5, y cheapest - prices convierte un puntero en su índice. Apuntar una posición después del último elemento, como prices + n, está permitido para comparar, pero no para leer *.

Una función recibe copias de sus argumentos. Para que find_cheapest cambie el puntero cheapest de main, se le pasa su dirección, &cheapest, y el parámetro es un puntero a puntero, double **. Dentro, *cheapest es el puntero de main y **cheapest es el precio al que apunta.

El caso más habitual de ** es una lista de cadenas: shops es un array de const char * que termina en NULL, como argv. const char **s recorre la lista: *s es cada cadena y **s, su primera letra.

En DMarlon Studio, este programa se escribe en el destino Consola y se compila y ejecuta con un clic (F9).

Código · main.c

#include <stdio.h>#include <string.h>// Receives the address of a pointer and makes it point at the cheapest price.void find_cheapest(double *prices, int n, double **cheapest) {    *cheapest = prices;    for (double *p = prices + 1; p < prices + n; p++)        if (*p < **cheapest) *cheapest = p;}int main(void) {    double prices[] = {4.50, 3.20, 5.10, 2.95, 3.80};    int n = sizeof prices / sizeof prices[0];    // Pointer arithmetic: p + 2 moves two elements, not two bytes.    double *p = prices;    printf("First: %.2f, third: %.2f\n", *p, *(p + 2));    printf("Bytes from p to p + 1: %td\n", (char *)(p + 1) - (char *)p);    printf("Elements from start to end: %td\n", (prices + n) - p);    double *cheapest = NULL;    find_cheapest(prices, n, &cheapest);    printf("Cheapest: %.2f at index %td\n", *cheapest, cheapest - prices);    // A list of strings is an array of pointers: char ** walks through it.    const char *shops[] = {"Bakery", "Market", "Kiosk", NULL};    for (const char **s = shops; *s != NULL; s++)        printf("Shop %td: %-7s first letter %c, %zu letters\n",               s - shops, *s, **s, strlen(*s));    const char **second = shops + 1;    printf("Through **: %s starts with %c\n", *second, **second);    return 0;}

Salida · cc main.c -o main && ./main

First: 4.50, third: 5.10
Bytes from p to p + 1: 8
Elements from start to end: 5
Cheapest: 2.95 at index 3
Shop 0: Bakery  first letter B, 6 letters
Shop 1: Market  first letter M, 6 letters
Shop 2: Kiosk   first letter K, 5 letters
Through **: Market starts with M

Para recordar

  • p + i avanza i elementos; *(p + i) es p[i].
  • La resta de punteros da elementos, con %td.
  • Para cambiar un puntero desde una función, pase &puntero y reciba T **.
  • Un array de cadenas se recorre con char ** hasta NULL.

Ejercicio

Escriba find_dearest con la misma forma que find_cheapest y use las dos para escribir el precio más alto, el más bajo y la distancia en elementos entre ellos.