Передача массива в качестве аргумента в С++

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

//merge sort first attempt

#include <iostream>

#include <algorithm>

#include <vector>

int mergeSort(int[]);
int main() {
    int originalarray[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
    mergeSort(originalarray[]);
}

int mergeSort(int[] originalarray) {
    int num = (sizeof(originalarray) / sizeof(int));
    std::vector < int > original(num);

    if (num > 2) {
        return num;
    }

    // Fill the array using the elements of originalarray
    // This is just for demonstration, normally original will be a parameter,
    // so you won't be filling it up with anything.
    std::copy(originalarray, originalarray + num, original.begin());

    // Create farray and sarray of the appropriate size
    std::vector < int > farray(num / 2);
    std::vector < int > sarray(num - farray.size());

    // Fill those using elements from original
    std::copy(original.begin(), original.begin() + farray.size(), farray.begin());
    std::copy(original.begin() + farray.size(), original.end(), sarray.begin());

    mergeSort(farray);
    mergeSort(sarray);
}

Обратите внимание, что эта функция mergeSort не работает, так как я еще не выяснил, как их объединить (это мое назначение). Я хотел бы отсортировать два вектора, прежде чем иметь дело с этим, и я не могу скомпилировать это из-за необходимости передавать массив в качестве аргумента. Я не понимаю указателей, поэтому, если это решение, мое оправдание - невежество. Я изучаю программирование прямо сейчас, с C++ в качестве первого языка, и имею только базовые знания о языковых особенностях. Спасибо за помощь.

Ответы

Ответ 1

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

Update

Хорошо, мы расширим еще немного.

C (и поэтому С++) на самом деле не имеет "массивов" как таковых. Все, что у него есть, это адреса, указатели. Поэтому, когда вы делаете что-то "массив", что действительно происходит, вы говорите компилятору, что какая-то переменная представляет собой адрес.

Полезно провести различие в C между объявлением и определением. В объявлении вы просто даете что-то имя и тип; в определении вы фактически выделяете пространство.

Итак, если мы начнем с определения массива типа

int ar[100];

Это означает, что мы говорим компилятору, что хотим пространства для 100 int, мы хотим, чтобы все они были выделены в одном фрагменте, и мы будем использовать для него имя ar. Оператор sizeof задает количество байтов, используемых типом или объектом, поэтому наш массив ar будет занимать 100 и раз; sizeof(int) bytes. На большинстве машин это будет 400 байт, но оно варьируется от машины к машине.

Если мы определим переменную

int * ar_p;   // using '_p' as a reminder this is a pointer

мы определяем пространство для переменной, которая будет содержать адрес. Его размер будет sizeof(int*), который обычно будет либо 4, либо 8, но на некоторых машинах может быть что угодно от 2 до 16 на некоторых машинах, которые вряд ли скоро будут запущены.

Имя массива ar. Компилятор преобразует это имя в адрес, поэтому мы можем сохранить этот адрес с помощью

ar_p = ar ;     // THIS WORKS

Теперь скажем, что для удобства наш массив ar начинался с места 1000 в памяти.

Это имя ar не имеет выделенного для него пространства; это как константа, число. Таким образом, вы не можете отменить это назначение

ar = ar_p ;     // THIS WON'T WORK

по той же причине, о которой вы не могли сказать

1000 = ar_p ;   // THIS WON'T WORK EITHER

т.е. вы не можете изменить значение 1000. (Вернувшись в ранние версии FORTRAN, этот трюк будет работать по сложным причинам. Это была ошибка. Вы никогда не жили до тех пор, пока не попытаетесь отладить программа, в которой значение "2" равно 3.)

Массивы в C всегда основаны на нуле, т.е. первый индекс всегда равен нулю. Любые другие индексы - это просто адреса, рассчитанные с использованием индекса. Таким образом, ar[0] - это просто адрес 1000 плюс 0 байт смещения или 1000. ar[1] равно 1000 плюс 1 раз размер int, поэтому следующий int over. И на самом деле это всегда верно в C.

Это называется ссылкой на массив.

Когда мы используем синтаксис *ar_p, мы говорим компилятору, чтобы он получил информацию по адресу, указанному в ar_p. `.

Это называется разыменованием указателя.

Если мы скажем

ar_p = ar;

то *ar_p и ar[0] относятся к одной и той же вещи.

Когда мы говорим ar[0], мы говорим компилятору, что хотим, чтобы вещь находилась в адресе 0 байт от ar. ar[1] - это адрес int, или 4 байта, из ar. Итак, *(ar_p+3) относится к тому же, что и ar[3]. (Нам нужны скобки, потому что мы хотим сначала добавить 3 к адресу, а затем посмотреть содержимое. *ar_p+3 сначала получит содержимое, на которое указывает ap_p, а затем добавит 3. к ним.

Дело в том, что C не знает или не заботится о том, насколько велик массив. Если я приеду и сделаю ar[365], компилятор с радостью сгенерирует код для поиска в ячейке 1000+ (365 & times; sizeof(int)). Если это в вашем массиве, отлично, но если это просто случайная память, это тоже хорошо. C не заботится.

(Помните, что C приходит из телефонной компании. "Нам все равно, мы не должны. Мы - Телефонная компания".)

Итак, теперь мы знаем некоторые правила, которые я переместил сюда. Читайте "& equiv;" как "эквивалентно" или "совпадает с".

От чего вы можете зависеть:

  • foo(TYPE t[]) & equiv; foo(TYPE * t)

Так как C не знает разницы между указателями и массивами, вы можете объявить один из них. Когда вы определяете функцию, вы можете написать

void foo(int[] ar){

или

void foo(int* ar){

и получить точно такой же эффект.

  • t[i] & equiv; *(t+i)

Это было выше. В любом месте, где вы могли бы написать ar[i], вы можете заменить его на *(ar+i). (На самом деле это странный боковой случай, который нарушает это, но вы не столкнетесь с ним как новичок.)

  • где TYPE *t, (t+i) будет равно адресу в t плюс i*sizeof(TYPE)

Объяснил это выше. Когда вы индексируете в массив, например ar[42], это означает, что вы хотите, чтобы 42-й из всех начальных адресов. Итак, если вы используете int, тогда вам нужно переместить более 42 раз, а int - это sizeof(int).

Теперь, что все C, а так как С++ определяется как "вид" C, все это выполняется и для С++. КРОМЕ

  • если TYPE - это определенный пользователем тип, который перегружает operator[] и operator*.

в С++, вы можете решить, хотите ли вы определить новый тип, который действует так же, как и любой другой тип, но вы можете изменить способ, которым язык выполняет определенные вещи. Таким образом, программист может решить "перегрузить", т.е. Заменить - поведение по умолчанию ссылки на массив и операторы разыменования указателей с чем-то из их собственных разработок. Как новичок, вы не должны столкнуться с этим в ближайшее время, но вы должны знать об этом.

Ответ 2

Нельзя использовать sizeof(originalarray)/sizeof(int). Он будет работать только для статически объявленных массивов (размер известен во время компиляции). Вы должны передать размер вместе с ним. Почему бы вам просто не сделать vector из массива и передать его вместо этого?

Боковое примечание. Как правило, всегда отмечайте, что sizeof будет переведен во время компиляции. Таким образом, он не мог узнать размер массива, переданного в качестве аргумента.

Ответ 3

Я вижу, что вы включили <vector>. Я предлагаю вам избавиться от всех видов использования массивов и использовать только класс vector. Вы можете увидеть примеры использования контейнеров STL, таких как vector здесь.

Ответ 4

  • Когда вы передаете массивы в функции, они распадаются на указатели на первый элемент массива, несмотря на обозначение. Таким образом, ваш sizeof работает не так, как ожидалось.

  • Когда вы передаете массив, лучше передать размер массива, чтобы вы знали, где остановиться. Добавьте его в качестве дополнительного параметра.

Ответ 5

В дополнение ко всем приведенным выше ответам вы также можете проверить Q & As на массивах c-faq.com: http://c-faq.com/aryptr/index.html

Ответ 6

К сожалению, очень сложно сделать то, что вы хотите сделать на C или С++. Вы можете передать массив фиксированного размера следующим образом:

int mergeSort(int originalarray[20])
{
    // do something
}

Однако размер вашего массива не определяется числом, определяемым количеством элементов в списке инициализации.

То, что вам нужно сделать в вашем случае (даже если это действительно неправильно) - сделать это в два этапа:

int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
const size_t arraySize = sizeof originalarray / sizeof originalarray[0];
int mergeSort(int array[arraySize])
{
    // do something
}

Слишком плохо, что вы не будете делать то, что вам нужно сделать: передача массива в такую ​​функцию делает копию массива, а точка сортировки - изменить исходный массив.

По правде говоря, вы не можете идти дальше, не понимая понятия "указатель".

Функция, которую нужно развивать, должна быть такой:

int originalarray[] = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
const size_t arraySize = sizeof originalarray / sizeof originalarray[0];

int mergeSort(int *array, const size_t size)
{
    // do something
}

mergeSort(&(originalArray[0]), arraySize);

Другими словами, вы передаете указатель на первый элемент и количество элементов.

Кроме того, вы можете иметь дело с векторами. Вектор инкапсулирует те же две вещи (указатель на первый элемент и размер) в единый объект, называемый "объект". Кроме того, он управляет памятью для вас, поэтому вы можете расширить количество элементов по мере необходимости. Это путь С++. Слишком плохо, вы не можете инициализировать вектор с помощью {...}, как вы можете массив.

Ответ 7

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

Во-первых, пусть ваш входной массив будет изменен на std::vector и заполнит его вашими входными данными.

int main()
{
   std::vector<int> originalarray;
   for (int data = 1; data <= 10; data++)
   {
      originalarray.push_back(data);
   }
   mergeSort(originaldata);
}

Теперь важно объявить вашу функцию mergesort ссылкой на std::vector.

int mergeSort(std::vector<int>& originalarray)
{
   // The rest of your code, note that now you are passing 
   // in your array for sorting, so you can continue with your code to split
   // the vector into farray and sarray

   // then call sort on your halves.
   mergeSort(farray);
   mergeSort(sarray);

   // I'm guessing at this point you'd write code to combine your farray sarray, and
   // put it back into originalarray...don't forget to clear original array first!
}

Просто заметьте, похоже, что вы не занимаетесь сортировкой inplace, поэтому ожидайте, что ваш сорт займет некоторое время, так как вы копируете большое количество данных.