Jose V
Jose V

Reputation: 1854

How to create a dynamic array that holds static arrays in C?

My program parses code, and as it parses code I need to keep track of how many instances of each keywords it goes through every x number of lines (probably every 10 lines or so), from this information I plan on later creating a histogram with gnuplot but that's not important.

So there's 13 keywords, I can easily keep count of them with an array of 0s where each index represents a keyword and whenever I find a keyword I increase it's index by 1. Ok simple

int keywordcount[13]={0};

The thing is that I need to create a new keywordcount every 10 lines, and I don't know how many code lines the file has. So this tells me thatI should have a dynamic array of keywordcount arrays.

How do I declare this dynamic array of arrays in C and how do I add to it keywordcount arrays? I'm still confused by multidimensional arrays in C. I don't know if I should declare it as an array of pointers or what, and I don't know how I would go about assigning it a new keywordcount array which would not disappear when the function that creates keywordcount returns. Let me know if something isn't clear.

Upvotes: 2

Views: 2497

Answers (3)

ad absurdum
ad absurdum

Reputation: 21323

You can use malloc() or calloc() to create a dynamic array of static arrays. For example, this defines keywordcount_arr as a pointer to an array of 13 ints (here enough memory is allocated for max_lines such arrays):

size_t max_lines = 10;
int (*keywordcount_arr)[13] = calloc(max_lines, sizeof *keywordcount_arr);

It may make the code a little easier to read and write if a typedef is used here:

typedef int KW_Count[13];

/* ... */

KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);

You can index into the allocated memory using 2d array indexing:

for (size_t i = 0; i < 13; i++) {
    keywordcount_arr[0][i] = i;
}

Or, if an existing array must be stored in the dynamic array, memcpy() can be used. If the dynamic array needs to grow, realloc() can be used. And realloc() can be used again to trim the dynamic allocation to final size:

max_lines *= 2;
KW_Count *temp = realloc(keywordcount_arr,
                         sizeof *keywordcount_arr * max_lines);

Here is an example program:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_KEYWORDS  13

typedef int KW_Count[NUM_KEYWORDS];

int main(void)
{
    size_t max_lines = 10;
    size_t num_lines = 0;
    KW_Count *keywordcount_arr = calloc(max_lines, sizeof *keywordcount_arr);
    if (keywordcount_arr == NULL) {
        perror("Allocation failure");
        /* Handle error... perhaps: */
        exit(EXIT_FAILURE);
    }

    /* Store keyword counts directly in keywordcount_arr[] */
    ++num_lines;
    for (size_t i = 0; i < NUM_KEYWORDS; i++) {
        keywordcount_arr[0][i] = i;
    }

    /* Or use memcpy() if an existing array must be stored */
    ++num_lines;
    KW_Count keywordcount = { 0, 2, 0, 0, 3, 1, 0, 0, 0, 1, 2, 0, 1 };
    memcpy(keywordcount_arr[1],
           keywordcount,
           sizeof *keywordcount * NUM_KEYWORDS);

    /* Use realloc() to grow the dynamic array as needed */
    max_lines *= 2;
    KW_Count *temp = realloc(keywordcount_arr,
                             sizeof *keywordcount_arr * max_lines);
    if (temp == NULL) {
        perror("Unable to reallocate");
        /* Handle error */
    } else {
        keywordcount_arr = temp;
    }

    /* Use realloc() to trim the dynamic array to final size */
    temp = realloc(keywordcount_arr, sizeof *keywordcount_arr * num_lines);
    if (temp == NULL) {
        perror("Unable to reallocate");
        /* Handle error */
    } else {
        keywordcount_arr = temp;
    }

    /* Display array contents */
    for (size_t i = 0; i < num_lines; i++) {
        for (size_t j = 0; j < NUM_KEYWORDS; j++) {
            printf("%5d", keywordcount_arr[i][j]);
        }
        putchar('\n');
    }

    /* Cleanup */
    free(keywordcount_arr);

    return 0;
}

Program output:

    0    1    2    3    4    5    6    7    8    9   10   11   12
    0    2    0    0    3    1    0    0    0    1    2    0    1

Upvotes: 3

n. m. could be an AI
n. m. could be an AI

Reputation: 119877

Don't touch 2D arrays, arrays of arrays, arrays of pointers, pointers to arrays or any such nonsense.

Wrap your statically-sized array in a struct.

typedef struct
{
  int keyword_count[13];
} fragment_info;

Have a dynamic array of fragment_info like you would create any other dynamic array:

fragment_info* infos = malloc(initial_capacity * sizeof(*infos));
....
fragment_info* new_infos = realloc(infos, new_capacity * sizeof(*new_infos));

Now if you want to store additional information about your 10-line fragments, you have a natural place to keep it. Just add more fields to the struct.

Upvotes: -3

gsamaras
gsamaras

Reputation: 73366

Make an assumption of how many keywordcounts will be created. Let's say that you are almost sure that 10 of them will be created.

You can dynamically declare a 2D array, of 10 rows and 13 columns.

Now keywordcount[0] will be the index of the first keywordcount array (which has size 13), and so on.

Now, if in action you see that you need more than 10 keywordcount arrays, you could use realloc() to dynamically increase the size of your 2D array.


PS: A good tip would be to double the size of your 2D array in rows every time you need to increase its size (instead of increasing by one row every time, so that you can avoid rellocations, which can be harm performance in some cases).

Upvotes: 2

Related Questions