2

I want to construct a 2d array in C where each row will have different number of elements. Specifically I want to construct a triangular 7x6 array. In order to save memory I want to avoid storing the zeros as in the following example.

                               1 0 0 0 0 0 0
                               1 1 0 0 0 0 0
                                     ...
                               1 1 1 1 1 1 1   

How can I do this?

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
Herc11
  • 49
  • 1
  • 3
  • This is one of the very first pattern problems one is required to solve during learning and you are asking us to solve it for you? – 0decimal0 Jul 01 '13 at 14:19
  • putting these two comments in context, a Porsche is the very first car one is required to own!! – billdoor Jul 01 '13 at 14:37
  • 4
    New users should be directed to the relevant help sections on how questions should be asked - not derided. – Timothy Shields Jul 01 '13 at 14:39
  • 1
    @Herc11 Please read these: (A) [How not to ask](http://stackoverflow.com/help/dont-ask) (B) [How to ask](http://stackoverflow.com/help/how-to-ask) – Timothy Shields Jul 01 '13 at 14:39

6 Answers6

20

Formulation

Won't this system of indexing work?

0
1 2
3 4 5
6 7 8 9
...

Just store your data in a single-dimensional array, using this mapping to the triangular matrix/array.

Bijection

One-dimensional zero-based index k and two-dimensional zero-based row i and column j are the same when k = i(i+1)/2 + j (where j <= i).

Note

The above is for a lower-triangular square matrix/array. You could do something very similar for

  • an upper-triangular square matrix/array
    • simply swap i and j
  • a rectangular lower- or upper-triangular matrix/array
    • this is a little trickier (you need to reason by cases), but the same idea of mapping the one-dimensional array (implementation) to the conceptual two-dimensional array (view) can be accomplished
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • Given `k`, how to I get back to `i` and `j`? – Fabian Oct 21 '20 at 07:47
  • My solution is to try to find the row (using the fact that the first value in each row is given by Gauss formula) and then compute `i` and `j` from it. I iterate with `m` over the array size and compute `c = (m + 1) * (m + 2) / 2;`. Then if `c>m`, the answer is `i = m` and `j = k - m * (m + 1) / 2`. But I don't like that I have to use a loop. Is there a closed formula? – Fabian Oct 21 '20 at 08:59
1

Caution -- this is untested pseudocode, not valid C code.

int **c;
c = malloc (7 * sizeof(int *));
for (i=0;i<7;i++)
  c[i] = malloc ( (i+1) * sizeof (int));

However, I'm not sure why you'd want to do this. You're very likely to end up with segmentation faults if you aren't very careful with your accesses to this array.

hymie
  • 1,982
  • 1
  • 13
  • 18
0

This function will assign a row and column number an index in a one-dimensional array and is unordered:

static inline int64_t index(const int32_t x, const int32_t y) {
    int_fast32_t min, max;
    if (x < y) {
        min = x;
        max = y;
    } else {
        min = y;
        max = x;
    }
    return ((max * (max + 1)) >> 1) + min;
}

will result into indices like (x and y starting with 0):

0   1   3   6   10  15  21  28
1   2   4   7   11  16  22  29
3   4   5   8   12  17  23  30
6   7   8   9   13  18  24  31
10  11  12  13  14  19  25  32
15  16  17  18  19  20  26  33
21  22  23  24  25  26  27  34
28  29  30  31  32  33  34  35
36  37  38  39  40  41  42  43
45  46  47  48  49  50  51  52
55  56  57  58  59  60  61  62
66  67  68  69  70  71  72  73
Sergey L.
  • 21,822
  • 5
  • 49
  • 75
0

Use a one dimensional array and calculate Declare an array with size = rows × (rows + 1) / 2 index = row x (row+1) / 2 + column With this solution you waste time multiplying, dividing by 2 and adding (although a shift right would take care of the divide by 2). Alternatively you may use an array of pointers for each row and allocate the needed number of elements in a loop.

Tarik
  • 10,810
  • 2
  • 26
  • 40
0

Instead of creating a single 1-D array and treating it as a 2-D array, you could create a 1-D array of pointers, where each pointer points to another 1-D array. This lets you allocate each row in the array with a different size.

For example:

// Allocate and initialize a triangular 2-D array
int** make_triangle_array(int nrows)
{
    int **  arr;

    // Allocate the 1-D array of pointers
    arr = malloc(nrows * sizeof(int *));

    // Allocate each row of the triangular array
    for (int i = 0;  i < nrows;  i++)
    {
        int     rowlen = i+1;

        // Allocate a row of ints for the array
        arr[i] = malloc(rowlen * sizeof(int));

        // Fill the row with '1' values
        for (int j = 0;  j < rowlen;  j++)
            arr[i][j] = 1;
    }

    // Return the allocated array
    return arr;
}

// Test driver
void test(int n)
{
    int **  arr;

    arr = make_triangle_array(n);
    ...
    free_triangle_array(arr, n);
}

This approach has the advantage of being able to allocate any size for each row. It also has the advantage of being able to use the syntax arr[x][y] to access a given element within the array.

(This is very similar to the way languages like Java and C# allocate multi-dimensional arrays using references.)

Note that you when you are done using the array, you have to deallocate it in two steps; first you have to deallocate each row of the array, and then you have to deallocate the array (of pointers) itself.

// Deallocate a 2-D array
void free_triangle_array(int **arr, int nrows)
{
    // Free each allocated row
    for (int i = 0;  i < nrows;  i++)
    {
        if (arr[i] != NULL)
            free(arr[i]);
        arr[i] = NULL;
    }

    // Free the pointer array
    free(arr);
}
David R Tribble
  • 11,918
  • 5
  • 42
  • 52
0

As you have mentioned a bit array in your question. So I assume you want to optimise the memory usage while using a very simple code. One solution if the 2-d array is fixed(maybe in your case) is to create a structure with bit fileds assigned as shown below:

struct triangular_array {
int line1:1      __attribute__((packed));  //line1 will have only one bit storage capacity
int line2:2      __attribute__((packed));
int line3:3      __attribute__((packed));
int line4:4      __attribute__((packed));
int lint5:5      __attribute__((packed));
int lint6:5      __attribute__((packed));
int lint7:7      __attribute__((packed));
.
.
.
.
and so on
};

//create an object
struct triangular_array object1;

//initialise the object
object1.line1= 0b1;
.
.
.
.

Things about this implementation :

  1. Simple method, but might be slower than when you dont use 'packed' attribute. Trade off will be that there would be extra bits packed. Also this might be unsafe for some implimentaitons(check the stackoverflow link below)
  2. You might have to take care on endian at times
  3. This method is at times used in networking code where packets need to be exchanged.

You can read more about attribute :

  1. GCC docs: http://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Type-Attributes.html
  2. Consideration : Is gcc's __attribute__((packed)) / #pragma pack unsafe?
Community
  • 1
  • 1
Pranaysharma
  • 537
  • 6
  • 13