реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Определение размера массива на этапе компиляции, Задачка
dxp
сообщение Sep 10 2012, 07:02
Сообщение #1


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. Забегая вперёд, скажу, от ответ знаю, но, во-первых, возможно есть и другие, получше, поинтереснее, во-вторых, сама по себе задачка, имхо, очень интересная и достойная того, чтобы поломать немножко над ней голову, тем более, что практическое решение явно полезно, а не просто академическая головоломка. sm.gif

P.P.S Если кто-то знает решение с ходу, просьба не сообщать его сразу - дайте другим тоже потерзать задачку. Сообщите только, что знаете решение (это, возможно, лучше мотивирует других решателей). sm.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 10 2012, 08:13
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (dxp @ Sep 10 2012, 10:02) *
P.P.S Если кто-то знает решение с ходу, просьба не сообщать его сразу - дайте другим тоже потерзать задачку. Сообщите только, что знаете решение (это, возможно, лучше мотивирует других решателей). sm.gif
Вроде бы знаю, на плюсах...


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
gerber
сообщение Sep 10 2012, 08:40
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Для работы с массивом на С совсем необязательно знать его размер ... wink.gif


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 10 2012, 09:05
Сообщение #4


Adept
******

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



QUOTE (gerber @ Sep 10 2012, 15:40) *
Для работы с массивом на С совсем необязательно знать его размер ... wink.gif

Вот как! А как, например, обработать все элементы массива? Скажем, подсчитать сумму элементов (если это инты)?

QUOTE (Сергей Борщ @ Sep 10 2012, 15:13) *
Вроде бы знаю, на плюсах...

Гуд, у тебя в асе спрошу. sm.gif

Добавлено:

Сергей Борщ - зачёт! sm.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Sep 10 2012, 11:56
Сообщение #5


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Не пользовался (юзал только препроцессор), но в GCC - элементарно.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 10 2012, 12:26
Сообщение #6


Adept
******

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



QUOTE (_Pasha @ Sep 10 2012, 18:56) *
Не пользовался (юзал только препроцессор), но в GCC - элементарно.

А как в GCC? Там какой-то свой язык С/С++?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
gerber
сообщение Sep 10 2012, 12:46
Сообщение #7


Знающий
****

Группа: Участник
Сообщений: 750
Регистрация: 1-11-11
Пользователь №: 68 088



Цитата(dxp @ Sep 10 2012, 13:05) *
Вот как! А как, например, обработать все элементы массива? Скажем, подсчитать сумму элементов (если это инты)?

Элементарно. Должен быть маркер последнего элемента массива. Как у "нуль-терминированных" строк. Если это массив указателей - нулевой указатель. Тогда перебор всех элементов массива идёт не циклом for, а циклом while.
С массивом произвольных интов сложнее, но на практике совсем произвольных данных не бывает rolleyes.gif , поэтому всегда по смыслу можно подобрать значение, годящееся на роль терминатора массива.


--------------------
"... часами я мог наблюдать, как люди работают." (М. Горький)
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Sep 10 2012, 12:56
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(gerber @ Sep 10 2012, 15:46) *
Тогда перебор всех элементов массива идёт не циклом for, а циклом while.

А почему for нельзя? У for есть какие-то ограничения не позволяющие его использовать?
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 10 2012, 12:59
Сообщение #9


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(gerber @ Sep 10 2012, 15:46) *
Элементарно. Должен быть маркер последнего элемента массива...

Вы изобретаете нечто, как минимум, не универсальное.
Go to the top of the page
 
+Quote Post
ig_z
сообщение Sep 10 2012, 12:59
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 437
Регистрация: 27-08-04
Пользователь №: 551



QUOTE (dxp @ Sep 10 2012, 10:02) *
Вопрос. Имеется ли тут хорошее решение на С или С++. И если имеется, то какое?

P.P.S Если кто-то знает решение с ходу, просьба не сообщать его сразу - дайте другим тоже потерзать задачку. Сообщите только, что знаете решение (это, возможно, лучше мотивирует других решателей). sm.gif


На с++ есть, и это решение давно присутствует в бусте ессно sm.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Sep 10 2012, 13:14
Сообщение #11


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(dxp @ Sep 10 2012, 16:26) *
А как в GCC? Там какой-то свой язык С/С++?

B GCC4.7 заявлена поддержка С++0х, в котором заявлена реализация циклов foreach

Но это по слухам.

Что ещё приходит в голову...
Завернуть массив в структуру, состоящую из собственно массива и константного поля длины.
Надеяться, что оптимизатор выкинет второе поле, подставив длину по месту.
Это если просто в си


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Sep 10 2012, 13:41
Сообщение #12


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(dxp @ Sep 10 2012, 15:26) *
А как в GCC? Там какой-то свой язык С/С++?

Ответ лежит в личке.

Цитата(MrYuran @ Sep 10 2012, 16:14) *
Завернуть массив в структуру, состоящую из собственно массива и константного поля длины.
Надеяться, что оптимизатор выкинет второе поле, подставив длину по месту.
Это если просто в си

Если сравнить с дефайном, то это хуже.
Go to the top of the page
 
+Quote Post
kurtis
сообщение Sep 10 2012, 14:40
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 466
Регистрация: 21-06-05
Пользователь №: 6 205



1. В нулевом элементе хранить размер массива.
2. Если используются сложные типы данных, то можно использовать связанный список, если не подразумевается извлечение произвольного элемента, или время извлечения элемента не критична.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 10 2012, 15:13
Сообщение #14


Adept
******

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



QUOTE (gerber @ Sep 10 2012, 19:46) *
Элементарно. Должен быть маркер последнего элемента массива. Как у "нуль-терминированных" строк. Если это массив указателей - нулевой указатель. Тогда перебор всех элементов массива идёт не циклом for, а циклом while.
С массивом произвольных интов сложнее, но на практике совсем произвольных данных не бывает rolleyes.gif , поэтому всегда по смыслу можно подобрать значение, годящееся на роль терминатора массива.

Это вы придумываете условия задачи. Исходно массивы есть как есть, и тип элемента в них может быть произвольным. Никаких предположений о возможности изменения содержимого первого или терминальнго элементов делать нельзя. Да и не нужно тут это - применять рантаймные проверки там, где вся информация о размере есть у комилятора на этапе компиляции и доступна в точке вызова. Задача лишь в том, чтобы автоматом доставить эту информацию внутрь функции.

QUOTE (ig_z @ Sep 10 2012, 19:59) *
На с++ есть, и это решение давно присутствует в бусте ессно sm.gif

Вам зачёт! sm.gif


Вижу, что решение многим известно, но пока не будем открывать, пусть для желающих останется некий challenge. В принципе, уже ясно, что в сети решение найти не проблема, но у нас тут спорт и от всех ожидается спортивное поведение. sm.gif


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 10 2012, 15:29
Сообщение #15


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Всё это - палиативные решения. Окажется массив двухмерным - опять возникнут проблемы пуще прежних.

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

А в пределе можно встроить в этот класс частно используемые фукции, типа обнуления, инициализации константой, умножения на число, нахождение суммы, минимального и максимального элемента и т.д. А при должном уровне упорства sm.gif определить операции над такими массивами на матричный манер - реализовать их умножение, разложение на множители, FFT и прочие преобразования, и очень много еще чего другого на собственный вкус.

Если не лезть на рожон (не определять функции вируальными), то компилятор будет компилировать только те функции класса, которые находят спрос в конкретной программе. Поэтому "излишества" не помешают, зато создадут удобную среду для работы.
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 7th July 2025 - 21:36
Рейтинг@Mail.ru


Страница сгенерированна за 0.06887 секунд с 7
ELECTRONIX ©2004-2016