Russian Qt Forum
Ноябрь 06, 2024, 02:29 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3 ... 6   Вниз
  Печать  
Автор Тема: Современные одномерные и двумерные массивы на C++  (Прочитано 49822 раз)
8Observer8
Гость
« : Октябрь 29, 2014, 10:28 »

Привет! Мне надоело объяснять на форумах как надо создавать одномерные и двумерные массивы. Поэтому создаю тему, на которую буду делать ссылки. От вас прошу высказать своё мнение, дополнить, посоветовать, что можно улучшить. Спасибо!

Современные одномерные и двумерные массивы на C++

Одномерные и двумерные динамические массивы на C++ можно создать с помощью std::vector и отказаться от операторов new и delete

Следующий пример создаёт одномерный массив из десяти ячеек, и заполняет их нулями. В данном примере в ячейчах могут храниться только целые числа:

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0 );
 
   return 0;
}
 


Для того чтобы хранить вещественные числа необходимо вместо int написать float, а константу заполнения записать явно, как float: 0.0f

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<float> arr( 10, 0.0f );
 
   return 0;
}
 


Для того чтобы хранить вещественные числа двойной точности необходимо вместо int написать double, а константу заполнения записать явно, как double: 0.0

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector<double> arr( 10, 0.0 );
 
   return 0;
}
 


После того как мы создали массив мы можем его использовать для хранения чисел. В следующем примере мы присваиваем нескольким элементам массива значения и выводим один их элементов массива на экран:

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0);
 
   arr[0] = 34;
   arr[1] = 5;
 
   std::cout << arr[0] << std::endl;
 
   return 0;
}
 


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

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   std::vector<int> arr( 10, 0);
 
   arr[0] = 34;
   arr[1] = 5;
 
   std::cout << "size = " << arr.size() << std::endl; // output: size = 10
 
   arr.push_back( 87 );
   std::cout << arr[10] << std::endl; // output: 87
 
   std::cout << "size = " << arr.size() << std::endl; // output: size = 11
 
   return 0;
}
 


Для того чтобы создать двумерный массив с помощью std::vector необходимо вместо int написать std::vector. Следующая запись означает, что мы создали массив из пяти элементов, каждый из которых - это массив целых чисел:

Код
C++ (Qt)
#include <vector>
 
int main()
{
   std::vector< std::vector<int> > arr( 5 );
 
   return 0;
}
 


Но пока каждый из этих под-массивов нулевой длины. Исправим это:

Код
C++ (Qt)
#include <vector>
 
int main()
{
   const int nrows = 5;
   const int ncols = 3;
 
   std::vector< std::vector<int> > arr( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr[row].resize( ncols );
   }
 
   return 0;
}
 
Теперь у нас есть двумерный массив у которого 5 строк и 3 столбца


Присвоим какой-либо ячейке значение и выведем значение этой ячейки на экран:

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
int main()
{
   const int nrows = 5;
   const int ncols = 3;
 
   std::vector< std::vector<int> > arr( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr[row].resize( ncols );
   }
 
   arr[4][0] = 87;
 
   std::cout << arr[4][0] << std::endl;
 
   return 0;
}
 


Передача в функцию

Одномерные и двумерные массивы передаются в функцию ссылкой, чтобы передавать адрес объекта, а не копировать целиком. Если не планируется менять значения элементов массива, то добавляется const

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
void show1DArray( const std::vector<int> &arr1D )
{
   std::cout << arr1D[0] << std::endl;
}
 
void show2DArray( const std::vector< std::vector<int> > &arr2D )
{
   std::cout << arr2D[1][1] << std::endl;
}
 
int main()
{
   // 1D array
   std::vector<int> arr1D( 10, 0);
 
   arr1D[0] = 34;
 
   show1DArray( arr1D );
 
   const int nrows = 5;
   const int ncols = 3;
 
   // 2D array
   std::vector< std::vector<int> > arr2D( nrows );
 
   for( size_t row = 0; row < nrows; ++row ) {
       arr2D[row].resize( ncols );
   }
 
   arr2D[1][1] = 5;
 
   show2DArray( arr2D );
 
   return 0;
}
 


Если требуется передать одномерный массив в функцию, которая принимает указатель на буфер, то для этого есть метод .data()

Код
C++ (Qt)
#include <iostream>
#include <vector>
 
void show1DArray( int *p )
{
   std::cout << p[0] << std::endl;
}
 
int main()
{
   // 1D array
   std::vector<int> arr1D( 10, 0);
 
   arr1D[0] = 34;
 
   show1DArray( arr1D.data() );
 
   return 0;
}
 
« Последнее редактирование: Октябрь 29, 2014, 10:42 от 8Observer8 » Записан
vulko
Гость
« Ответ #1 : Октябрь 29, 2014, 11:15 »

Все конечно классно...

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

Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.


Цитировать
и отказаться от операторов new и delete

чаще всего векторы из int и float создают только студенты.

на практике очень часто приходится создавать контейнеры из указателей на структуры, классы... да даже тупо void*.
отказаться от операторов new и delete врядли получится.
хотя есть вроде аллокаторы, но я ими никогда не пользовался и хз как оно работает.
имхо проще new delete.

посему предлагаю все же не писать десяток простейших примеров, а объединить их в один. и дополнить реально полезной инфой о контейнерах из указателей.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #2 : Октябрь 29, 2014, 11:29 »

