2013-11-26 5 views
8

Допустит, я хочу выделить память для 3-х целых чисел:экранные переменные в выделенной памяти

int *pn = malloc(3 * sizeof(*pn)); 

Теперь присвоить им значение я сделать:

pn[0] = 5550; 
pn[1] = 11; 
pn[2] = 70000; 

Чтобы получить доступ к 2-ому значению я делаю:

pn[1] 

Но оператор [n] является просто ярлыком для * (a + n). Тогда это будет означать, что я получаю первый байт после индекса. Но int составляет 4 байта, поэтому shoudnt i do

*(a+sizeof(*a)*n) 

вместо этого? Как это работает?

+3

Абсолютно ничего не говорится о том, что '* (a + n)' работает в байтах; если «a» не является указателем байта, конечно. Вся арифметика указателя относится к типу указателя. – unwind

ответ

8

Хороший вопрос, но C автоматически умножит смещение на размер заостренного типа. Другими словами, когда вы доступ

p[n] 

для указателя, объявленного

T *p; 

вы получите доступ адрес p + (sizeof(T) * n) неявно.

13

Нет, компилятор позаботится об этом. Существуют специальные правила в арифметике указателя, и это один из них.

Если вы действительно хотите увеличить его на один байт, вам нужно наложить указатель на указатель на тип, который длится один байт (например, char).

+0

Должен ли каждый компилятор C делать это (это что-то строгое, стандартизованное)? –

+1

@ MichałTabor Да. –

+0

+1, а не только для явного упоминания арифметики * указателя *. – alk

1

Например, мы можем использовать стандарт C99, чтобы узнать, что происходит. В соответствии со стандартом C99:

6.5.2.1 индексации массивов
сдерживающих
- 1 Одно из выражений должны иметь тип «» указатель на объект типа «», другое выражение должно иметь целочисленный тип, и результат имеет тип '' type ''.
Семантика
- 2-выражение постфикса следует выражение в квадратных скобках [] является индексируются обозначение элемента объекта массива. Определение индекса оператора [] является то, что Е1 [Е2] идентичен (* ((E1) + (E2))). Из-за правила преобразования, которые применяются к бинарного оператора +, если Е1 является объектом массива (что эквивалентно, указатель на начальный элемент объекта массива) и Е2 представляет собой целое число, Е1 [Е2] обозначает E2-th элемент E1 (начиная с нуля).

И с 6.5.5.8 о правилах преобразования для оператора +:

Когда выражение, которое имеет целочисленный тип добавляется или вычитается из указателя, то результат имеет тип указателя операнда. Если операнд указателя указывает на элемент объекта массива, и массив достаточно велик, результат указывает на смещение элемента от исходного элемента таким образом, что разность индексов результирующего и исходного элементов массива равна целочисленное выражение. Другими словами, если выражение P указывает на i-й элемент объекта массива, выражения (P) + N (эквивалентно, N + (P)) и (P) -N (где N имеет значение n) указывают на, соответственно, i + n-й и i-n-ый элементы объекта массива при условии, что они существуют. Более того, если выражение P указывает на последний элемент объекта массива, выражение (P) +1 указывает один за последним элементом объекта массива , а если выражение Q указывает один за последним элементом массива object, выражение (Q) -1 указывает на последний элемент объекта массива. Если и указатель , и результат указывают на элементы одного и того же объекта массива или один за последний элемент объекта массива, оценка не должна приводить к переполнению; в противном случае поведение не определено. Если результат указывает один за последним элементом объекта массива, он не должен использоваться как операнд унарного * оператора, который оценивается, .

Таким образом, все эти заметки о вашем случае, и это работает точно так же, как вы написали, и вам не нужны специальные конструкции, разыменования или что-нибудь еще (указатели арифметика сделать это для вас):

pn[1] => *((pn)+(1)) 

Или, в терминах указателей байт (для упрощения описания того, что происходит), эта операция аналогична:

pn[1] => *(((char*)pn) + (1*sizeof(*pn))) 

Более того, вы можете получить доступ к этому элементу с 1[pn] и результатом будет са меня.

0

Вы не должны. Правила, которые происходят, когда вы добавляете int в указатель, не очевидны. Поэтому лучше не использовать свою интуицию, но читать языковые стандарты о том, что происходит в таких случаях. Например, читайте больше об указателе арифметики here (C) или here (C++).

Вскоре - указатель не пустот «измеряется» в единицах длины типа.

+0

Я был бы осторожен в этой странице, он говорит о C, но большая часть кода - C++. –

Смежные вопросы