0

I wanted to dynamically allocate a partially fixed size array, but ran into errors which would lead me to believe I don't actually know how an array like this functions, so I'm trying to figure out how would you dynamically allocate in this case? Basically I'm asking how to do what's done in this question, Initialization of 2D array with dynamic number of rows and fixed number of columns. C++ but in pure C.

char *list[256];
int len = 10;
list = (char **) calloc(len, 256);

This is the code I have right now, but I'm getting this error: "error: assignment to expression with array type". Thanks.

Ethan
  • 161
  • 2
  • 19
  • 1
    What do you want `list` to be, an array of pointers (which is what you currently have), or a pointer to an array (which would be `char (*list)[265]`)? – Some programmer dude Jul 26 '23 at 08:37
  • 4
    You possibly want `char (*list)[256];` and `list = calloc(len, sizeof(*list));`. – Ian Abbott Jul 26 '23 at 08:41
  • @Someprogrammerdude I want a dynamically allocated array pointer to a bunch of fixed 256 length arrays – Ethan Jul 26 '23 at 09:19
  • 2
    @Ethan Then see Ian Abbot's comment, that's exactly what you describe – the cast then would look like `(char(*)[256])`, but you actually [needn't cast the result of malloc in C](https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) (many would say *'should't'*, but make up your own mind) – unless you write C++ compatible code, that is. – Aconcagua Jul 26 '23 at 09:39
  • @Aconcagua In this case, the cast to `char **` is flat wrong. `list` is not a `char **`. A `char **` or any other double pointer like it never refers to an actual two-dimensional array. – Andrew Henle Jul 26 '23 at 09:56
  • @Aconcagua My comment is in *addition* to your comment - not only is the cast unnecessary in C, in this case the OPs `(char **)` cast is actually wrong. – Andrew Henle Jul 26 '23 at 12:44
  • @AndrewHenle I see, little misunderstanding – addressing me directly gave impression you'd be referring directly to my comment, maybe something being wrong with ;) – Aconcagua Jul 26 '23 at 13:09
  • @Aconcagua I've found that a combination of both of yours and Ian Abbott's comments has given me the behavior I was looking for, and it may not be necessary to cast it but I just find it helps if I know what the type actually looks like, now if someone could form that into an answer because the current top rated answer looks interesting, but it seems more complicated than what I'm looking for. Thanks. – Ethan Jul 27 '23 at 07:19
  • @Ethan No need to write a duplicate, the currently top-rated answer covers that already – note that if you resolve the typedef then `ROW* array` results in `char(*array)[256]` anyway. A minor issue is that `nrows` should actually be of type `size_t` and I'd have considered `sizeof(*array)` (with parentheses) more obvious, but that doesn't matter any further… – Aconcagua Jul 27 '23 at 09:13

2 Answers2

4

Maybe you're looking for something like this:

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

typedef char    ROW[256];

int     main( int argc, char *argv[] )
{
        int     nrows = 10;
        ROW     *array = calloc( nrows, sizeof *array );

        // just filling the first columns for demonstration
        for( int row=0; row<nrows; row++ ) {
                for( int col=0; col<5; col++ ) {
                        array[row][col] = row * 10 + col;
                }
        }
        for( int row=0; row<nrows; row++ ) {
                for( int col=0; col<5; col++ ) {
                        printf( "%3d ", array[row][col] );
                }
                fputc( '\n', stdout );
        }
}

Output:

  0   1   2   3   4 
 10  11  12  13  14 
 20  21  22  23  24 
 30  31  32  33  34 
 40  41  42  43  44 
 50  51  52  53  54 
 60  61  62  63  64 
 70  71  72  73  74 
 80  81  82  83  84 
 90  91  92  93  94 

Here, I'm using a typedef to define a a row with a fixed number of columns and use that to create an array with a variable number of rows

Ingo Leonhardt
  • 9,435
  • 2
  • 24
  • 33
0

So, do you want to allocate a matrix of size (N, 256)?

You can allocate it as a 2D vector, as:

char **list;
int len = 10;
int i = 0;
list = (char **)malloc(sizeof(char *)*len);
for(i==0; i<len; ++i){
    list[i] = (char *)calloc(256, sizeof(char));
}
  • 2
    That's not a "2D vector". That's an array of pointers to multiple and separate 1D arrays of `char`. – Andrew Henle Jul 26 '23 at 09:55
  • That's likely not what the question author has in mind – this solution allows for jagged arrays, distributes data all over the memory destroying any data locality and requires double indirection. Yes, there are benefits of, too, like e.g. easily exchanging individual data rows, but it doesn't appear to be the point here. – Aconcagua Jul 26 '23 at 11:37
  • @AndrewHenle, is there any practical difference? Can a 2D be implemented in a different way where the 1D arrays are not going to be separated? Thanks – Federico Turco Jul 26 '23 at 11:41
  • @FedericoTurco See [this answer](https://stackoverflow.com/a/76769824/1312382)... There's just a single malloc, so all data held together, and just one single pointer involved. Data represents a large array of continuously allocated elements where each individual element is an array of 256 elements itself. – Aconcagua Jul 26 '23 at 11:52
  • 1
    @FedericoTurco There's a huge difference. A true 2D array declared with something like `int x[2][4];` has a completely different memory layout from one built dynamically starting with something like `int **x = malloc(...);`. You can't pass the `x[2][4]` array to a function with an `in **` parameter, and you can't pass an `int **`-based construct to a function expecting an `int[][]` array. See https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays for a good description. – Andrew Henle Jul 26 '23 at 12:35