Recientemente encontré un código en stackoverflow donde los punteros a los punteros se usaban para cambiar la memoria asignada. Mientras revisaba el código, cometí el error de agregar un ampersand a un puntero, así que haga un puntero a un puntero, pero el compilador compiló felizmente y se produjeron errores de tiempo de ejecución. Como ejemplo
#include <stdio.h> void func(int **p) { printf("Pointer is at %p\n", p); } int main(void) { int *p = 0; func(p); func(&p); int **pp = &p; func(&pp); return 0; } Entiendo que C tiene restricciones significativamente más bajas para punteros que C++ y permite algo como char *buf = malloc(SIZE) mientras que C++ no está permitido. Lo veo como una conveniencia porque sucede mucho en C.
Sin embargo, creo que la cantidad de referencias es una gran fuente de errores y me pregunto por qué se podría permitir esto, especialmente porque int es diferente de int* . Además, quiero saber si el estándar C dice algo al respecto.
EDITAR Lo compilé en ideone.com, que probablemente no muestre advertencias. Mi compilador clang local, así como gcc, dan advertencias. Aún así, ¿por qué son solo advertencias cuando representan cosas diferentes?
PD: Siento que algo como esto debería haberse preguntado en los últimos seis años de SO. Si se trata de un duplicado, lo siento por no encontrar uno.
La conversión no es legal. Más precisamente, no hay una conversión implícita de int* a int** , o de int*** a int** . Intentar pasar un int* o un int*** a una función que requiere un argumento int** es una violación de restricción ; cualquier compilador conforme debe diagnosticarlo. (El mensaje de diagnóstico puede ser una advertencia no fatal).
Cuando compilo su código con gcc, incluso con las opciones predeterminadas (lo que hace que gcc no cumpla), recibo varias advertencias:
cc: In function 'func': cc:4:3: warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'int **' [-Wformat=] printf("Pointer is at %x\n", p); ^ cc: In function 'main': cc:9:3: warning: passing argument 1 of 'func' from incompatible pointer type [enabled by default] func(p); ^ cc:3:6: note: expected 'int **' but argument is of type 'int *' void func(int **p) { ^ cc:12:3: warning: passing argument 1 of 'func' from incompatible pointer type [enabled by default] func(&pp); ^ cc:3:6: note: expected 'int **' but argument is of type 'int ***' void func(int **p) { ^No sé por qué ideone no se queja ( http://ideone.com/uzeXur ).
El compilador aparentemente no tiene advertencias habilitadas:
int main() { int *p = 0, **p2 = p; ... $ gcc -std=c11 test.c -lncurses test.c: In function 'main': test.c:8:21: warning: initialization from incompatible pointer type [enabled by default] int *p = 0, **p2 = p; ^Entonces, gcc se queja muy bien. Ese sitio podría haber deshabilitado las advertencias o se lo traga. No debería hacer nada.
Para gcc, también puede convertir todas las advertencias en errores con -Werror o simplemente algunos específicos: -Werror=<name of warning> . Para esto, sería strict-aliasing .
La razón por la que esto no es predeterminado es probablemente por razones históricas. Hacer que sea un error de forma predeterminada podría romper demasiado software heredado o roto en la naturaleza.
La razón por la que no produce un error se puede encontrar aquí en el estándar . Oración 7. Solo es UB si el puntero no está correctamente alineado para el puntero de recepción o no está referenciado (lo que no se hace aquí).
Creo que ideone es suave con las advertencias. Sin -Wall o cualquier indicador de advertencia adicional en mi computadora, gcc me da
test_ptrs.c: In function 'func': test_ptrs.c:4:3: warning: format '%x' expects argument of type 'unsigned int', but argument 2 has type 'int **' [-Wformat=] printf("Pointer is at %x\n", p); ^ test_ptrs.c: In function 'main': test_ptrs.c:9:3: warning: passing argument 1 of 'func' from incompatible pointer type [enabled by default] func(p); ^ test_ptrs.c:3:6: note: expected 'int **' but argument is of type 'int *' void func(int **p) { ^ test_ptrs.c:12:3: warning: passing argument 1 of 'func' from incompatible pointer type [enabled by default] func(&pp); ^ test_ptrs.c:3:6: note: expected 'int **' but argument is of type 'int ***' void func(int **p) {