kurtis 0 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Так какой правильный ответ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Ответ лежит в личке. Посмотрел, спасибо. Насколько понял, это несколько не то - эта штука чекает размер с целью контроля переполнения памяти. Но она никак не поможет узнать размер массива внутри функции, которая видит указатель. Ну, и весьма частное решение, даже если бы делало то, что надо. Всё это - палиативные решения. Окажется массив двухмерным - опять возникнут проблемы пуще прежних. Двумерных массивов в С/С++ не бывает. Если решать проблему, то на корню. Создавать класс, в которую входит указатель на массив Не нужно придумывать условия задачи. Они уже определены и вполне однозначны и просты. И решение есть, простое и эффективное. Так какой правильный ответ? Давайте ещё немножко подождём, до завтра, до середины дня, пусть хотя бы сутки будут на решение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 24 10 сентября, 2012 Опубликовано 10 сентября, 2012 (изменено) · Жалоба С макросами я бы делал как-то вот так. #define AR(a) (struct ar __a = {(void *) (a), sizeof(a)}, __a) struct ar { void *p; int sz; }; #define FOO(a) foo(AR(a)) void foo(struct ar a); ... int A[] = {1, 2, 3}; FOO(A); Точнее я бы так не делал :) Обычно можно проще, но для этого надо видеть всю задачу, в такой постановке ничего не поделать. Изменено 10 сентября, 2012 пользователем amaora Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Двумерных массивов в С/С++ не бывает. Шутить изволите? int A[5][6]; int main() { A[2][3]=123; A[4][2]=456; A[2][4]=789; ... 24 int A[5][6]; \ A: \ 00000000 DS8 120 ... \ 00000004 .... LDR.N R0,??DataTable0 \ 00000006 7B21 MOVS R1,#+123 \ 00000008 C163 STR R1,[R0, #+60] 29 A[4][2]=456; \ 0000000A 4FF4E471 MOV R1,#+456 \ 0000000E 8166 STR R1,[R0, #+104] 30 A[2][4]=789; \ 00000010 40F21531 MOVW R1,#+789 \ 00000014 0164 STR R1,[R0, #+64] ... \ ??DataTable0: \ 00000000 ........ DC32 A Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов ;) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Я бы пользовался макроподстановкой, описанной в первом сообщении Но, если не нравится так, можно заменить саму функцию #define a_s(array) arr_sum(array, sizeof(array)/sizeof(array[0])) uint32_t arr_sum(uint32_t *p, uint32_t s); ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 45 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Еще бы темплейты задействовать :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 10 сентября, 2012 Опубликовано 10 сентября, 2012 · Жалоба Насколько понял, это несколько не то - эта штука чекает размер с целью контроля переполнения памяти. По идее, она возвращает размер, тип возврата - size_t. Вроде всё ОК. А дальше по Жванецкому: включаем - не работает. :( Странно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Шутить изволите? Ничуть. int A[5][6]; int main() { A[2][3]=123; A[4][2]=456; A[2][4]=789; ... [...] Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов ;) Именно. А массив массивов - это ни разу не двумерный массив. sizeof элемента массива всегда один и тот же по определению (т.к. массив - агрегатный объект, состоящий из элементов одного типа). Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель). Помнится, на фидоэхе su.с-сpp один очень квалифицированный человек весьма наглядно и на примерах показал ключевую разницу между этими вещами и к чему приводит неверная трактовка. Впрочем, соглашусь с тем, что сам по себе термин "двумерный массив" в C/C++ вполне имеет право быть, только нужно всегда иметь в виду контекст применения этого термина. Еще бы темплейты задействовать :) Это мысль в правильном направлении. По идее, она возвращает размер, тип возврата - size_t. Вроде всё ОК. А дальше по Жванецкому: включаем - не работает. :( Странно. Она-то возвращает, но ей надо видеть определение объекта в точке вызова. Если это сделать при вызове функции - при передаче аргументов, то оно сработает, но ровно так же работает и sizeof(), с этим нет проблем. А вот внутри функции аргумент вырождается в указатель - что оно тут сможет извлечь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель). Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит. Хотите получить sizeof элемента - так и берите элемент - a[j]. sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве. Все четко и логично. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит. Хотите получить sizeof элемента - так и берите элемент - a[j]. sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве. Все четко и логично. Будь это настоящим двумерным массивом, операция a + 1 давала бы адрес следующего элемента, а в нашем случае это будет адрес следующего массива. Разница существенная. Повторять всё обилие различий не хочется, тут подробнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Повторять всё обилие различий не хочется, тут подробнее. Бред там написан. Будь А полноценным двумерным массивом - т.е. законченным, целостным объектом, то выражение: А + 1 означало бы адрес следующего такого двумерного массива, Например, int A[10]; и последующее выражение A+1 указывает не на A[10], а на A[1], так почему там требуют другого поведения, соответствующему, кстати, указателю на двумерный массив? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Например, int A[10]; и последующее выражение A+1 указывает не на A[10], а на A[1], так почему там требуют другого поведения, соответствующему, кстати, указателю на двумерный массив? Допустим, у нас есть настоящий честный двумерный массив А[10][20]. Что возвращает A + 1? И что возвращает это выражение в случае сишного массива? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Допустим, у нас есть настоящий честный двумерный массив А[10][20]. Что возвращает A + 1? Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: int (*a)[5][6]; (*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Например, язык пакета Matlab. Или какой-нибудь другой высокоуровневый язык (тот же питон с библиотекой numpy). В низкоуровенвых языках, как С/C++, паскаль и подобных, представление соответствует уровню, т.е. является тоже низкоуровневым - непрерывная область памяти с элементами одного и того же типа. Максимум что они позволяют - массивы массивов. Тем не менее концепция двумерного массива никуда не девается. В мире полно объектов, которые описываются именно двумерным массивом, а не массивом массивов. Попытка адресоваться по одной координате всегда приводит к декомпозиции исходного типа и он перестаёт существовать. Например, есть объект - точка на экране. Она характеризуется двумя координатами. И изображение на экране - это двумерный массив этих точек. Попытка обращаться только через одну координату автоматически переводит адресуемый элемент из точки в строку или столбец. Нормальное представление двумерного массива вполне допускает обращение к его фрагментам - строкам, столбцам и просто прямоугольным фрагментам, и предоставляет для этого соответствующие средства (slice). Вы показывали, как ловко на С получить строку из "двумерного" массива. Покажите, как получить столбец? Или прямоугольный фрагмент? Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: int (*a)[5][6]; (*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Настоящий двумерный массив в принципе не поддерживает такую нотацию обращения - через разыменовывание. Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу. Самая эта тема сутью задачи подчёркивает эту разницу. :) Собственно, возвращаемся к точке начала спора. Спор о терминах. Понимание сути у всех есть. Двумерных массивов в С/C++ нет. Есть массивы массивов. Разница между ними есть. В ряде случаев массив массивов может использоваться в качестве двумерного массива с некоторыми ограничениями. Учитывая этот контекст, вполне допустимо употреблять термин "двумерный массив" для краткости (и лучше оговаривать сразу, что имеется в виду), но всегда помнить, что за этим стоит. На этом предлагают дискуссию закончить, дабы не тратить время и ходить по кругу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 65 11 сентября, 2012 Опубликовано 11 сентября, 2012 · Жалоба Наверное, пришло время обнародовать решение, как вчера было обещано. Решение на самом деле очень простое и эффективное. Выглядит так: template <typename T, size_t N> void f(T (&a)[N]) { ... // используем N - это длина массива } В общем случае это не тот размер, который возвращает sizeof(), а именно длина массива, но именно она-то и нужна. А размер получается тоже элементарно - N*sizeof(T). Всё на этапе компиляции. Возможно, не всем понятно, как это работает, поэтому краткое пояснение. В С++ инстанцирование функции по шаблону может быть явным, когда задаются параметры шаблона, и неявным, когда компилятор сам исходя из контекста использования, может сгенерировать реализацию. Именно вот такое неявное инстанцирование тут и используется. При этом вся информация у компилятора есть - есть объект-массив, про который всё известно - и тип элементов, и длина массива. Далее, ключевой момент: аргументом функции заявлена ссылка на массив, состоящий из элементов типа T и длиной N. Теперь в точке вызова: int A[] = { 1, 2, 3, 4 }; ... f(A); компилятор находит использование функции f(), ищет её реализацию, находит шаблон, анализирует контекст (а по контексту требуется именно массив - ссылка на него, а не указатель) и генерирует функцию f(int &а[4]). Всё, дело сделано. Поскольку параметры шаблона доступны внутри определения функции, то доступен и тип, и длина массива. Все действия производятся на этапе компиляции, т.е. получение длины массива достигается без единой инструкции, выполняемой на рантайме. Пример: template <typename T, int N> int len(T (& a)[N]) { return N; } const int a[] = {1,1,1,1,2,3,4,5,6}; // 9 элементов const int b[] = {1,1,1,5,6}; // 5 элементов volatile int d; void main() { d = len(a); d = len(b); } Результат (MSP430/IAR): d = len(a); 000000 B2400900.... MOV.W #0x9, &d d = len(b); 000006 B2400500.... MOV.W #0x5, &d Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться