37

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

12 Answers 12

30

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.

Sign up to request clarification or add additional context in comments.

2 Comments

In this example, what is the correct way to free the memory?
free(jagged[0]);free(jagged[1]);
19

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 }; 

6 Comments

+1. This is where C99's compound literals show off: int *jagged[] = { (int[]){0,1}, (int[]){1, 2, 3} }; isn't that nice too?
The trouble with this solution is that the sub-arrays immediately decay to pointers, so you have no means of telling what the bounds are.
@Neil, i didn't think of this at all. Of course you are right. Good point :)
@Neil: that's where guardian values come in handy to mark the end of the array
@Christoph Guardian values can be problematic for arrays of numbers, as there may be no allowable "special" value. I think storing the array dimension explicitly somehow is better practice.
|
16

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.

Comments

13

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.

Comments

5

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:

Comments

4

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 ;)

1 Comment

I thought you can't make arrays of incomplete type... oh, you're making an array of pointers to an incomplete type, that's possible but doesn't buy you anything over rampion's answer.
4

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 *).

Comments

3

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.

2 Comments

Just out of curiosity: do you know which C standard is required for that to work?
@Cherusker, C99 does support this. More details are available here.
1

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

Comments

1
// //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; } 

1 Comment

hey... You can check my code for implementing jagged arrays in c++
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


    1234
    56



    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


    8 Comments

    I'm pretty sure this should use delete[] jagged[0]; and delete[] jagged[1];, not delete[] jagged;.
    @Ruzihm But you know when we delete a pointer so all the indexes are automatically deleted so we want to delete them all instead of just deleting only one index we want to free the memory.Hope you understand.Thanks.
    Running the code in this answer with valgrind says definitely lost: 24 bytes in 2 blocks both at operator new[](unsigned long). But, removing jagged[i]++; and replacing delete[] jagged; with delete[] jagged[0]; delete[] jagged[1]; reports no leaks are possible.
    Also even compiling this code in g++ gives a warning: foo.cpp:49:14: warning: deleting array ‘jagged’ 49 | delete[] jagged;
    @Ruzihm Thank you Sir.Editing according to your suggestion.
    |
    0

    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.

    Comments

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.