1

I am trying to populate an array I allocated with data recieved from a socket, but am unable to make it work properly. When i define and get data through:

uint16_t data[2048];
recv(network_socket, &data, sizeof(data), 0);

the data is recieved properly, but when I try to do it through an allocated array:

int i;
int N = 3;
int M = 2048;
int **matrix; 

matrix = (int **)calloc(N, sizeof(int *));

for (i=0; i<N; i++) {
    matrix[i] = (int *)calloc(M, sizeof(uint16_t));
}

for (i=0; i<N; i++) {
    recv(network_socket, matrix[i], sizeof(data), 0);
}

I am sensing things go wrong at the final part. As far as I understand matrix[i] at the end gets the pointer to the beginning of row i and should work for recv() but that might be where I'm going wrong here.

EDIT: When I try to printf("Number: %" PRIu16 "\n", matrix[a][b]); I get some whacko large number in the second part, wheras printf("Number: %" PRIu16 "\n", data[a]); works fine in the first.

David Montgomery
  • 473
  • 1
  • 4
  • 15

3 Answers3

3

You tell in your first code you want an array of 16bit unsigned integers and receive them. All is good.

In your second code you want an array of ints which probably aren’t 16bit on your platform. Then you allocate an amount of memory to them based on them being 16bit values and read an undisclosed amount of data in.

Then you try to access them as ints which obviously will cause two uint16_t values being combined into one int if your system is 32bit, or even four on a 64bit system.

Fix your code to use uint16_t as in the first one and it’ll actually know how to handle the 16bit data. Your current code will even have undefined behavior since you try to access memory outside the allocated range.

Sami Kuhmonen
  • 30,146
  • 9
  • 61
  • 74
2

The comments and other answers have pointed out some of the potential problems regarding type consistency (suggestions to use either int or uint16_t, but not to mix) and allocating memory.

A suggestion regarding memory creation:
For simplicity, and readability, especially when desiring to emulate multiple dimensions of an array, consider encapsulating memory creation into a function. For example:

uint16_t ** Create2D(int c, int r)
{   
    uint16_t **arr;
    int    y;

    arr   = calloc(c, sizeof(uint16_t *));
    for(y=0;y<c;y++)
    {
        arr[y] = calloc(r, sizeof(uint16_t));   
    }
    return arr;
}

Call the function like this:

uint16_t ** matrix = Create2D(N, M);
if(matrix)//always good to check return of [c][m]alloc before using
{
    // Use allocated memory
    ...

Notes:

  • This example does not create a 2D matrix, rather an emulation of of one. (as described in great detail HERE) It is actually just a pointer to a collection of pointers, each pointing to the allocated memory such that their contents can be accessed using row-column notation, just as if it had been created as:

uint16_t array[N][M];

Freeing this memory can also be implemented in an encapsulated form. For example:

void free2D(uint16_t **arr, int c)
{
    int i;
    for(i=0;i<c;i++)
    {
        free(arr[i]);
    }
    free(arr);
}  
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Thanks for replying, I will try to structure my code into functions like these. However the tricky part I find is the use of the ´recv( )´ function here – David Montgomery Aug 13 '18 at 12:30
  • 1
    Why would they need to use this look-up table for in the first place? Encapsulating it just hides the crap underneath the carpet. Do it proper instead, as explained [here](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays). – Lundin Aug 13 '18 at 12:35
  • if you are after `unsigned int` use `unsigned int`. Printing a `signed int` via `%u` invokes undefined behaviour. – alk Aug 13 '18 at 12:50
  • Even if `matrix[x][y]` would be an `unsigned short` passing it to the (variadic) `printf()` function it would get promoted to `int`. – alk Aug 13 '18 at 12:52
  • @Lunden - I acknowledge your concern. But when having to perform such pieces of code multiple times in an application, I find it much more readable to encapsulate once, rather than duplicate the messy code necessary many times. In any case, no arguments with what I think is your sentiment, and have cited your linked answer in mine for its very detailed explanation. Thank you – ryyker Aug 13 '18 at 14:45
  • @ryyker What lead me to this approach is that the array rows will be changed (through `recv( )`) one at a time thousands of times. So I figured I wanted to keep each row as separate as possible. But again Im pretty new at this so this might be unnecessary... – David Montgomery Aug 13 '18 at 22:16
  • @Lundin see my comment above – David Montgomery Aug 13 '18 at 22:17
1
int **matrix; 

matrix = (int **)calloc(N, sizeof(int *));
...

The code doesn't work since the above is not a 2D array, but rather a segmented, pointer-based look-up table. As such, it is not in the slightest compatible with arrays.

There is no reason why you need to have such a look-up table here. The problem likely originates in confusion about how to Correctly allocating multi-dimensional arrays.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The problem that lead me to this solution (which should be with `uint16_t`s as pointed out above) was that I have an application that sends data in buckets of 2048, and I need to store this data in some handy way with previously sent data so that I can `fprintf( )` all contents to a .dat file for gnu-plot. I will read through your link to see if I can find a better approach! Thanks for answering – David Montgomery Aug 13 '18 at 22:10