Is there such a thing as a jagged array in C or C++?
When I compile this:
int jagged[][] = { {0,1}, {1,2,3} };
I get this error:
error: declaration of `jagged' as multidimensional array must have bounds for all dimensions except the first
In C I would use an array of pointers.
For instance:
int *jagged[5];
jagged[0] = malloc(sizeof(int) * 10);
jagged[1] = malloc(sizeof(int) * 3);
etc etc.
There's a bunch of ways to do it. Here's another way:
int jagged_row0[] = {0,1};
int jagged_row1[] = {1,2,3};
int *jagged[] = { jagged_row0, jagged_row1 };
If you just want to initialise it, you can say:
int jagged[][3] = { {0,1}, {1,2,3} };
but the array will still have the shape [2][3]. If you want a true jagged array, you will have to create it dynamically. And if you do that, and are using C++, you should use a std::vector, as friol suggests.
In C++ (not compiled, and probably there's a more compact syntax):
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);
So now you can access the elements with, for example, myArray[0][0], etc.
In C99 you can do the following:
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} };
The only difference here (as compared to rampion's answer) is that the arrays don't decay to pointers and one has to access the individual arrays via another level of indirection - (e.g. *jagged[0] - and the size of each row has to be recorded - i.e. sizeof(*jagged[0]) will not compile) - but they're jagged-appearing to the bone ;)
The reason you got the error is that you must specify the bounds for at least the outer dimension; i.e.
int jagged[][3] = {{0,1},{1,2,3}};
You cannot have jagged[0] be a 2-element array of int and jagged[1] be a 3-element array of int; an N-element array is a different type from an M-element array (where N != M), and all elements of an array must be the same type.
What you can do is what the others have suggested above and create jagged as an array of pointers to int; that way each element can point to integer arrays of different sizes:
int row0[] = {0,1};
int row1[] = {1,2,3};
int *jagged[] = {row0, row1};
Even though row0 and row1 are different types (2-element vs. 3-element arrays of int), in the context of the initializer they are both implicitly converted to the same type (int *).
With C++11 initializer lists this can be written more compactly:
#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";
}
}
The output is:
$ g++ test.cc -std=c++11 && ./a.out
1 2 3
4 5
For reference:
http://en.cppreference.com/w/cpp/utility/initializer_list
You can also use the compound literals in c to initialize a truly jagged array which is contiguous in memory as follows:
int (*arr[]) = { (int []) {0, 1}, (int []){ 2, 3, 4}, (int []){5, 6, 7, 8} }
This will be laid out contiguously in memory.
By using dynamic allocation in cpp we can create jagged arrays.
For example:
#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;
}
For n=3, we have created a jagged array in the following look:
Enter n: 3
Enter elements:
1
1 2
1 2 3
Jagged Array:
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;
}
The jagged arrays do exist in c++/c but the syntax is quite complex and you have to handle many things.
There are two types of jagged arrays in c++.
1) STATIC JAGGED ARRAY(A 2d array in which the size will be a constant number and there will be different number of columns in each row).
2) DYNAMIC JAGGED ARRAY(A 2d array in which the size will be any number taken from user and there will be different number of columns in each row)
1)STEPS OF IMPLEMENTING STATIC JAGGED ARRAY
Using array and a pointer
1) Declare 1-D arrays with the number of rows you will need
2) The size of each array(array for the elements in the row) will be the number of columns (or elements) in the row
3) Declare a 1-D array of pointers that will hold the addresses of the arrows
4) The size of the 1-D array is the number of rows you want in the jagged array
#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;
}
The output is as follows
123456
1)STEPS OF IMPLEMENTING DYNAMIC JAGGED ARRAY
Using an array of pointer
1) Declare an array of pointers(jagged array)
2) The size of this array will be the number of rows required in the jagged array
3) For each pointer in the array allocate memory for the number of elements you want in this row.
#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[0];
delete[] jagged[1];
return 0;
}
The output is as follows
100
101102103104105
No, there are no jagged multidimensional arrays in C nor C++. You can create various constructs that perform similar function at some memory cost (like array of pointers to arrays), but not an actual C-style multidimensional array.
The reason is that C-style arrays, no matter how many dimensions, occupy contiguous memory area with no metadata. So, memory-wise, they're all single-dimensional. It's only the cleverness of pointer arithmetic (striding the pointer by the size of a row) that gives you the functionality of extra dimensions. A jagged array laid out serially has different row sizes, so it cannot be strode by a constant value, so it requires additional storage depending on data size, thus is impossible to express in C type system.
It becomes clearer when you consider to what pointer multidimensional array decay to: Array to pointer decay and passing multidimensional arrays to functions
And that's why you see the error message must have bounds for all dimensions except the first, because all dimensions except the first are necessary to stride the array.
Related
Write a function, reverseArray, that when passed an int array of length greater than 0 will return a dynamically allocated array of the same length but with the elements in the reverse order. For example, if passed the array, {1,2,3,4,5,6,7,8,9,0} the function would return the array {0,9,8,7,6,5,4,3,2,1}.
Below is my code, but there is a bug in it.
This is my output.
1
2
3
4
5
6
4113
6
5
4
3
2
1
0x7fffe697ceb0
The 4113 and address are provided by the compiler.
#include <iostream>
using namespace std;
int * readNumbers() {
int * a = new int[6];
for (int i = 0; i < 6; i++) {
int x;
cin >> x;
a[i] = x;
}
// a++;
return a;
delete[] a;
}
int *reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
return numbers1;
delete [] numbers1;
}
int main() {
int *arr1 = readNumbers();
cout << reverseArray(arr1,6) << endl;
return 0;
}
I think there may have been an issue with your wording. Assuming you want your function just to print the reverse of a passed array, you're off to a good start.
One issue is what was said in the comments: your for loop is indexing past your array. When you type int * a = new int[6]; you are creating a pointer 'a' which points to a location in memory. Since you chose size 6, the appropriate amount of memory is allocated. If you happen to index outside of that range, you will end up pointing to a random spot in memory, not allocated for your array. Hence why you are getting a weird number '4113'.
A fix for this could be:
int i = length changed to int i = length-1
Another issue is that your function returns an integer pointer, and you are trying to cout this pointer. As another commenter said, you have to think about what this does. If you try this code:
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3};
cout << arr << endl;
return 0;
}
your output would be something like 0xff09ba. This represents the location of the start of the array in memory. If you change arr to (arr + 1) you will get the location of the second index of the array.
So when you type cout << reverseArray(arr1,6) << endl; you are really just printing out the location of numbers1 in memory. This is why you are getting '0x7fffe697ceb0' in your output. To fix this, simply make your function
void reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
}
and change your main to:
int main() {
int *arr1 = readNumbers();
reverseArray(arr1,6);
return 0;
}
Now, if you actually want to return this array, you would need to create a new array which holds the reverse numbers and then return that. An example of a function that does that is:
int* reverseArray(int *numbers1,int length) {
int j = 0;
int *numbers2 = new int[length];
for (int i = length-1; i >=0; i--) {
numbers2[j] = numbers1[i];
j++;
}
return numbers2;
}
There are probably better ways to do this, but this is just one solution. Regardless, you should always be careful when allocating memory yourself.
I have a variable k of type int to set the length of a dynamically allocated int array:
int *Numbers = new int[k];
But because of this I cannot iterate over the array, I get an error:
"no matching begin function was found required for this range-based for statement"
I also cannot get the length of the array using size();
Here's the complete code:
#include <iostream>
using namespace std;
int main()
{
int b, k;
cin >> b >> k;
int *Numbers = new int[k];
for (int i : Numbers) {// (There is a error)
}
for (int i = 0; i < size(Numbers); i++) {
}
}
Prefer using a std::vector instead of a std::array. (Like #tadman mentioned.)
Here is your code using std::vector instead:
#include <iostream>
#include <vector>
int main()
{
int b, k;
std::cin >> b >> k;
std::vector<int> Numbers(b,k); // Fills the vector "Numbers" with nth number of elements with each element as a copy of val.
for (int i : Numbers)
std::cout << i << std::endl;
for (int i = 0; i < Numbers.size(); i++)
std::cout << Numbers[i] << std::endl;
return 0;
}
Say I want 10 elements with the number 5.
Output:
10
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
5
Also consider not using namespace std;.
The simple and recommended solution is to use std::vector, however if you really want a dynamically allocated array and to use iterator like features on it, you can use iterator_range from boost library, which allows you to create an iterator range for it thus making it usable in range based for loops and in functions like std::size.
Live demo
#include <iostream>
#include<boost/range.hpp>
int main()
{
int k = 5;
int *Numbers = new int[k]{1,4,5,7,8};
auto arr = boost::make_iterator_range(Numbers, Numbers + k);
for (int i : arr) { //range based loop
std::cout << i << " ";
}
std::cout << std::endl << "Size: " << arr.size(); //print size
//or std::size(arr);
}
Output:
1 4 5 7 8
Size: 5
Range-based for loops work with arrays, but not work with pointers. The Actual issue is that arrays is actually a pointer and not an array.try to use simple array.
Using pointers is problematic for many reasons. The simple solution to your problem is to use a vector
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int b, k;
cin >> b >> k;
vector<int> Numbers(k);
for (int i : Numbers) {
cout << i << endl;
}
for (int i = 0; i < Numbers.size(); i++) {
cout << Numbers[i] << endl;
}
}
C array does not have default iterator and thus there is no begin() and end() functions that are used to iterate over array when you use statment like this:
for (int i : Numbers)
You can check range-for reference:
range_expression - any expression that represents a suitable sequence (either an array or an object for which begin and end member functions or free functions are defined, see below) or a braced-init-list.
Okay, so since the dynamic array does not have a default iterator, do not use the for-each loop, instead consider using the regular for loop.
Also, mind the the size function will not work for an array (or dynamic array) and you need to remember the size, since it's not possible to get the size from the pointer only. Hence, this code would work:
#include <iostream>
using namespace std;
int main()
{
int b, k;
cin >> b >> k;
int *Numbers = new int[k];
const int SIZE = k;
for (int i = 0; i < SIZE; i++) {
cout << i << ' ';
}
}
You need to dereference *Numbers by using the * if you want to iterate over the array because *Numbers is a pointer to an integer which points to the first element of your array.For Example :
#include <iostream>
using namespace std;
int main()
{
int k = 10;
int *numbers = new int[k];
//filling the array
for(int i = 0 ; i < k ; ++i) {
*(numbers + i) = i ;
}
//output array element
for(int i = 0 ; i < k ; ++i) {
cout << numbers + i << " is the address of "<<*(numbers + i) << endl;
}
return 0;
}
The output is :
0x6f1750 is the address of 0
0x6f1754 is the address of 1
0x6f1758 is the address of 2
0x6f175c is the address of 3
0x6f1760 is the address of 4
0x6f1764 is the address of 5
0x6f1768 is the address of 6
0x6f176c is the address of 7
0x6f1770 is the address of 8
0x6f1774 is the address of 9
Unfortunatly, you can't get the size of your array with *Numbers because it's not an array but a pointer.
I am took two arrays and then merged those two arrays to a newly created third array and it worked but when I output the size of the array, I was getting the size as '1'. I don't understand why the size of that array was '1' even though there are 5 elements in it.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int arr1[] = { 1,2,3 };
int arr2[] = { 9,4 };
int size1 = sizeof(arr1) / sizeof(int);
int size2 = sizeof(arr2) / sizeof(int);
int *arr = new int[size1 + size2];
//merging the two arrays by transferinng the elements into the third array
for (int i = 0; i < size1; i++)
{
arr[i] = arr1[i];
}
for (int i = size1; i < (size1 + size2); i++)
{
arr[i] = arr2[i - size1];
}
//sorting the array
sort(arr, arr + (size1 + size2));
cout << endl;
//finding the size of newly merged array
int mergeSize = sizeof(arr) / sizeof(int);
cout << "The size of the array is " << mergeSize << endl; //why am I getting the size of the array as '1'
return 0;
}
sizeof(arr) gives you the size of the pointer arr, which does not depend on the number of elements you allocated for it.
Avoid the problem by using std::array. It doesn't have the overhead of std::vector and it's easier to use than C-style arrays.
int main()
{
array<int, 3> arr1 = { 1, 2, 3 };
array<int, 2> arr2 = { 9, 4 };
array<int, arr1.size() + arr2.size()> arr;
//merging the two arrays by transferinng the elements into the third array
for (int i = 0; i < arr1.size(); i++)
{
arr[i] = arr1[i];
}
for (int i = 0; i < arr2.size(); i++)
{
arr[i + arr1.size()] = arr2[i];
}
//sorting the array
sort(arr.begin(), arr .end());
cout << endl;
//finding the size of newly merged array
int mergeSize = arr.size();
cout << "The size of the array is " << mergeSize << endl; //why am I getting the size of the array as '1'
return 0;
}
arr is not an array, it's a pointer, Using sizeof on a pointer gives the size of the pointer not the size of the dynamic array it's pointing at. The sizeof a pointer is usually 4 or 8, depending on whether you have a 32 bit or 64 bit system.
You can avoid these problems by using vectors instead of arrays. Vectors have a size method which always gives the actual size. Arrays are quite poor in C++.
I've separated my code into 3 files: main.cpp, array.h, array.cpp
My code asks the user to input size of a square 2D matrix and I implement some functions (transpose, addition of 2 2D Arrays, etc)
my array.cpp's constructor initializes a dynamic array of size s and puts all entries to 0s.
Array::Array(int s)
{
// The constructor creates a dynamic array v[s][s], and set size to s.
// initialize all entries v[i][j] to 0.
int **v = new int*[s];
for(int i = 0; i < s; ++i)
v[i] = new int[s];
for(int i = 0; i < s; i++)
for(int j = 0; j < s; j++)
v[i][j] = 0;
}
Array::~Array()
{
// The destructor deletes v.
int arraysize = sizeof(v)/sizeof(v[0]);
for(int i = 0; i < arraysize; ++i)
{
delete [] v[i];
}
delete [] v;
}
This is part of my main.cpp that i'm having trouble with.
I have a function asking the user to input entries for 2d array on the top of my main function, but I've been getting error "type 'Array' does not provide a subscript operator"
#include <iostream>
#include "array.h"
using namespace std;
// input array
void input(Array &C)
{
int i, j;
for(i = 0; C[i][0] == 0; i++)
for(j = 0; C[0][j] == 0; j++)
{
cin >> C[i][j];
}
}
int main(void)
{
//input size
int size;
cout << "Please input array size:" << endl;
cin >> size;
//input A, B
Array A(size), B(size);
cout << "Please input " << size << "x" << size << "integer array A:" << endl;
input(A);
cout << "Please input " << size << "x" << size << "integer array B:" << endl;
input(B);
........
I have to use the parameter (Array &C) for the input function, but I'm not sure how to change the body of the input funtion
First off, the expression sizeof(v)/sizeof(v[0]) does not do what you expect it to do.
This would work for a statically-allocated array, not for a dynamically-allocated array.
A sizeof expression is translated during compilation-time, by applying it on the type of of the operand.
In your case, the operand is v and its type is int**.
Therefore, sizeof(v) is equivalent to sizeof(int**), and sizeof(v[0]) is equivalent to sizeof(int*).
You expect the expression sizeof(v) to give you the size of the dynamically-allocated array pointed by v, but the compiler cannot guess (during compilation-time) what this size is going to be during runtime.
With regards to the actual question at hand (and as already mentioned in a comment to it), you'll need to implement the following functions in your Array class:
Reader - int* Array::operator[](int index) const {return v[index];}
Writer - int*& Array::operator[](int index) {return v[index];}
BTW, declaring in the constructor a local variable named v, will result in the initialization of that local variable instead of in the initialization of the member variable of the same name.
My goal is to read in a file at the command line, which is to be an adjacency matrix representation of a directed graph, and store the values in a 2D array. My plan is to read the number of integers on a line and use that as the size for my array(i.e. a 5 line input, with 5 integers per line would mean i would create a 5 x 5 array). However, to initialize an array, a constant value is needed, and counting the integers per line and storing it in a variable to use as my size parameter, does not allow me to create the array.
Sample input:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Code:
#include <iostream>
#include <sstream>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
string currentLine;
int i, m = 0;
int count;
ifstream input(argv[1]);
int storage[10000];
printf("Original matrix: \n" );
if(input.is_open())
{
while(getline(input, currentLine))
{
istringstream iss(currentLine);
count = 0;
while(iss >> i)
{
if(iss.eof())//at end of each line, ends loop
{
count++;
storage[m] = i;
m++;
printf("%d \n", i);
break;
}
else
{
count++;
storage[m] = i;
m++;
printf("%d ", i);
}
}
}
}
int **matrix;
matrix = new int*[count];
for(int y = 0; y < count; y++)
matrix[y] = new int[count];
for(int r = 0; r < count; r++)
for(int c = 0; c < count; r++)
matrix[r][c] = storage[r+c];
printf("first = %d ", matrix[0][0]);
system("PAUSE");
return 0;
}
Based on my input, I should create a 5 x 5 array. But the line
int matrix[count][count];
Gives me an error saying that the "count" size parameter should be a constant. Is my way of counting the size of the input to use an invalid way of doing this, or is there a way to create a constant to use as my size param?
Instead of using 2D native C++ arrays, consider using a vector of vectors.
#include <vector>
#include <iostream>
int main() {
using namespace std;
int count = 5;
// create a matrix of 'count' rows by 0 columns
vector<vector<int>> matrix(count);
// resize the column count for each row
for (auto& r : matrix)
r.resize(count);
// use it just like an array
for (int i = 0; i < count; ++i)
matrix[i][i] = i;
for (int r = 0; r < count; ++r) {
for (int c = 0; c < count; ++c)
cout << matrix[r][c] << ' ';
cout << endl;
}
}
you will need to use a dynamic array
int *myArray; //Declare pointer to type of array
myArray = new int[x]; //use 'new' to create array of size x
myArray[3] = 10; //Use as normal (static) array
...
delete [] myArrray; //remeber to free memeory when finished.
http://www.cplusplus.com/forum/beginner/1601/
http://www.cplusplus.com/doc/tutorial/dynamic/
You are not going to get a 2-D array. You will have to work with Array of Array.
If you are willing to work with dynamic allocations, please do something like this:
int *myArray = new int [count]; // variable length array can get you into trouble here,
// if you are not careful as the inner dimension needs
// to be freed before the array goes out of scope.
for (/*iterate from 0 count*/) {
myArray[i] = new int [count];
}
myArray[m][n] to give you a semblance of what you wanted.