Почему C или C ++ не позволяют передавать массив по значениям в функцию - PullRequest
8 голосов
/ 22 марта 2009

C и C ++ позволяют передавать структуру и объекты по значению в функцию, хотя и предотвращают передачу массивов по значениям, почему?

Ответы [ 6 ]

18 голосов
/ 22 марта 2009

В C / C ++, внутренне, массив передается как указатель на какое-то место, и в основном он равен , переданному по значению. Дело в том, что скопированное значение представляет адрес памяти в том же месте .

В C ++, vector<T>, кстати, копируется и передается другой функции.

11 голосов
/ 22 марта 2009

Вы можете передавать массив по значению, но вы должны сначала обернуть его в структуру или класс. Или просто используйте тип, такой как std :: vector.

Я думаю, что решение было ради эффективности. Никто не хотел бы делать это большую часть времени. Это то же самое рассуждение, что и почему нет беззнаковых двойников. Нет связанной инструкции CPU, поэтому вы должны сделать то, что неэффективно, очень сложно в таком языке, как C ++.

Как упомянул @litb: «C ++ 1x и boost оба обернули собственные массивы в структуры, обеспечивающие std :: array и boost :: array, что я всегда предпочел бы, потому что это позволяет передавать и возвращать массивы в структурах»

Массив - это указатель на память, в которой хранится этот массив и его размер. Обратите внимание, что это не то же самое, что указатель на первый элемент массива.

Большинство людей считают, что вы должны передать массив в качестве указателя и указать размер в качестве отдельного параметра, но это не нужно. Вы можете передать ссылку на сам фактический массив, сохраняя его статус sizeof ().

//Here you need the size because you have reduced 
// your array to an int* pointing to the first element.
void test1(int *x, int size)
{
  assert(sizeof(x) == 4);
}

//This function can take in an array of size 10
void test2(int (&x)[10])
{
  assert(sizeof(x) == 40);
}

//Same as test2 but by pointer
void test3(int (*x)[10])
{
  assert(sizeof(*x) == 40);
  //Note to access elements you need to do: (*x)[i]
}

Некоторые люди могут сказать, что размер массива неизвестен. Это неправда.

int x[10];  
assert(sizeof(x) == 40);

Но как насчет распределений в куче? Выделения в куче не возвращают массив. Они возвращают указатель на первый элемент массива. Таким образом, новый тип не является безопасным. Если у вас действительно есть переменная массива, то вы будете знать размер ее содержимого.

8 голосов
/ 22 марта 2009

РЕДАКТИРОВАТЬ: я оставил оригинальный ответ ниже, но я думаю, что большая часть значения теперь в комментариях. Я сделал это вики-сообществом, поэтому, если кто-то из участников последующего разговора захочет отредактировать ответ, чтобы отразить эту информацию, не стесняйтесь.

Оригинальный ответ

Во-первых, как он узнает, какой объем стека выделить? Это исправлено для структур и объектов (я полагаю), но с массивом это будет зависеть от размера массива, который неизвестен до времени выполнения. (Даже если каждый вызывающий знает во время компиляции, могут быть разные вызывающие с разными размерами массива.) Вы можете указать конкретный размер массива в объявлении параметра, но это кажется немного странным.

Помимо этого, как говорит Брайан, есть вопрос эффективности.

Чего бы вы хотели достичь через все это? Нужно ли удостовериться, что содержимое исходного массива не изменилось?

4 голосов
/ 22 марта 2009

Я думаю, что есть 3 основные причины, по которым массивы передаются как указатели в C, а не по значению. Первые 2 упоминаются в других ответах:

  • эффективность
  • потому что вообще нет информации о размере для массивов (если вы включаете динамически размещаемые массивы)

Однако, я думаю, что третья причина связана с:

  • эволюция C от более ранних языков, таких как B и BCPL, где массивы фактически были реализованы как указатель на данные массива

Деннис Ритчи говорит о ранней эволюции C от таких языков, как BCPL и B, и, в частности, о том, как реализованы массивы и как на них влияли массивы BCPL и B, и как и почему они различаются (оставаясь очень похожими в выражениях, потому что имена массивов распадаются на указатели в выражениях).

3 голосов
/ 22 марта 2009

Это один из тех ответов «просто потому что». C ++ унаследовал его от C, и должен был следовать ему, чтобы сохранить совместимость. Так было сделано в Си для эффективности. Вы редко захотите сделать копию большого массива (помните, подумайте здесь, PDP-11) в стеке, чтобы передать его функции.

3 голосов
/ 22 марта 2009

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

Редактировать: Для downvoters - если вы знаете лучше, пожалуйста, сообщите нам всем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...