Существуют ли зазубренные массивы в C/C++?
Есть ли такая вещь, как зубчатый массив в C или C++?
Когда я собираю это:
int jagged[][] = { {0,1}, {1,2,3} };
Я получаю эту ошибку:
ошибка: объявление jagged как многомерного массива должно иметь границы для всех измерений, кроме первого
12 ответов
В C I будет использовать массив указателей.
Например:
int *jagged[5];
jagged[0] = malloc(sizeof(int) * 10);
jagged[1] = malloc(sizeof(int) * 3);
и т. д.
Есть множество способов сделать это. Вот еще один способ:
int jagged_row0[] = {0,1};
int jagged_row1[] = {1,2,3};
int *jagged[] = { jagged_row0, jagged_row1 };
Если вы просто хотите инициализировать его, вы можете сказать:
int jagged[][3] = { {0,1}, {1,2,3} };
но массив все равно будет иметь форму [2][3]. Если вам нужен истинный зубчатый массив, вам придется создавать его динамически. И если вы делаете это и используете C++, вы должны использовать std::vector
как говорит фриол.
В C++ (не скомпилировано, и, вероятно, есть более компактный синтаксис):
std::vector<std::vector<int> > myArray;
myArray.push_back(std::vector<int>());
myArray.push_back(std::vector<int>());
myArray[0].push_back(0);
myArray[0].push_back(1);
myArray[1].push_back(1);
myArray[1].push_back(2);
myArray[1].push_back(3);
Так что теперь вы можете получить доступ к элементам, например, myArray[0][0] и т. Д.
С помощью списков инициализаторов C++11 это можно записать более компактно:
#include <vector>
#include <iostream>
int main() {
// declare and initialize array
std::vector<std::vector<int>> arr = {{1,2,3}, {4,5}};
// print content of array
for (auto row : arr) {
for (auto col : row)
std::cout << col << " ";
std::cout << "\n";
}
}
Выход:
$ g++ test.cc -std=c++11 && ./a.out
1 2 3
4 5
Для справки:
Причина, по которой вы получили ошибку, заключается в том, что вы должны указать границы хотя бы для внешнего измерения; т.е.
int jagged[][3] = {{0,1},{1,2,3}};
Вы не можете jagged[0] быть массивом из 2 элементов типа int, а jagged[1] быть массивом из 3 элементов типа int; массив N-элементов отличается от массива M-элементов (где N!= M), и все элементы массива должны быть одного типа.
То, что вы можете сделать, - это то, что другие предложили выше, и создать неровные массивы указателей на int; таким образом, каждый элемент может указывать на целочисленные массивы разных размеров:
int row0[] = {0,1};
int row1[] = {1,2,3};
int *jagged[] = {row0, row1};
Несмотря на то, что row0 и row1 являются разными типами (2-элементные или 3-элементные массивы int), в контексте инициализатора они оба неявно преобразуются в один и тот же тип (int *).
В C99 вы можете сделать следующее:
int jagged_row0[] = {0,1};
int jagged_row1[] = {1,2,3};
int (*jagged[])[] = { &jagged_row0, &jagged_row1 }; // note the ampersand
// also since compound literals are lvalues ...
int (*jagged2[])[] = { &(int[]){0,1}, &(int[]){1,2,3} };
Единственное отличие здесь (по сравнению с ответом rampion) состоит в том, что массивы не распадаются на указатели, и нужно обращаться к отдельным массивам через другой уровень косвенности - (например, *jagged[0]
- и размер каждой строки должен быть записан - т.е. sizeof(*jagged[0])
не будет компилироваться) - но они зазубренные до костей;)
Вы также можете использовать составные литералы в c для инициализации действительно зубчатого массива, который непрерывен в памяти следующим образом:
int (*arr[]) = { (int []) {0, 1}, (int []){ 2, 3, 4}, (int []){5, 6, 7, 8} }
Это будет выложено непрерывно в памяти.
Используя динамическое размещение в cpp, мы можем создавать неровные массивы.
Например:
#include<iostream>
using namespace std;
int main(){
int n;
cout<<"Enter n:";
cin>>n;
cout<<"Enter elements:";
int **p = new int *[n];
for(int i=0;i<n;i++){
p[i] = new int[i+1];
for(int j=0;j<(i+1);j++){
cin>>p[i][j];
}
}
cout<<"Jagged Array:"<<endl;
for(int i=0;i<n;i++){
for(int j=0;j<(i+1);j++){
cout<<p[i][j]<<" ";
}
cout<<endl;
}
for(int i=0;i<n;i++){
delete []p[i];
}
delete []p;
}
За
n=3
, мы создали зубчатый массив следующего вида:
- Введите n: 3
Введите элементы:
1
1 2
1 2 3
Неровный массив:
1
1 2
1 2 3
//
//jaggedArrays.cpp
//
//program to implement jagged arrays in c++
//
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int rows, i, j;
cout << endl << "Enter no of rows : ";
cin >> rows;
int columnsSizeOfEachRow[rows];
cout << endl;
for( i = 0 ; i < rows ; i++ )
{
cout << "Enter column size for row no " << i + 1 << " : ";
cin >> columnsSizeOfEachRow[i];
}
int *jaggedArray[rows];
for (i = 0 ; i < rows ; i++)
jaggedArray[i] = new int[columnsSizeOfEachRow[i]];
cout << endl;
for(i = 0 ; i < rows ; i++)
{
for ( j = 0 ; j < columnsSizeOfEachRow[i] ;j++)
{
cout << "Array[" << i + 1 << "][" << j + 1 << "] << ";
cin >> jaggedArray[i][j];
}
cout << endl;
}
cout << endl << endl << "Jagged array is as follows : " << endl;
for( i = 0 ; i < rows ; i++)
{
for ( j = 0 ; j < columnsSizeOfEachRow[i] ;j++)
cout << setw(3) <<jaggedArray[i][j] << " ";
cout << endl;
}
return 0;
}
Нет, зубчатых многомерных массивов нет ни в C, ни в C++. Вы можете создавать различные конструкции, которые выполняют аналогичные функции с некоторой затратой памяти (например, массив указателей на массивы ), но не настоящий многомерный массив в стиле C.
Причина в том, что массивы в стиле C, независимо от количества измерений, занимают непрерывную область памяти без метаданных. Итак, с точки зрения памяти они все одномерны. Только хитрость арифметики указателя ( перемещение указателя по размеру строки) дает вам функциональность дополнительных измерений. Зубчатый массив, выложенный последовательно, имеет разные размеры строк, поэтому его нельзя обвести постоянным значением, поэтому он требует дополнительной памяти в зависимости от размера данных, поэтому его невозможно выразить в системе типов C.
Становится яснее, когда вы рассматриваете, к какому указателю распадается многомерный массив: Массив к распаду указателя и передача многомерного массива в функции
И поэтому вы видите сообщение об ошибкеmust have bounds for all dimensions except the first
, потому что все измерения, кроме первого, необходимы для обхода массива.
Зубчатые массивы действительно существуют в C++/c, но синтаксис довольно сложен, и вам придется обрабатывать многие вещи.
В C++ есть два типа зубчатых массивов.1) СТАТИЧЕСКИЙ Массив с зазубринами(2- мерный массив, в котором размер будет постоянным числом и будет различное количество столбцов в каждой строке).
2) ДИНАМИЧЕСКИЙ Массив с зазубринами(2d массив, в котором размер будет любым числом, взятым у пользователя, и будет различное количество столбцов в каждой строке)
1) ЭТАПЫ РЕАЛИЗАЦИИ СТАТИЧЕСКОГО МОДУЛЬНОГО МАССИВА
- 1) Объявите одномерные массивы с нужным количеством строк
- 2) Размер каждого массива (массива для элементов в строке) будет количеством столбцов (или элементов) в строке
- 3) Объявите одномерный массив указателей, который будет содержать адреса стрелок.
- 4) Размер одномерного массива - это количество строк, которое вы хотите в неровном массиве.
#include<iostream>
#include<string>
using namespace std;
int main()
{
int row0[4] = { 1,2,3,4 };
int row1[2] = { 5,6 };
int* jagged[2] = { row0,row1 };
int Size[2] = { 4,2 }, k = 0;
for (int i = 0; i < 2; i++)
{
int* ptr = jagged[i];
for (int j = 0; j < Size[k]; j++)
{
cout << *ptr << "";
ptr++;
}
cout << endl;
k++;
jagged[i]++;
}
return 0;
}
Результат выглядит следующим образом
1234
56
1) ЭТАПЫ РЕАЛИЗАЦИИ ДИНАМИЧЕСКОГО МОДУЛЬНОГО МАССИВА
- 1) Объявить массив указателей (зубчатый массив)
- 2) Размер этого массива будет количеством строк, необходимых в неровном массиве.
- 3) Для каждого указателя в массиве выделите память на необходимое количество элементов в этой строке.
#include<iostream>
#include<string>
using namespace std;
int main()
{
//2 rows
int* jagged[2];
//Allocate memeory for the elements in the row 0
jagged[0] = new int[1];
//Allocate memory for the elements in row 1
jagged[1] = new int[5];
//Array to hold the size of each row
int Size[2] = { 1,5 },k = 0, number = 100;
//User enters the numbers
for (int i = 0; i < 2; i++)
{
int* p = jagged[i];
for (int j = 0; j < Size[k]; j++)
{
*p = number++;
//move the pointer
p++;
}
k++;
}
k = 0;
//Display elements in Jagged array
for (int i = 0; i < 2; i++)
{
int* q = jagged[i];
for (int j = 0; j < Size[k]; j++)
{
cout << *q << "";
//move the pointer to the next element
q++;
}
cout << endl;
k++;
//move the pointer to the next row
jagged[i]++;
}
delete[] jagged;
return 0;
}
Результат выглядит следующим образом
100
101102103104105
ПРИМЕЧАНИЕ:(Код скопирован со слайда с курсом университета)