Форум программистов, компьютерный форум, киберфорум
C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/1: Рейтинг темы: голосов - 1, средняя оценка - 5.00
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128

Легальность проверки указателя на нахождение внутри массива

30.11.2025, 18:33. Показов 6886. Ответов 24
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Допустим, имеется указатель на начало массива и длина массива.
C++
1
2
A* begin;
size_t size;
Также имеется указатель на некоторый одиночный объект
C++
1
A* item;
Насколько легальна вот такая "проверка на нахождение внутри массива" ?

C++
1
2
3
4
if(item >= begin && item < begin+size)
{
    //элемент принадлежит массиву
}
нет ли тут подводных камней?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.11.2025, 18:33
Ответы с готовыми решениями:

Как из неизменяемого указателя – имя массива и смещения указателя заполнить массив случайными числами
Как с помощью неизменяемого указателя – имя массива и смещения указателя заполнить массив...

Перезаписать память начиная с указателя Bitmap[1] элементами начиная с указателя Bitmap[0]
Задан массив из 3 указателей Bitmap, по адресу Bitmap необходимо записать 480*640 элементов из...

Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на абстрактный класс А ...
Написать обработчик исключений ситуации при преобразовании указателя на класс B до указателя на...

24
Злостный нарушитель
 Аватар для Verevkin
10637 / 5788 / 1277
Регистрация: 12.03.2015
Сообщений: 26,723
30.11.2025, 19:35
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Насколько легальна вот такая "проверка на нахождение внутри массива" ?
Это не запрещено. А что не запрещено, то легально.
Цитата Сообщение от Алексей1153 Посмотреть сообщение
нет ли тут подводных камней?
Массив - это непрерывный кусок памяти размером <кол-во элементов> * sizeof(тип элемента) байт. Весь вопрос в том, где ты берёшь значение указателя, ведь это адрес, не привязанный к типу. Теоретически он может быть между началом и концом, но указывать не на начало элемента. Нужно проверять кратность размеру элемента.

C++
1
2
3
4
5
6
bool is_item(A* begin, A* item, size_t size)
{
  //элемент принадлежит массиву?
  return (item >= begin) && (item < begin + size) &&
         !((intptr_t(item) - intptr_t(begin)) % sizeof(A));
}
0
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
30.11.2025, 20:04  [ТС]
Verevkin, про кратность - ну, да, возможно. Хотя, откуда он невыровненный появится.

С этим моментом достаточно просто побороться - скастить к char* да проверить в байтах.

Смущает другое: арифметика укзазателей имеет смысл только тогда, когда указуемые элементы лежат в одном массиве.

Поэтому интересен ответ с точки зрения знатоков стандарта - легально ли вот такое сравнение

Добавлено через 1 минуту
Цитата Сообщение от Verevkin Посмотреть сообщение
ведь это адрес, не привязанный к типу
нет, в данном примере тип один и тот же.

Добавлено через 1 минуту
в "реальной жизни" такая задача никогда не нужна, это чисто интерес - "можно ли так", есть ли скрытые грабли
0
Злостный нарушитель
 Аватар для Verevkin
10637 / 5788 / 1277
Регистрация: 12.03.2015
Сообщений: 26,723
30.11.2025, 20:13
Цитата Сообщение от Алексей1153 Посмотреть сообщение
Хотя, откуда он невыровненный появится.
Программирование - такая штука, что любая хренотень может появиться когда и где угодно. Я ж не знаю, зачем автору вот это вот всё.
Цитата Сообщение от Алексей1153 Посмотреть сообщение
нет, в данном примере тип один и тот же.
Мож он хочет там сравнивать адреса из разных массивов, неизвестно как выровненных и неизвестно в какой области памяти и архитектуре.
Поэтому, я б наколхозил чото такое:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
 
typedef  uint64_t A;
 
bool is_item(A* begin, A* item, size_t count)
{
  //элемент принадлежит массиву?
  bool result = (item >= begin) && 
                (item < begin + count) &&
                !((intptr_t(item) - intptr_t(begin)) % sizeof(A));
                
  if (result) 
  {
    size_t idx = (intptr_t(item) - intptr_t(begin)) / sizeof(A);
    printf("%p is item[%u] = %zu of array [%p]\n",
           item, idx, *item, begin); 
  }
  else     
    printf("%p is NOT item of array [%p]\n", item, begin);   
    
  return result;
}
 
 
int main()
{
  A begin[] = {1, 2, 3, 4, 5};
  const auto count = sizeof(begin) / sizeof(A);
  A* item1 = &begin[2]; // 3
  auto item2 = (A*)((unsigned char*)(&begin[2]) + 1); // +1 байт
  
  is_item(begin, item1, count); 
  is_item(begin, item2, count); 
 
  return 0;
}
0
1972 / 828 / 115
Регистрация: 01.10.2012
Сообщений: 4,969
Записей в блоге: 2
02.12.2025, 06:06
Интереснее такой вопрос
C++
1
2
3
4
//элемент принадлежит массиву?
  bool result = (item >= begin) && 
                (item < begin + count) &&
                !((intptr_t(item) - intptr_t(begin)) % sizeof(A))
Приведите пример когда первые 2 условия выполняются, а последнее нет (невыровненный)
0
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
02.12.2025, 07:19  [ТС]
Igor3D, ну, да, ситуация редкая. Но, к примеру, последние два вызова будут false
https://onlinegdb.com/1qSsIbUfJ

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
 
struct A
{
    int n1;
    int n2;
};
 
bool ArrayContainsTheItem(const A* begin , size_t size, const A* item)
{
    if(item >= begin && item < begin+size)
    {
        //проверяем выравнивание
        const auto offset=((const char*)item) - ((const char*)begin);
        if(offset%sizeof(A) == 0)
        {
            //элемент принадлежит массиву
            return true;
        }
    }
    return false;
}
 
int main()
{
    A arr[10];
    A a;
 
    std::cout<<std::boolalpha;
    
    std::cout<<ArrayContainsTheItem(arr,std::size(arr),&arr[5])<<'\n';//true
    std::cout<<ArrayContainsTheItem(arr,std::size(arr),&a)<<'\n';//false
 
    char C[10 * sizeof(A)]{};
    auto begin = (const A*)C;
    auto size = std::size(C)/sizeof(A);
    auto item0 = (const A*)(C+0);
    auto item1 = (const A*)(C+1);
    auto item2 = (const A*)(C+2);
    
    std::cout<<ArrayContainsTheItem(begin,size,item0)<<'\n';//true
    std::cout<<ArrayContainsTheItem(begin,size,item1)<<'\n';//false - невыровнено
    std::cout<<ArrayContainsTheItem(begin,size,item2)<<'\n';//false - невыровнено
}
0
1972 / 828 / 115
Регистрация: 01.10.2012
Сообщений: 4,969
Записей в блоге: 2
02.12.2025, 16:42
Цитата Сообщение от Алексей1153 Посмотреть сообщение
auto item1 = (const A*)(C+1);
С такими бандитскими приведениями item1 не только не выровнен, но и вообще покалечен. Ниже никакого насилия - но последнее условие (с3) false
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
int main()
{
// объявите контейнер test
    const A * begin = &test[0];
    const A * target = &test[1];
    
    bool c1 = (target - begin > 0);
    bool c2 = (target < begin + 10);
    bool c3 = (((char *) target - (char *) begin) % sizeof(A) == 0);
    printf("%d, %d, %d\n", int(c1), int(c2), int(c3));
 
    return 0;
}
Добавлено через 30 минут

Не по теме:

Цитата Сообщение от Алексей1153 Посмотреть сообщение
auto item2 = (const A*)(C+2);
Хотя с др стороны.. В каком-нибудь расте или хаскеле так наверняка нельзя. А тут если надоело все - достал ножик и порубал в капусту! Свобода!

0
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
02.12.2025, 17:22  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
но и вообще покалечен
почему вдруг?

Особенно, если выровнять саму структура на 1 байт (у меня в примере этого нет, ага)
0
1972 / 828 / 115
Регистрация: 01.10.2012
Сообщений: 4,969
Записей в блоге: 2
03.12.2025, 00:24
Цитата Сообщение от Алексей1153 Посмотреть сообщение
почему вдруг?
C++
1
2
3
4
5
char C[10 * sizeof(A)]{};
...
auto item0 = (const A*)(C+0);
auto item1 = (const A*)(C+1);
auto item2 = (const A*)(C+2);
Потому что С для адресной арифметики char *, item0 - адрес первого, остальные 2 - порезанные уроды со смещением 1 и 2 байта от первого
0
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
03.12.2025, 06:51  [ТС]
Igor3D, зависит от ситуации.

