| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > как передать массив в функцию по значению? |
| Автор: Dmitriy2k 30.3.2008, 11:29 |
| Подскажите, можно ли передать копию массива в функцию? т.е. обычно мы передаем в функцию как бы указатель на первый элемент массива и выглядит это так: FuncArray(int arr[][20]){ ... } main() { int a[2][20]; FuncArray(a); } мне же нужно чтобы передавалась в функцию копия массива, чтобы можно было в функции изменять значения элементов, не повреждая исходный массив. |
| Автор: bsa 30.3.2008, 11:38 | ||
|
| Автор: Dennnis 30.3.2008, 11:38 | ||||
или
|
| Автор: bsa 30.3.2008, 11:41 |
| Dennnis, во втором случае передачи идет по ссылке, по сути, тоже самое, что по указателю. |
| Автор: bsa 30.3.2008, 11:53 |
| Dennnis, да. Теперь уже передача по значению. |
| Автор: Dmitriy2k 30.3.2008, 14:50 | ||
Мне не очень понятно что означают угловые скобки. Я сколько писал на Си ни разу не встречал :( [quote] |
| Автор: bsa 30.3.2008, 22:59 | ||||
Это С++. std::vector - это шаблон динамического массива. В этой строчке, в частности, создание массива массивов int. |
| Автор: Rififi 30.3.2008, 23:43 | ||||
массив не является указателем на первый элемент а неявно приводится к нему компилятором. вот пример функцмии, в который передаётся сам массив, без потери информации о типе.
|
| Автор: bsa 31.3.2008, 11:40 |
| Rififi, читаем вопрос Dmitriy2k внимательно - речь идет о языке Си |
| Автор: Rififi 31.3.2008, 12:17 |
| bsa, а чего тогда ему советуют вектор? Для Си кроме отсутствия ссылочного типа ничего не меняется void f(int (*arr)[10]) { printf("%d элементов.\n", sizeof(*arr) / sizeof((*arr)[0])); } int arr[10]; FuncArray(&arr); |
| Автор: bsa 31.3.2008, 12:28 |
| Rififi, ты ему предлагаешь передать по указателю, а ему нужно по значению |
| Автор: Rififi 31.3.2008, 13:40 |
| чтобы передать "массив по-значению", нужно чтобы он был lvalue и/или имел конструктор копирования. а массив, как известно, не является lvalue, зато является POD-типом, следовательно, запрашиваемое в исходном вопросе невозможно. |
| Автор: UnrealMan 31.3.2008, 15:23 | ||
Это ты где такое вычитал? |
| Автор: Graf_h 31.3.2008, 16:39 |
Это честно говоря глупо |
| Автор: vinter 31.3.2008, 18:26 | ||||||
угу, это очень умно, особенно если учесть что
имя массива есть адрес первого элемента, т.е можно считать указателем.
чего? |
| Автор: Rififi 31.3.2008, 18:37 |
| vinter, процитированная фраза - это исключительно моё предположение, потому что я не знаю, что означает "передать массив по-значению". |
| Автор: bsa 31.3.2008, 21:15 | ||
Похоже, массив действительно нельзя передать по значению. Тогда придется либо через структуру извращаться, либо вручную создавать копию |
| Автор: JackFlamingo 31.3.2008, 21:33 |
| На мой взгляд, наиболее элегантное решение в отношении переносимости и понимаемости кода - это передать массив по ссылке с модификатором const, а затем ВРУЧНУЮ создать копию. |
| Автор: vinter 31.3.2008, 22:34 | ||
зачем? какой смысл тут от передачи по ссылке? |
| Автор: MAKCim 1.4.2008, 09:22 | ||||
а теперь посмотри ассемблерный листинг как бы мы не старались передать массив по значению, не получится единственный вариант - инкапсуляция
|
| Автор: Dmitriy2k 1.4.2008, 09:31 |
| Понятно. Спасибо за ответы. Ну чтож единственным вариантом является передача элемента структуры, содержащей массив, в функцию |
| Автор: UnrealMan 1.4.2008, 14:36 | ||||||||||||
А создать копию массива внутри функции религия не позволяет?
Имя массива - это не указатель.
Затем, что такая передача позволяет контролировать размерность (если она должна быть жёстко задана). Вместо ссылки на массив можно использовать указатель на массив (не путать с указателем на первый элемент). А может, лучше всё-таки в стандарт посмотреть?
Невозможно сделать параметр функции массивом. Всякий параметр, объявление которого выглядит, как объявление массива, на самом деле будет объявленным как указатель. Для массивов не существует copy-initialization, а именно copy-initialization выполняется при передаче параметра:
При отсутствии у массивов copy-initialization функция, параметром которой был бы массив, попросту никогда бы не могла быть вызвана. |
| Автор: Rififi 1.4.2008, 15:40 | ||||
MAKCim,
листинг доказывает только то, что массив и его первый элемент начинаются с одного адреса, "и чё дальше"?
во-первых, обьясни, что это значит, "массив по значению"? во-вторых, выше была приведена функция, которая получает массив на вход (да-да, именно сам массив, а ни какой не указатель) |
| Автор: vinter 1.4.2008, 19:15 |
причем тут это? причем тут константные ссылки? читай название топика Добавлено через 4 минуты и 42 секунды не будем играть терминами, это практически одно тоже, в случае одномерного. И не надо меня сейчас тыкать стандартом, и с пеной на губах доказывать что я не прав. На практике это работает точно так же, а значит это эквивалент ;) |
| Автор: UnrealMan 1.4.2008, 20:39 | ||||||
Ответ на поставленный в топике вопрос - никак. Всё, что тут можно предложить, - это обходное решение.
ну да, здесь
и здесь
вывод будет практически один и тот же |
| Автор: vinter 1.4.2008, 21:32 |
| UnrealMan, я не говорил что массивы ничем от указателей не отличаются, я сказал что имя массива можно считать указателем(константным). Специфика использования одинакова, и разница между ними не существенна.. |
| Автор: MAKCim 1.4.2008, 21:32 | ||||||
мне достаточно ассемблерного листинга
теперь понятно? если нет, объясню |
| Автор: Rififi 1.4.2008, 22:57 | ||
vinter,
int arr[10]; в этой записи имя 'arr' имеет тип 'массив из 10 элементов типа int'. всё. где тут уазатель, покажите мне его? а нету. никакой указатель, константный или нет ни имеет к данной записи ни малейшего отношения. если внутри, в машинном представлении какой-то конкретный компилятор реализует массивы через указатели, как очевидно пытается доказать MAKCim, то я рад за них обоих. только причём здесь C/C++? меня вообще не волнует, что там сидит в машинном коде, да и раздел этот про C/C++. мифические "указатели" появляются, как только имя arr будет использовано в выражениях. а именно, компилятор приводит имя arr к типу int*. так почему же arr - не указатель? да потому, что такое приведение типов не срабатывает всегда: 1. оператор sizeof(arr) вернет размер, равный 10*sizeof(int), а не sizeof(int*) как это было бы в случае указателя 2. унарный оператор & для выражения &arr имеет тип int(*)[10] а не int** а результат унарного оператора нужен например затем, чтобы итерироваться по подмассивам: int arr[10][10]; int (*p)[10] = &a[0]; (*p)[0] = 10; // работаем с первым подмассивом ++p; переходим на следующий подмассив. (*p)[0] = 20; // продолжаем инициализацию |
| Автор: baldina 1.4.2008, 23:56 | ||||
Можно. Делаешь копию массива и передаешь ;) Можно наоборот - передаешь исходный, а внутри делаешь копию. В этом случае видимо удобно воспользоваться функций _alloca():
|
| Автор: vinter 2.4.2008, 06:15 | ||
Rififi, блин, указатель это переменная содержащая адрес, имя массива является адресом. Связи не улавливаешь?
реализация разная, а вот использование одинаково. |
| Автор: Dmitriy2k 2.4.2008, 12:18 | ||
а как тогда объяснишь это?
|
| Автор: vinter 2.4.2008, 12:23 |
| Dmitriy2k, тут ты объявляешь двойной указатель, а не массив |
| Автор: Dmitriy2k 2.4.2008, 12:56 | ||||
правильней конечно будет так:
а какая разница то компилятор все равно имя массива приводит к указателю(адресу первого элемента массива) смоти ассемблерный код:
|
| Автор: Rififi 2.4.2008, 12:59 | ||
vinter,
внимательно перечитай мое предыдущее сообшение, особенно про операторы sizeof и & Добавлено через 2 минуты и 27 секунд а что тут обьяснять? завалить программу можно разными способами, например так: void f(int**); int arr[10][10]; f((int**) arr); или даже так: int* p = NULL; p[0] = 1; |
| Автор: vinter 2.4.2008, 13:28 |
| Rififi, имя массива есть адрес, указатель есть переменная хранящая адрес. Для меня очевидно что эти понятия эквивалентны, даже если в одном есть некоторый функционал отсутсвующий у другого. к тому же ты привел пример различия, которое используется достаточно редко, а вот то что используется часто работает одинаково. |
| Автор: MAKCim 2.4.2008, 16:39 | ||
я пытаюсь доказать, что в С/С++ массив нельзя передать в функцию по значению ассемблерный код тому подтверждение точка |