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

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

30.11.2025, 18:33. Показов 3261. Ответов 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
10260 / 5684 / 1265
Регистрация: 12.03.2015
Сообщений: 26,366
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
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
30.11.2025, 20:04  [ТС]
Verevkin, про кратность - ну, да, возможно. Хотя, откуда он невыровненный появится.

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

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

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

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

Добавлено через 1 минуту
в "реальной жизни" такая задача никогда не нужна, это чисто интерес - "можно ли так", есть ли скрытые грабли
0
Злостный нарушитель
 Аватар для Verevkin
10260 / 5684 / 1265
Регистрация: 12.03.2015
Сообщений: 26,366
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
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,815
Записей в блоге: 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
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
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
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,815
Записей в блоге: 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
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
02.12.2025, 17:22  [ТС]
Цитата Сообщение от Igor3D Посмотреть сообщение
но и вообще покалечен
почему вдруг?

Особенно, если выровнять саму структура на 1 байт (у меня в примере этого нет, ага)
0
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,815
Записей в блоге: 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
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
03.12.2025, 06:51  [ТС]
Igor3D, зависит от ситуации.

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

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

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

Но чисто гипотетически вот такой вызов может произойти, тут нет криминала
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6156 / 2847 / 1042
Регистрация: 01.06.2021
Сообщений: 10,396
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
Сообщений: 866
03.12.2025, 18:23
Royal_X, даже прям захотелось собрать что нибудь под bc 3.1 под дос с моделью памяти huge и посмотреть как там компилятор делает сравнение дальних указателей. Вот честно я даже не помню.
0
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
03.12.2025, 18:43  [ТС]
Royal_X, там ведь так же будет всё через оператор < сравнено, разница разве будет ?

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

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

Решение

Цитата Сообщение от Алексей1153 Посмотреть сообщение
нет ли тут подводных камней?
Есть
3
фрилансер
 Аватар для Алексей1153
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
03.12.2025, 20:13  [ТС]
eva2326, ну, вот я что-то такое и имел в виду
0
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,815
Записей в блоге: 2
03.12.2025, 21:32
Цитата Сообщение от Алексей1153 Посмотреть сообщение
И я склоняюсь, что такая проверка - "нахожусь ли я в массиве" вообще не имеет смысла.
Совершенно нормальная, разумная задача. Вот только условия стартового поста (указатель + длина) не гарантируют что проверяемый - один из элементов массива/вектора. См намек в посте #7. Проверка на кратность недостоверна, т.е, может сработать а может и нет.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12931 / 6799 / 1820
Регистрация: 18.10.2014
Сообщений: 17,210
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
6449 / 5643 / 1129
Регистрация: 11.10.2019
Сообщений: 15,029
04.12.2025, 17:18  [ТС]
TheCalligrapher, принято

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

(Вспоминается защита от самокопирования, там обычно так смело if(this != &rhs))
0
1967 / 823 / 114
Регистрация: 01.10.2012
Сообщений: 4,815
Записей в блоге: 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
Ответ Создать тему
Новые блоги и статьи
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru