¿Por qué el operador de desreferencia

9 minutos de lectura

también se utiliza para declarar un puntero?
avatar de usuario

cavando para el fuego

No estoy seguro de si esta es una pregunta de programación adecuada, pero es algo que siempre me ha molestado, y me pregunto si soy el único.

Cuando aprendí inicialmente C++, entendí el concepto de referencias, pero los punteros me confundían. ¿Porque preguntas? Debido a cómo declaras un puntero.

void foo(int* bar)
{
}


int main()
{
    int x = 5;
    int* y = NULL;

    y = &x;
    *y = 15;     
    foo(y);

}

Considera lo siguiente: foo(int*) La función int toma un y puntero como parámetro. Desde que he declarado int como y puntero, puedo pasar fooa * pero cuando aprendí C++ por primera vez asocié el int símbolo con desreferenciación, como tal me imaginé un desreferenciado *y necesitaba ser pasado. intentaría pasar foodentro

que obviamente no funciona.

void test(int@ x)
{
}

  • ¿No hubiera sido más fácil tener un operador separado para declarar un puntero? (o para desreferenciar). Por ejemplo:

    Esta pregunta no puede ser respondida, solo especulada.

    – bmargulies

  • 31 de diciembre de 2011 a las 0:58

    @bmargulies Se puede responder directamente; el creador de C escribió un documento explicando exactamente por qué esto es así.

    – Crashworks

  • 31 de diciembre de 2011 a las 1:15

    Una pregunta puede ser en forma de curiosidad genuina, ¿verdad? De hecho, creo que la respuesta de Crashworks es solo eso, una respuesta directa a mi pregunta. Entonces, ¿por qué solo se puede especular sobre esto?

    – cavando para el fuego

  • 31 de diciembre de 2011 a las 1:16

    @ildjarn: Esto no se basa en una discusión, hay una respuesta clara a la pregunta y todos la hemos dado.

    – Stuart Golodetz

  • 31 de diciembre de 2011 a las 1:35 phooehy Podría tener sentido sacar el maincaso y reducir el código a un simplificado reference . quite de las etiquetas, ya que la pregunta no parece ser sobre referencias en absoluto. Aunque el relacionado

    la pregunta podría ser: “¿Por qué el operador de dirección (&) también se usa para declarar una referencia?” También está sobrecargado de manera similar.

    usuario166390


31 de diciembre de 2011 a las 1:39
avatar de usuario

Crashworks EnEl desarrollo del lenguaje C

Dennis Ritchie explica así su razonamiento: [This] La segunda innovación que más claramente distingue a C de sus predecesores es esta estructura de tipos más completa y especialmente su expresión en la sintaxis de las declaraciones… dado un objeto de cualquier tipo, debería ser posible describir un nuevo objeto que reúna varios en una matriz. , lo produce a partir de una función, o es un puntero a ella…. condujo a una sintaxis de declaración para nombres que reflejaba la sintaxis de expresión en la que normalmente aparecen los nombres.

int i, *pi, **ppi; De este modo, i, *pi, and **ppi declarar un entero, un puntero a un entero, un puntero a un puntero a un entero. La sintaxis de estas declaraciones refleja la observación de que int todos producen un

cuando se usa en una expresión. int f(), *f(), (*f)(); Similarmente, int *api[10],
(*pai)[10];
declarar una función que devuelve un número entero, una función que devuelve un puntero a un número entero, un puntero a una función que devuelve un número entero.

declarar una matriz de punteros a enteros y un puntero a una matriz de enteros.En todos estos casos, la declaración de una variable se asemeja a su uso en una expresión cuyo tipo es el que se nombra en el encabezado de la declaración.

. *fp() and (*pf)()
Un accidente de sintaxis contribuyó a la complejidad percibida del lenguaje. El operador de direccionamiento indirecto, deletreado * en C, es sintácticamente un operador de prefijo unario, al igual que en BCPL y B. Esto funciona bien en expresiones simples, pero en casos más complejos, se requieren paréntesis para dirigir el análisis. Por ejemplo, para distinguir la indirección a través del valor devuelto por una función al llamar a una función designada por un puntero, uno escribe

int *fp(); int (*pf)();

respectivamente. El estilo utilizado en las expresiones se transmite a las declaraciones, por lo que los nombres pueden declararse int *(*pfp)(); En casos más ornamentados pero aún realistas, las cosas empeoran:

es un puntero a una función que devuelve un puntero a un número entero. [Sethi 81] Se producen dos efectos. Lo más importante es que C tiene un conjunto relativamente rico de formas de describir tipos (en comparación, digamos, con Pascal). Las declaraciones en lenguajes tan expresivos como C (Algol 68, por ejemplo) describen objetos igualmente difíciles de entender, simplemente porque los objetos en sí son complejos. Un segundo efecto se debe a los detalles de la sintaxis. Las declaraciones en C deben leerse en un estilo ‘de adentro hacia afuera’ que muchos encuentran difícil de comprender. Sethi

  • observó que muchas de las declaraciones y expresiones anidadas se volverían más simples si el operador de direccionamiento indirecto se hubiera tomado como un operador de posfijo en lugar de prefijo, pero para entonces ya era demasiado tarde para cambiar.

    Esa es una excelente explicación, desearía que nos dijeran este tipo de cosas en clase, me habría ayudado a entender los consejos mucho antes.

    – cavando para el fuego


  • 31 de diciembre de 2011 a las 1:52

    @Tomalak Geret’kal: Vaya, lástima que no puedo editarlo ahora. Bueno, estas cosas pasan cuando se escribe en un idioma extranjero.

    – cavando para el fuego


  • 31 de diciembre de 2011 a las 2:10

    @diggingforfire También te puede gustar mi técnica de “papel cuadriculado y lápiz” para razonar con punteros (ejemplo: stackoverflow.com/questions/7062853/…). En general, creo que aprender lo que la máquina realmente hace con punteros primero hace que aprender la abstracción de C sea más fácil; en lugar de tratar de aprender primero la abstracción y luego lo concreto.

    – Crashworks

  • 31 de diciembre de 2011 a las 2:38

    ¿Qué parte de esta cita explica por qué se seleccionó el prefijo * sobre las alternativas?

    –David Heffernan

  • 31 de diciembre de 2011 a las 8:29

    @DavidHeffernan: “al igual que en BCPL y B” en BCPL, todos los operadores unarios eran prefijos

    – mmmmmm

31 de diciembre de 2011 a las 15:06

int x, *y;

La razón es más clara si lo escribes así:

  • Es decir, tanto x como *y son enteros. Entonces y es un int *.

    En realidad, esto no queda más claro si lo amplías. No quiero iniciar una discusión, pero me gustaría señalar que esta sintaxis está destinada a conducir a una.

    – Carreras de ligereza en órbita

  • 31 de diciembre de 2011 a las 1:02 Estoy de acuerdo en que no deberías usar

    esta sintaxis en la práctica – era simplemente para ilustrar el punto (que es el mismo punto que hace David).

    – Stuart Golodetz

  • 31 de diciembre de 2011 a las 1:03

    De hecho, nada contra usted o su respuesta (excepto quizás la parte “más clara”)

    – Carreras de ligereza en órbita


  • 31 de diciembre de 2011 a las 1:04

    Sin ofender 🙂 Solo trato de aclarar.

    – Stuart Golodetz

  • 31 de diciembre de 2011 a las 1:05

    Probablemente no sea la respuesta más clara del mundo, pero escrita en un iPad, por lo tanto, más corta de lo normal. El punto que estaba tratando de hacer es que si agrupa el * con el nombre de la variable, se vuelve más claro de dónde proviene esta sintaxis, es decir, la idea de que al decir * y es un int, está implicando que y en sí mismo es un int * . Como esta respuesta ha sido confirmada en la práctica por la referencia dada (y no fue una suposición), no estoy seguro de dónde proviene la hostilidad. De todos modos, pongámonos de acuerdo en estar en desacuerdo.

    – Stuart Golodetz


31 de diciembre de 2011 a las 12:41 int *p; Esa es una decisión de lenguaje anterior a C++, ya que C++ la heredó de C. Una vez escuché que la motivación era que la declaración y el uso serían equivalentes, es decir, dada una declaración *p la expresion int es de tipo int i; de la misma manera que con i la expresion intes de tipo

.
avatar de usuario

Carreras de ligereza en órbita * Porque el comité, y aquellos que desarrollaron C++ en las décadas previas a su estandarización, decidieron quedebe conservar sus tres significados originales

  • :
  • Un tipo de puntero
  • El operador de desreferencia

Multiplicación * Tienes razón al sugerir que los múltiples significados de &(y, del mismo modo,


) son confusos. Durante algunos años, he sido de la opinión de que son una barrera importante para la comprensión de los recién llegados al idioma.

¿Por qué no elegir otro símbolo para C++? Compatibilidad al revés


es la causa raíz… es mejor reutilizar los símbolos existentes en un nuevo contexto que romper los programas C traduciendo los que antes no eran operadores a nuevos significados.

¿Por qué no elegir otro símbolo para C?

Es imposible saberlo con certeza, pero hay varios argumentos que se pueden hacer, y se han hecho. Lo más importante es la idea de que: [an] cuando

identificador aparece en una expresión de la misma forma que el declarador, produce un objeto del tipo especificado. {K&R, pág. 216}[citation needed] Esta es también la razón por la que los programadores de C tienden a

int *ptr1; // roughly C-style
int* ptr2; // roughly C++-style

prefieren alinear sus asteriscos a la derecha en lugar de a la izquierda, es decir:

aunque ambas variedades se encuentran en programas de ambos idiomas, de manera variable. La página 65 de Programación experta en C: Deep C Secrets incluye lo siguiente:

Y luego, está la filosofía C de que la declaración de un objeto debe parecerse a su uso. Página 216 de El lenguaje de programación C, 2.ª edición (también conocido como K&R) incluye:

Un declarador se lee como una afirmación de que cuando su identificador aparece en una expresión de la misma forma que el declarador, produce un objeto del tipo especificado.

Prefiero la forma en que lo expresa van der Linden.
avatar de usuario

binario

Jaja, siento tu dolor, tuve exactamente el mismo problema. &int Pensé que un puntero debería declararse como

porque tiene sentido que un puntero sea una dirección de algo. Después de un tiempo pensé por mí mismo, cada tipo en C tiene que ser leídohacia atrás

int * const a

me gusta

a constant something, when dereferenced equals an intes para mí . algo que tiene que serdesreferenciado

¿Ha sido útil esta solución?