Почему 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)