... и все равно такие вопросы будут задавать, ибо подобные темы и раньше поднимались, а те кто такие вопросы задают банально не умеют пользоваться гуглом, так чего они будут делать поиск по форуму? Веселый
Записан

8Observer8
Гость
« Ответ #3 : Октябрь 29, 2014, 11:36 »

Цитировать
чаще всего векторы из int и float создают только студенты.
Как раз таки нет. Они пишут эту дурацкую конструкцию, которой место на свалке:  float *ptrarray = new float [10];

Цитировать
и все равно такие вопросы будут задавать, ибо подобные темы и раньше поднимались, а те кто такие вопросы задают банально не умеют пользоваться гуглом, так чего они будут делать поиск по форуму?
Я тему создал лишь в личных интересах. Для того, чтобы каждый раз не объяснять, а давать ссылку на эту тему
Записан
8Observer8
Гость
« Ответ #4 : Октябрь 29, 2014, 11:39 »

Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #5 : Октябрь 29, 2014, 11:42 »

Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
8Observer8
Гость
« Ответ #6 : Октябрь 29, 2014, 11:47 »

Цитировать
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....
Это я не знал. А с std::string такая же фигня?
Записан
Kurles
Бывалый
*****
Offline Offline

Сообщений: 480



Просмотр профиля
« Ответ #7 : Октябрь 29, 2014, 11:48 »

Цитировать
Во-вторых, вектор платформо-зависим... точнее компиляторо-зависим.
Что это значит?
Это значит, что нельзя перекидывать такие массивы между модулями (либами), ибо если они собраны разными компиляторами....
Вроде все плюсовые либы компиляторо-зависимы, нет какого-либо стандарта...
Записан

Код
C++ (Qt)
while(!asleep()) sheep++;
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Октябрь 29, 2014, 11:49 »

Это я не знал. А с std::string такая же фигня?
Ага. Вообще, любого stl касается. Use Qt, Luke.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
8Observer8
Гость
« Ответ #9 : Октябрь 29, 2014, 12:10 »

Цитировать
Вроде все плюсовые либы компиляторо-зависимы, нет какого-либо стандарта...
Все либы, которые я использую, я собирал с помощью Qt из исходников. И это были либы написанные без использования Qt (не мной). За информацию, спасибо

Я сам на практике использую одномерный вектор для хранения координат, а передаю в функции указатель на буфер http://www.cplusplus.com/reference/vector/vector/data/

Можно, конечно, и так передавать: &v[0], но гораздо приятнее так: v.data()

Согласитесь, что гораздо удобнее работать с вектором, чем запрашивать из кучи. И не писать статический массив, который может не поместиться в стек
« Последнее редактирование: Октябрь 29, 2014, 12:12 от 8Observer8 » Записан
vulko
Гость
« Ответ #10 : Октябрь 29, 2014, 12:12 »

Цитировать
чаще всего векторы из int и float создают только студенты.
Как раз таки нет. Они пишут эту дурацкую конструкцию, которой место на свалке:  float *ptrarray = new float [10];

почему им место на свалке и чем она дурацкая?
Записан
8Observer8
Гость
« Ответ #11 : Октябрь 29, 2014, 12:15 »

Тем что можно забыть правильно освободить ресурсы, нужно писать лишний код по освобождению ресурсов, а если пользователь вводит и вводит собака, то придётся предусмотреть выделение дополнительных ресурсов
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #12 : Октябрь 29, 2014, 12:18 »

Блин, форум скатывается в какой-то LOR/BASH.ORG Улыбающийся
Записан

ArchLinux x86_64 / Win10 64 bit
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2095



Просмотр профиля
« Ответ #13 : Октябрь 29, 2014, 12:27 »

Блин, форум скатывается в какой-то LOR/BASH.ORG Улыбающийся
Меня особенно название темы повеселило: "Современные одномерные и двумерные массивы на C++" Без лишнего пафоса, так..  Смеющийся
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
vulko
Гость
« Ответ #14 : Октябрь 29, 2014, 12:38 »

Все либы, которые я использую, я собирал с помощью Qt из исходников. И это были либы написанные без использования Qt (не мной). За информацию, спасибо

Неважно кто собирал, важно не забывать что stl сильно зависит от платформы/компилятора.
И вообще stl штука неоднозначная. Например легко может случиться, что на одной платформе size() будет O(1), а на другой O(N).


Я сам на практике использую одномерный вектор для хранения координат, а передаю в функции указатель на буфер http://www.cplusplus.com/reference/vector/vector/data/

Все операции вставки/извлечения в/из stl контейнера происходят по значению. Т.е. объект копируется.
Гораздо лучше держать контейнер из указателей.

Если не ошибаюсь, stl::vector может фрагментироваться при изменении размера. Либо же при изменении размера он тупо будет заниматься копированием.


Можно, конечно, и так передавать: &v[0], но гораздо приятнее так: v.data()

Согласитесь, что гораздо удобнее работать с вектором, чем запрашивать из кучи. И не писать статический массив, который может не поместиться в стек

Зачем передавать в функции v.data()?
Можно хранить указатель на вектор и не боятся передавать его в функции. Либо передавать вектор по ссылке... чтобы не испортили по константной ссылке.

В чем конкретно удобство работы с вектором? Для него даже оператор [] перегрузили чтобы он от обычного массива не отличался.
Создавать динамически объекты все равно приходится очень часто. И даже не потому что везде вектора не воткнуть, а просто потому что долго живущие объекты должны жить в куче.
Записан
Страниц: [1] 2 3 ... 6   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.396 секунд. Запросов: 22.