К примеру, это сырой поток данных, и мы сканируем его, пытаясь найти валидное содержимое для A, внутри которого, к примеру, есть преамбула и CRC. Мы так и будем по байтику двигаться и анализировать

Это ничего не ломает

Правда, при этом нет никакой необходимости проверять нахождение в массиве.

Но чисто гипотетически вот такой вызов может произойти, тут нет криминала
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6234 / 2943 / 1047
Регистрация: 01.06.2021
Сообщений: 10,938
03.12.2025, 17:01
Цитата Сообщение от Алексей1153 Посмотреть сообщение
C++
1
if(item >= begin && item < begin+size)
мне кажется, лучше так проверять

C++
1
if (std::less_equal<A*>{}(begin, item) && std::less<A*>{}(item, begin + size))
так можно гарантированно избежать UB. Просто я вот думаю, что на некоторых платформах память может быть сегментированной.
0
267 / 199 / 30
Регистрация: 26.11.2022
Сообщений: 869
03.12.2025, 18:23
Royal_X, даже прям захотелось собрать что нибудь под bc 3.1 под дос с моделью памяти huge и посмотреть как там компилятор делает сравнение дальних указателей. Вот честно я даже не помню.
0
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
03.12.2025, 18:43  [ТС]
Royal_X, там ведь так же будет всё через оператор < сравнено, разница разве будет ?

А UB тут изначально не было, вопрос был в осмысленности результата.

И я склоняюсь, что такая проверка - "нахожусь ли я в массиве" вообще не имеет смысла. Ведь это всегда известно по алгоритму
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6234 / 2943 / 1047
Регистрация: 01.06.2021
Сообщений: 10,938
03.12.2025, 19:05
Цитата Сообщение от Алексей1153 Посмотреть сообщение
, там ведь так же будет всё через оператор < сравнено, разница разве будет ?
на нормальной современной архитектуре так и будет. Т.е. твой изначальный код тоже норм. Но на какой-то дичевой архитектуре оператор < не обязан работать правильно в твоем коде. Однако, даже на таких архитектурах std::less должен работать правильно.
0
 Аватар для eva2326
1673 / 501 / 107
Регистрация: 17.05.2015
Сообщений: 1,519
03.12.2025, 19:49
Лучший ответ Сообщение было отмечено Алексей1153 как решение

Решение

Цитата Сообщение от Алексей1153 Посмотреть сообщение
нет ли тут подводных камней?
Есть
3
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
03.12.2025, 20:13  [ТС]
eva2326, ну, вот я что-то такое и имел в виду
0
1972 / 828 / 115
Регистрация: 01.10.2012
Сообщений: 4,969
Записей в блоге: 2
03.12.2025, 21:32
Цитата Сообщение от Алексей1153 Посмотреть сообщение
И я склоняюсь, что такая проверка - "нахожусь ли я в массиве" вообще не имеет смысла.
Совершенно нормальная, разумная задача. Вот только условия стартового поста (указатель + длина) не гарантируют что проверяемый - один из элементов массива/вектора. См намек в посте #7. Проверка на кратность недостоверна, т.е, может сработать а может и нет.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13182 / 6818 / 1821
Регистрация: 18.10.2014
Сообщений: 17,255
04.12.2025, 13:16
Лучший ответ Сообщение было отмечено Алексей1153 как решение

Решение

Цитата Сообщение от Алексей1153 Посмотреть сообщение
Насколько легальна вот такая "проверка на нахождение внутри массива" ?
Если элемент лежит за пределами массива, то такой код вызовет неопределенное поведение. То есть такая проверка "легальна", но бесполезна.

Глобальное упорядочение указателей без неопределенного поведения вам даст std::less. То есть вместо того, что у вас там написано, должно было быть

C++
1
2
3
4
if (!std::less()(item, begin) && std::less()(item, begin + size))
{
    //элемент принадлежит массиву
}
Конкретное упорядочение std::less определяется реализацией, но должно вести себя "как надо".

Добавлено через 4 минуты
Цитата Сообщение от Алексей1153 Посмотреть сообщение
там ведь так же будет всё через оператор < сравнено, разница разве будет ?
То там будет спрятано внутри вас интересовать не должно. Вас должно интересовать только то, что std::less не вызывает UB.

Цитата Сообщение от Алексей1153 Посмотреть сообщение
А UB тут изначально не было, вопрос был в осмысленности результата.
Не надо нести чушь. UB тут изначально наличествует, как говорится, во все воронье горло.
1
фрилансер
 Аватар для Алексей1153
6466 / 5683 / 1131
Регистрация: 11.10.2019
Сообщений: 15,128
04.12.2025, 17:18  [ТС]
TheCalligrapher, принято

Добавлено через 7 минут
TheCalligrapher, кстати, а проверять указатели на равенство, неравенство и прочее - тоже лучше стандартными функторами ?

(Вспоминается защита от самокопирования, там обычно так смело if(this != &rhs))
0
1972 / 828 / 115
Регистрация: 01.10.2012
Сообщений: 4,969
Записей в блоге: 2
04.12.2025, 17:32
Цитата Сообщение от Алексей1153 Посмотреть сообщение
а проверять указатели на равенство, неравенство и прочее - тоже лучше стандартными функторами ?
Есть хороший способ. Возьмите исходники либы которую Вы лично уважаете, напр то же Qt - и пишите в том же духе/стиле. И не давайте себя запугать
Цитата Сообщение от Алексей1153 Посмотреть сообщение
вот я что-то такое и имел в виду
Какое "такое"? День спустя Вы можете вспомнить хоть что-нибудь из той статьи? (я нет) Адресную арифметику никто не отменял. Переход на др адресную модель не актуален. "Фишки" типа std::less - пустая трата времени и внимания программиста. Если много говорит об UB - опасайтесь/избегайте таких
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
04.12.2025, 17:32
Помогаю со студенческими работами здесь

Преобразование кода без указателя в код с использованием указателя
Правильно ли выполнил? Исходный код без указателя #include &lt;iostream&gt; #include &lt;cstdlib&gt;...

Как сделать функцию от указателя на класс и указателя на метод?
Не получается сделать функцию, параметрами которой являются указатель на класс и на метод....

В чём отличие константного указателя и указателя на константу?
int *const p1 и int const* p2 Объясните мне в чём тут отличие.

Почему увеличение указателя на sizeof(тип) не тождественно инкременту этого же указателя?
Всем доброго дня.:) Можете обьяснить ,почему при инкриментировании указателя,его значение(адресс)...

Возвращение неконстантного указателя из константного указателя на строку
Не могу до конца понять один момент. Допустим, у нас есть функция searchSymbol, которая принимает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Вывод данных через динамический список в справочнике
Maks 01.04.2026
Реализация из решения ниже выполнена на примере нетипового справочника "Спецтехника" разработанного в конфигурации КА2. Задача: вывести данные из ТЧ нетипового документа. . .
Функция заполнения текстового поля в реквизите формы документа
Maks 01.04.2026
Алгоритм из решения ниже реализован на нетиповом документе "ВыдачаОборудованияНаСпецтехнику" разработанного в конфигурации КА2, в дополнении к предыдущему решению. На форме документа создается. . .
К слову об оптимизации
kumehtar 01.04.2026
Вспоминаю начало 2000-х, университет, когда я писал на Delphi. Тогда среди программистов на форумах активно обсуждали аккуратную работу с памятью: нужно было следить за переменными, вовремя. . .
Идея фильтра интернета (сервер = слой+фильтр).
Hrethgir 31.03.2026
Суть идеи заключается в том, чтобы запустить свой сервер, о чём я если честно мечтал давно и давно приобрёл книгу как это сделать. Но не было причин его запускать. Очумелые учёные напечатали на. . .
Модель здравосоХранения 6. ESG-повестка и устойчивое развитие; углублённый анализ кадрового бренда
anaschu 31.03.2026
В прикрепленном документе раздумья о том, как можно поменять модель в будущем
10 пpимет, которые всегда сбываются
Maks 31.03.2026
1. Чтобы, наконец, пришла маршрутка, надо закурить. Если сигарета последняя, маршрутка придет еще до второй затяжки даже вопреки расписанию. 2. Нaдоели зима и снег? Не надо переезжать. Достаточно. . .
Перемещение выделенных строк ТЧ из одного документа в другой
Maks 31.03.2026
Реализация из решения ниже выполнена на примере нетипового документа "ВыдачаОборудованияНаСпецтехнику" с единственной табличной частью "ОборудованиеИКомплектующие" разработанного в конфигурации КА2. . . .
Functional First Web Framework Suave
DevAlt 30.03.2026
Sauve. IO Апнулись до NET10. Из зависимостей один пакет, работает одинаково хорошо как в режиме проекта так и в интерактивном режиме. из сложностей - чисто функциональный подход. Решил. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru