|
Определение размера массива на этапе компиляции, Задачка |
|
|
|
Sep 10 2012, 07:02
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Не уверен, в тот ли форум написал - не нашёл специализированного подфорума по программированию, есть этот и ещё в разделе по DSP. Вопрос чисто по программированию на С/С++. Задача. Есть энное количество массивов. Тип элемента массива в данном случае не важен (на практике он может быть любым - в частности, у меня это небольшая структура), поэтому в примере будет просто int. Длины массивов произвольные. Обработка данных из массивов возложена на функцию. Вариант на голом С. CODE int A[] = { 1, 2, 3 }; int B[] = { 4, 5 }; int C[] = { 6 }; int D[] = { 7, 8, 9, 0 }; ... // и т.д.
void f(int *p, size_t size) { ... } вызов (пример): CODE f(A, sizeof(A)); Очевидный недостаток - нужно руками задавать правильный размер массива. При достаточно большом количестве массивов и вызовов, а также при интенсивном редактировании этого кода (особенно, когда обычным спутником такого редактирования является метод copy'n'paste), можно легко передать адрес одного массива, а размер другого, просто не уследив глазами за именами в аргументах. Хочется избавиться от этого недостатка. Очевидное решение в стиле С - использовать макроподстановку препроцессора: CODE #define PASS_ARRAY(a) a, sizeof(a)
f(PASS_ARRAY(A)); Это в некотором смысле получше, но есть свои минусы: препроцессор игнорирует пространства имён - возможен конфликт имён, макросу лучше задавать такое имя, чтобы оно было поуникальнее (а значит, подлиннее, поуродливее, сильнее загромождающее код), но самое главное то, что препроцессор не производит контроль типов и если на вход подать не массив, а указатель, то результат работы функции будет ошибочным при полном отсутствии ругани со стороны компилятора. В общем, основная проблема в низкоуровневом представлении массива на С, который при передаче в функцию даунгрейдится до указателя и внутри функции уже видится просто как адрес на объект своего типа. Хочется обойти этот недостаток - ведь в точке вызова-то у компилятора вся информация о массиве, переданном в качестве аргумента, есть. Вопрос. Имеется ли тут хорошее решение на С или С++. И если имеется, то какое? P.S. Забегая вперёд, скажу, от ответ знаю, но, во-первых, возможно есть и другие, получше, поинтереснее, во-вторых, сама по себе задачка, имхо, очень интересная и достойная того, чтобы поломать немножко над ней голову, тем более, что практическое решение явно полезно, а не просто академическая головоломка.  P.P.S Если кто-то знает решение с ходу, просьба не сообщать его сразу - дайте другим тоже потерзать задачку. Сообщите только, что знаете решение (это, возможно, лучше мотивирует других решателей).
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
 |
Ответов
|
Sep 11 2012, 07:47
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
QUOTE Допустим, у нас есть настоящий честный двумерный массив А[10][20]. Что возвращает A + 1? Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: CODE int (*a)[5][6];
(*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 11 2012, 08:31
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (Rst7 @ Sep 11 2012, 14:47)  Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Например, язык пакета Matlab. Или какой-нибудь другой высокоуровневый язык (тот же питон с библиотекой numpy). В низкоуровенвых языках, как С/C++, паскаль и подобных, представление соответствует уровню, т.е. является тоже низкоуровневым - непрерывная область памяти с элементами одного и того же типа. Максимум что они позволяют - массивы массивов. Тем не менее концепция двумерного массива никуда не девается. В мире полно объектов, которые описываются именно двумерным массивом, а не массивом массивов. Попытка адресоваться по одной координате всегда приводит к декомпозиции исходного типа и он перестаёт существовать. Например, есть объект - точка на экране. Она характеризуется двумя координатами. И изображение на экране - это двумерный массив этих точек. Попытка обращаться только через одну координату автоматически переводит адресуемый элемент из точки в строку или столбец. Нормальное представление двумерного массива вполне допускает обращение к его фрагментам - строкам, столбцам и просто прямоугольным фрагментам, и предоставляет для этого соответствующие средства (slice). Вы показывали, как ловко на С получить строку из "двумерного" массива. Покажите, как получить столбец? Или прямоугольный фрагмент? QUOTE (Rst7 @ Sep 11 2012, 14:47)  Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: CODE int (*a)[5][6];
(*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Настоящий двумерный массив в принципе не поддерживает такую нотацию обращения - через разыменовывание. QUOTE (Rst7 @ Sep 11 2012, 14:47)  Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу. Самая эта тема сутью задачи подчёркивает эту разницу.  Собственно, возвращаемся к точке начала спора. Спор о терминах. Понимание сути у всех есть. Двумерных массивов в С/C++ нет. Есть массивы массивов. Разница между ними есть. В ряде случаев массив массивов может использоваться в качестве двумерного массива с некоторыми ограничениями. Учитывая этот контекст, вполне допустимо употреблять термин "двумерный массив" для краткости (и лучше оговаривать сразу, что имеется в виду), но всегда помнить, что за этим стоит. На этом предлагают дискуссию закончить, дабы не тратить время и ходить по кругу.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
Сообщений в этой теме
dxp Определение размера массива на этапе компиляции Sep 10 2012, 07:02 Сергей Борщ QUOTE (dxp @ Sep 10 2012, 10:02) P.P.S Ес... Sep 10 2012, 08:13 gerber Для работы с массивом на С совсем необязательно зн... Sep 10 2012, 08:40 dxp QUOTE (gerber @ Sep 10 2012, 15:40) Для р... Sep 10 2012, 09:05  gerber Цитата(dxp @ Sep 10 2012, 13:05) Вот как... Sep 10 2012, 12:46   _Артём_ Цитата(gerber @ Sep 10 2012, 15:46) Тогда... Sep 10 2012, 12:56   ViKo Цитата(gerber @ Sep 10 2012, 15:46) Элеме... Sep 10 2012, 12:59 _Pasha Не пользовался (юзал только препроцессор), но в GC... Sep 10 2012, 11:56 dxp QUOTE (_Pasha @ Sep 10 2012, 18:56) Не по... Sep 10 2012, 12:26  MrYuran Цитата(dxp @ Sep 10 2012, 16:26) А как в ... Sep 10 2012, 13:14  _Pasha Цитата(dxp @ Sep 10 2012, 15:26) А как в ... Sep 10 2012, 13:41   dxp QUOTE (_Pasha @ Sep 10 2012, 20:41) Ответ... Sep 10 2012, 15:54    _Pasha Цитата(dxp @ Sep 10 2012, 18:54) Наскольк... Sep 10 2012, 18:35 ig_z QUOTE (dxp @ Sep 10 2012, 10:02) Вопрос. ... Sep 10 2012, 12:59 kurtis 1. В нулевом элементе хранить размер массива.
2. Е... Sep 10 2012, 14:40 dxp QUOTE (gerber @ Sep 10 2012, 19:46) Элеме... Sep 10 2012, 15:13 Xenia Всё это - палиативные решения. Окажется массив дву... Sep 10 2012, 15:29 kurtis Так какой правильный ответ? Sep 10 2012, 15:36 amaora С макросами я бы делал как-то вот так.
Код#define... Sep 10 2012, 16:12 Rst7 QUOTE Двумерных массивов в С/С++ не бывает.
Шутит... Sep 10 2012, 17:02 ViKo Я бы пользовался макроподстановкой, описанной в пе... Sep 10 2012, 18:16 Xenia Еще бы темплейты задействовать Sep 10 2012, 18:31 dxp QUOTE (Rst7 @ Sep 11 2012, 00:02) Шутить ... Sep 11 2012, 00:59 Rst7 QUOTE Для настоящего (тру Ъ) двумерного массива но... Sep 11 2012, 03:35 dxp QUOTE (Rst7 @ Sep 11 2012, 10:35) Ну, во-... Sep 11 2012, 04:37 Rst7 QUOTE Повторять всё обилие различий не хочется, ту... Sep 11 2012, 05:04 dxp QUOTE (Rst7 @ Sep 11 2012, 12:04) Наприме... Sep 11 2012, 05:31 dxp Наверное, пришло время обнародовать решение, как в... Sep 11 2012, 10:09 kurtis А чем это принципиально отличается от sizeof(a)/si... Sep 11 2012, 11:46 dxp QUOTE (kurtis @ Sep 11 2012, 18:46) А чем... Sep 11 2012, 11:51 kurtis Опять не понял
Код#include <iostream>
te... Sep 11 2012, 11:57 dxp QUOTE (kurtis @ Sep 11 2012, 18:57) Опять... Sep 11 2012, 15:22  ViKo Цитата(dxp @ Sep 11 2012, 18:22) Именно т... Sep 11 2012, 17:03   _Pasha Цитата(ViKo @ Sep 11 2012, 20:03) Такая ж... Sep 11 2012, 19:17   dxp QUOTE (ViKo @ Sep 12 2012, 00:03) Такая ж... Sep 12 2012, 01:36    ViKo Цитата(dxp @ Sep 12 2012, 04:36) В том-то... Sep 12 2012, 04:38 MrYuran Закорючка лишняя.
Либо если уж разыменовывать, то ... Sep 11 2012, 12:37 amaora А компиляторы C++ уже способны это оптимизировать?... Sep 11 2012, 14:07 kurtis ЦитатаЗаведите массив внутри вашей функции и перед... Sep 11 2012, 17:20 AHTOXA Цитата(kurtis @ Sep 11 2012, 23:20) Может... Sep 11 2012, 18:30 kurtis Чем это принципиально отличается от sizeof и как м... Sep 11 2012, 19:04 AHTOXA Цитата(kurtis @ Sep 12 2012, 01:04) Чем э... Sep 12 2012, 03:51 kurtis Медлено начинаю понимать...
Код#include <iost... Sep 12 2012, 03:41 kurtis Спасибо. Ситуация начинает проясняться.
Да, в так... Sep 12 2012, 03:57
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|