Почему i[arr] работает так же, как arr[i] в C с большими типами данных?

это довольно распространенное знание, что если вы получаете доступ к элементу массива как arr[i] В C, что вы также можете получить доступ к элементу как i[arr], потому что они просто сводятся к *(arr + i) и сложение коммутативно. Мой вопрос в том, почему это работает для типов данных больше, чем char, потому что sizeof(char) равно 1, и для меня это должно продвинуть указатель только на один символ.

возможно, этот пример делает его более ясным:

#include <string.h>
#include <stdio.h>

struct large { char data[1024]; };

int main( int argc, char * argv[] )
{
    struct large arr[4];
    memset( arr, 0, sizeof( arr ) );

    printf( "%lun", sizeof( arr ) ); // prints 4096

    strcpy( arr[0].data, "should not be accessed (and is not)" );
    strcpy( arr[1].data, "Hello world!" );

    printf( "%s, %s, %sn", arr[1].data, 1[arr].data, (*(arr+1)).data );
    // prints Hello world!, Hello world!, Hello world!
    // I expected `hold not be accessed (and is not)' for #3 at least

    return 0;

}

Итак, почему добавление одного в указатель массива заранее это sizeof( struct large )?

5 ответов


в C арифметика указателя определяется так, что запись

ptr + k

не выдвигает указатель на k байт, а к объекты. Таким образом, если у вас есть указатель на целочисленный массив и писать!--5-->

*(myIntArrayPointer + 3)

вы разыменовываете указатель на элемент с индексом 3 в массиве, а не целое число, которое начинается через три байта после начала объекта.

аналогично, если вы вычесть два указателя, вы получите логическое число элементов между ними, а не общее количество байтов. Таким образом, пишет

(myIntArrayPointer + 3) - myIntArrayPointer

дает значение 3, даже если есть 3 * sizeof(int) байты между ними.

надеюсь, что это помогает!


это указатель арифметические. Когда вы пишете

some_pointer + i 

он скомпилирован как

some_pointer + (i * sizeof(*my_pointer))

(i это int если уж на то пошло:))


такими всегда ответьте, прочитав спецификацию C. Попробуй!

§6.5.6 аддитивные операторы, пункт 8:

когда выражение с целочисленным типом добавляется или вычитается из Указателя, результат имеет тип указателя операнда. Если операнд указателя указывает на элемент объекта array, а массив достаточно большой, результат указывает на смещение элемента от исходный элемент такой, что разница индексов результирующие и исходные элементы массива равны целочисленному выражению.


вводится массив/указатель. Компилятор знает, насколько велика "вещь", в данном случае ваша структура.

и C просто определяется таким образом; продвижение указателя на "один" перейдет к следующей вещи в массиве. Компилятор знает, как далеко можно зайти. Это относится к любому из связанных и эквивалентный синтаксис:

*(arr + i)
arr[i]
i[arr]

для любого типа, о котором знает компилятор.

Это называется "арифметика указателя", и он имеет по крайней мере еще одно забавное свойство: если у вас есть два указателя на элементы в массив, вы можете вычесть их, чтобы получить количество элементов между ними, в объектах (т. е. не байт).


arr объявляется как массив из 4 структур с каждой структурой, состоящей из массива символов 1024 символов.

Арр рассматривается как указатель на первый элемент этого массива структур. При увеличении arr на 1 Этот новый указатель пропустит всю структуру (тип, на который он указывает), а затем указывает на следующий элемент массива.

все сводится к тому, что компилятор знает тип, на который указывает указатель, а затем, если вы увеличиваете массив, он будет указывать на следующий элемент подобного типа в непрерывной области памяти.

в этом случае, если базовый адрес массива XYZ, то arr+ i = XYZ + i * sizeof(arr)/sizeof (struct large)