Puntero además vs resta

$5.7 –

«[..]Para la adición, de cualquiera de los dos operandos tendrá la aritmética o el tipo de enumeración, o un operando debe ser un puntero a un tipo de objeto definido y el otro tendrá integral o tipo de enumeración.

2 Para la resta, uno de los siguientes deberán tener:
— ambos operandos tienen la aritmética o el tipo de enumeración; o
— ambos operandos son punteros a la cv-calificado o cv-sin calificar versiones de la misma completamente tipo de objeto definido; o
— la izquierda el operando es un puntero a un tipo de objeto definido y el operando derecho ha integral o tipo de enumeración.

int main(){
        int buf[10];
        int *p1 = &buf[0];
        int *p2 = 0;

        p1 + p2;       //Error

        p1 - p2;       //OK
}

Así, mi pregunta es por qué ‘puntero además’ no es compatible en C++ pero ‘puntero resta’ es?

  • Nota: el puntero, además, se apoya en el sentido de que T* p = /**/; p = p + 1 es válido (y los puntos de uno de los elementos más). Que difiere un poco de tu pregunta, sin embargo 🙂
  • muchas de las respuestas indican que la diferencia significaría que el número de objetos de un tipo que puede ser almacenado entre dos puntos p1 y p2. ¿Qué pasa si el puntero es de tipo » void *’?
  • entonces no se puede restar de ellos.
InformationsquelleAutor Chubsdad | 2010-08-30

8 Kommentare

  1. 29

    La diferencia entre los dos punteros significa el número de elementos del tipo que se ajuste entre los objetivos de los dos punteros. La suma de los dos punteros significa…er…nada, que es la razón por la que no se admite.

  2. 18

    El resultado de la resta es la distancia (útil).

    El resultado de la adición de un puntero y una distancia que es otro significativo puntero.

    El resultado de la adición de 2 punteros es otro puntero, esta vez sin sentido, sin embargo.

    Es la misma razón hay de distintos períodos de tiempo y objetos DateTime en la mayoría de las bibliotecas.

  3. 4

    La primera cosa que viene a la mente es que no tiene sentido hacer puntero, así que no es compatible. Si usted tiene 2 punteros 0x45ff23dd, 0x45ff23ed. ¿Qué significa para agregarlos?? Algunos de memoria fuera de los límites. Y la gente en la norma del comité no han encontrado razones suficientemente buenas como para apoyar cosas como esa, y en lugar de advertir a usted en tiempo de compilación acerca de un posible problema. Mientras que el puntero de la resta es bueno porque indica que la memoria de la distancia, que es a menudo útil.

  4. 3

    Resultado de puntero de la resta es el número de objetos entre dos direcciones de memoria. Puntero, además de que no significa nada, esta es la razón por la que no está permitido.

  5. 2

    Debido a la adición de dos punteros no tiene sentido.

    Considerar tengo dos ints en la memoria en 0x1234 y 0x1240. La diferencia entre estas direcciones es 0xc y es un distancia en la memoria. La suma es 0x2474 y no corresponden a nada significativo.

    Que puede sin embargo, añadir un puntero a un entero para obtener otro puntero. Esto es lo que usted hace cuando usted índice en una matriz: p[4] significa *(p + 4), que significa «lo que hay almacenado en la dirección 4 unidades pasado esta dirección.»

    En general, se puede determinar la «pointerness» de una operación aritmética mediante la asignación de cada indicador un valor de 1 y cada entero un valor de cero. Si el resultado es 1, tienes un puntero; si es 0, se tiene un número entero; si es cualquier otro valor, usted tiene algo que no tiene sentido. Ejemplos:

    /* here p,q,r are pointers, i,j,k are integers */
    p + i; /* 1 + 0 == 1 => p+i is a pointer */
    p - q; /* 1 - 1 == 0 => p-q is an integer */
    p + (q-r); /* 1 + (1-1) == 1 => pointer */
  6. 1

    N. B. No hay reclamos en C normas de aquí.

    Como una rápida adición a @Brian Hooper respuesta, «[t]él la suma de los dos punteros significa…er…nada» sin embargo, la suma de un puntero y un entero que permite el desplazamiento de la inicial del puntero.

    Restando un valor superior puntero desde un valor inferior puntero le da el desplazamiento entre los dos. Tenga en cuenta que yo no soy de contabilidad para la paginación de memoria aquí; estoy asumiendo los valores de la memoria son, tanto dentro de la accesible alcance del proceso.

    Así que si usted tiene un puntero a una serie de sucesivas ubicaciones de memoria en el montón, o un conjunto de ubicaciones de memoria en la pila (cuyo nombre de variable se desintegra en un puntero), estos punteros (el real puntero y el que se desintegra en un puntero) va a señalar el puño de la memoria ubicación de la pregunta (es decir, el elemento [0]). La adición de un valor entero para el puntero es equivalente a incrementar el índice entre corchetes por el mismo número.

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        //This first declaration does several things (this is conceptual and not an exact list of steps the computer takes):
        //     1) allots space on the stack for a variable of type pointer
        //     2) allocates number of bytes on the heap necessary to fit number of chars in initialisation string
        //        plus the NULL termination '\0' (i.e. sizeof(char) * <characters in string> + 1 for '\0')
        //     3) changes the value of the variable from step 1 to the memory address of the beginning of the memory
        //        allocated in step 2
        //The variable iPointToAMemoryLocationOnTheHeap points to the first address location of the memory that was allocated.
        char *iPointToAMemoryLocationOnTheHeap = "ABCDE";
    
        //This second declaration does the following:
        //     1) allots space on the stack for a variable that is not a pointer but is said to decay to a pointer allowing
        //        us to so the following iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
        //     2) allots number of bytes on the stack necessary to fit number of chars in initialisation string
        //        plus the NULL termination '\0' (i.e. sizeof(char) * <characters in string> + 1 for '\0')
        //The variable iPointToACharOnTheHeap just points to first address location.
        //It just so happens that others follow which is why null termination is important in a series of chars you treat
        char iAmASeriesOfConsecutiveCharsOnTheStack[] = "ABCDE";
    
        //In both these cases it just so happens that other chars follow which is why null termination is important in a series
        //of chars you treat as though they are a string (which they are not).
    
        char *iJustPointToMemoryLocationsYouTellMeToPointTo = NULL;
    
        iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
    
        //If you increment iPointToAMemoryLocationOnTheHeap, you'll lose track of where you started
        for( ; *(++iJustPointToMemoryLocationsYouTellMeToPointTo) != '\0' ; ) {
            printf("Offset of: %ld\n", iJustPointToMemoryLocationsYouTellMeToPointTo - iPointToAMemoryLocationOnTheHeap);
            printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo);
            printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo);
        }
    
        printf("\n");
    
        iJustPointToMemoryLocationsYouTellMeToPointTo = iPointToAMemoryLocationOnTheHeap;
    
        for(int i = 0 ; *(iJustPointToMemoryLocationsYouTellMeToPointTo + i) != '\0' ; i++) {
            printf("Offset of: %ld\n", (iJustPointToMemoryLocationsYouTellMeToPointTo + i) - iPointToAMemoryLocationOnTheHeap);
            printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo + i);
            printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo + i);
        }
    
        printf("\n");
    
        iJustPointToMemoryLocationsYouTellMeToPointTo = iAmASeriesOfConsecutiveCharsOnTheStack;
    
        //If you increment iAmASeriesOfConsecutiveCharsOnTheStack, you'll lose track of where you started
        for( ; *(++iJustPointToMemoryLocationsYouTellMeToPointTo) != '\0' ; ) {
            printf("Offset of: %ld\n", iJustPointToMemoryLocationsYouTellMeToPointTo - iAmASeriesOfConsecutiveCharsOnTheStack);
            printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo);
            printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo);
        }
    
        printf("\n");
    
        iJustPointToMemoryLocationsYouTellMeToPointTo = iAmASeriesOfConsecutiveCharsOnTheStack;
    
        for(int i = 0 ; *(iJustPointToMemoryLocationsYouTellMeToPointTo + i) != '\0' ; i++) {
            printf("Offset of: %ld\n", (iJustPointToMemoryLocationsYouTellMeToPointTo + i) - iAmASeriesOfConsecutiveCharsOnTheStack);
            printf("%s\n", iJustPointToMemoryLocationsYouTellMeToPointTo + i);
            printf("%c\n", *iJustPointToMemoryLocationsYouTellMeToPointTo + i);
        }
        return 1;
    }

    La primera notable lo que hacemos en este programa se copia el valor del puntero iPointToAMemoryLocationOnTheHeap a iJustPointToMemoryLocationsYouTellMeToPointTo. Así que ahora ambos apuntan a la misma ubicación de memoria en el heap. Lo hacemos para no perder de vista el principio de ella.

    En la primera for bucle incrementamos el valor que acaba de copiar en iJustPointToMemoryLocationsYouTellMeToPointTo (incremento de 1 significa que apunta a una ubicación de memoria más lejos de iPointToAMemoryLocationOnTheHeap).

    El segundo bucle es similar, pero yo quería mostrar más claramente cómo incrementar el valor está relacionado con el desplazamiento, y cómo la media aritmética de las obras.

    La tercera y la cuarta bucles repita el proceso, pero sí en una matriz en la pila como se opuso a la memoria asignada en el montón.

    Nota: el asterisco * cuando la impresión de que el individuo char. Esto indica printf para la salida de lo que es apuntado por la variable, y no el contenido de la variable en sí. Esto está en contraste con la línea de arriba, donde el equilibrio de la cadena se imprime y no hay ningún asterisco antes de la variable, porque printf() que está buscando en la serie de ubicaciones de memoria en su totalidad hasta que NULL es alcanzado.

    Aquí está la salida de ubuntu 15.10 se ejecuta en un i7 (la primera y la tercera bucles de salida a partir de un desplazamiento de 1, debido a mi bucle elección de for incrementos en el principio del bucle frente a un do{}while(); yo sólo quería keep it simple):

    Offset of: 1
    BCDE
    B
    Offset of: 2
    CDE
    C
    Offset of: 3
    DE
    D
    Offset of: 4
    E
    E
    
    Offset of: 0
    ABCDE
    A
    Offset of: 1
    BCDE
    B
    Offset of: 2
    CDE
    C
    Offset of: 3
    DE
    D
    Offset of: 4
    E
    E
    
    Offset of: 1
    BCDE
    B
    Offset of: 2
    CDE
    C
    Offset of: 3
    DE
    D
    Offset of: 4
    E
    E
    
    Offset of: 0
    ABCDE
    A
    Offset of: 1
    BCDE
    B
    Offset of: 2
    CDE
    C
    Offset of: 3
    DE
    D
    Offset of: 4
    E
    E
  7. 0

    Porque el resultado de esa operación es indefinido. ¿De donde p1 + p2 punto a? ¿Cómo puede asegurarse de que apunta a un inicializado correctamente la memoria, por lo que se podría anular la referencia más adelante?
    p1 – p2 da el desplazamiento entre los 2 punteros y que el resultado podría ser utilizado más adelante.

  8. 0

    la resta de los punteros sólo está definida si apuntan en la misma matriz de objetos. El resultado de la resta es la escala por el tamaño del objeto que seleccione. es decir, el puntero de la resta da el número de elementos entre los dos punteros.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea