2016-10-30 2 views
0

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

Есть ли способ определить, указывает ли указатель где-то внутри структуры? В этом случае мой массив A?

Я видел подобные вопросы относительно C++, но не с С.

+0

Возможно, есть еще один вопрос, задающий этот вопрос. Сорта. Стандарт не говорит, что это сработает, но если вы знаете начало массива, количество элементов и размер каждого элемента, а также указатель, который вы указали, тогда вы можете определить, находится ли данный указатель между начало и конец массива.Проблема в том, что если указатель находится за пределами диапазона, сравнения не гарантируются работой стандарта, хотя чаще всего в эти дни, на несегментированных машинах (большинство из них), на самом деле это работает. –

+0

Если вы имеете дело с массивами, почему бы не получить смещения? Я имею в виду, простое целое число, которое будет использоваться в качестве индекса. Таким образом, вы можете сэкономить на проверке принадлежности. –

ответ

3

Единственный переносимый способ - использовать тест равенства против всех возможных допустимых значений для указателя. Например:

int A[10]; 

bool points_to_A(int *ptr) 
{ 
    for (int i = 0; i < 10; ++i) 
     if (ptr == &A[i]) 
      return true; 

    return false; 
} 

Обратите внимание, что с помощью реляционного оператора (например, <) или вычитание, с двумя указателями не определено поведение, если два указателя на самом деле не делают точки к элементам одного и того же массива (или один его конец) ,

+0

Умный! Это избавляет от предупреждений – Bob

+0

'int array [100000];' ... Ouch! Но это то, что говорит стандарт. –

+0

Стоит также сказать, что вычитающие указатели (например, 'ptr - A') также дают неопределенное поведение, если оба указателя не принадлежат к одному и тому же массиву или не относятся к C++. –

1

В разделе §6.5.8 реляционные операторы, стандарт C11 (ISO/IEC 9899: 2011) говорит:

При сравнении двух указателей результат зависит от относительных местоположений в адресном пространстве объектов, на которые указывает. Если два указателя на типы объектов указывают на один и тот же объект или оба указывают один за последним элементом одного и того же объекта массива, они сравнивают равные. Если объекты, на которые указывают, являются членами одного и того же совокупного объекта, указатели на элементы структуры, объявленные позже, сравниваются больше, чем указатели на элементы, объявленные ранее в структуре, а указатели на элементы массива с большими значениями индекса сравниваются больше, чем указатели на элементы одного и того же массива с нижними значениями индекса. Все указатели на члены одного и того же объекта объединения сравниваются одинаково. Если выражение P указывает на элемент объекта массива, а выражение Q указывает на последний элемент того же объекта массива, выражение указателя Q+1 сравнивает более P. Во всех остальных случаях поведение не определено.

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

Обратите внимание, что для массива SomeType array[20];, адрес &array[20] гарантированно будет действительным и надежно сравнить с любым адресом из &array[0] через &array[19]. Вам нужно решить, хотите ли вы считать это как находящийся в вашем массиве.

В соответствии с замечанием, что стандарт не гарантирует, что он будет работать, то вы можете сравнить два int указателей:

int within_int_array(int *array, size_t num_ints, int *ptr) 
{ 
    return ptr >= array && ptr < array + num_ints; 
} 

В эти дни, вы должны быть более осторожным о вызове к неопределенному поведению. Компиляторы делают неприятные вещи для программ, которые используют неопределенное поведение, и технически, у вас нет возможности использовать средства, поскольку в стандарте указано «неопределенное поведение».

+0

Что касается вашего более раннего комментария о больших массивах [~ 100000]: если вам нужно было часто тестировать массив, не могли бы вы направить все действительные указатели на массив в 'uintptr_t' и построить хэш-таблицу. Затем, чтобы выяснить, указывает ли указатель 'p' на элемент массива, вы можете наложить' p' на 'uintptr_t', hash результат и проверить таблицу. Или это просто плохая идея? –

+1

@DavidBowling: Он может использоваться (хеш-таблица или что-то в этом роде), но я не могу не чувствовать, что было бы лучше знать, где ваши указатели указывают, а не столько инфраструктуры. –