0

I am creating a two-dimensional array in C as follows:

int array1[] = {1,2,3,4,5,6,7,8,9,10};
int array2[] = {11,12,13,14,15};
int* array3[2] = {array1,array2};

and now I want to get the size of both dimensions. For the first dimension I get the correct result of 2 if I use the following code:

int array3_x = sizeof(array3)/sizeof(*array3);    // array3_x = 2

but I am not able to get the size of the other dimension. So far I have tried the following:

for (int i = 0; i < array3_x; ++i) {
  array3_y[i] = sizeof(array3[i])/sizeof(*array3[i]);
}

I always get a result of 1. Is there a way to get the correct sizes of 10 and 5?

zionlion
  • 17
  • 6
  • 1
    Is this C or C++? If it’s C++, then I don’t think it’s possible and you should use `std::vector`. If it’s C, then I don’t know the answer because VLAs are weird. Either way, please only tag one. – Daniel H Sep 06 '17 at 23:23
  • 8
    There is no 2D array here. Just 2 1D arrays of ints and a 1D array of pointers. – John3136 Sep 06 '17 at 23:25
  • you are right John3136, I have first a 1D array of ints that I place inside a pointer. but how do I get the size of the array of ints from the pointer? – zionlion Sep 06 '17 at 23:31
  • 1
    `*array3[i]` is of type int. It's not an array. Problem is, you degenerate the arrays into pointers, which cannot possibly carry any such information. You need to store the data elsewhere (or do something like null termination, which is ugly). Or you switch to C++ if possible. – Aziuth Sep 06 '17 at 23:35
  • You don't. Because those are pointers to int and not to int arrays (even if they were, they would have to have the same length – MikeMB Sep 06 '17 at 23:36
  • @zionlion. There is no easy way to do it with plain arrays. Either a sentinel value at the end of the array so you can search for it, or use your knowledge of how the array was built - you can figure out the lengths of array1 and array2. – John3136 Sep 06 '17 at 23:39
  • Have you learned about structures yet? If so, `struct Array { size_t n_elems; int *data; } array3[] = { { sizeof(array1)/sizeof(array1[0]), array1 }, { sizeof(array2)/sizeof(array2[0]), array2 } };` stores the size information, and you could use `array3[0].n_elems` to get the number of elements, and `array3[0].data[i]` to get the i'th element of the array. – Jonathan Leffler Sep 06 '17 at 23:39
  • Just use 2D arrays. The rest ist straight forward. – too honest for this site Sep 07 '17 at 01:00
  • 1
    A container pointing at two arrays of different size is not a 2D array. For the same reason as why a mathematical matrix must be square-shaped. – Lundin Sep 07 '17 at 08:43
  • @Lundin: Actually a mathematica matric need not be square, but is rectangular. But you are right about the code in the question. Not sure if OP really knows what he wants/needs. – too honest for this site Sep 08 '17 at 00:33

4 Answers4

0

There is this idea of arrays being pointers. They're not. Arrays can degenerate into pointers. The idea here is that arrays are stored contiguous in memory, so if we have a pointer to the first element, we can use pointer arithmetics to get the rest. But understand that this is a pointer to the first element, not an array.

By typing int* array3[2] = {array1,array2};, you create an array that consists of two pointer to first elements of arrays. Those pointers do not carry any information about the length of the arrays. Ever seen a function that takes such a pointer as argument? Those tend to also get the size as another argument. (except for the null-terminated arrays of char)

As a result, you have to store the information in some other way. Being used to C++, my approach would be to use a structure that imitates a class. Essentially imitating the C++ std::vector. That said, I'm not that used to C, no idea if this is the standard approach here.

Edit: An important thing here is your application. The best approach of course needs to know what you want to do. If for example you'd want to store 2D grid data, I'd simply go with a 1D array of size n*m. If you want to store jagged data, you could simply accompany it with an array that stores the sub-arrays sizes.

Aziuth
  • 3,652
  • 3
  • 18
  • 36
  • 2
    Talking someone into C++ is not a good idea. Answer C questions with C, not C++. They are different languages, not just dialects. – too honest for this site Sep 07 '17 at 01:06
  • @Olaf Where exactly do I talk somebody in C++? I'm talking about *imitating* C++ here. – Aziuth Sep 07 '17 at 12:48
  • Your other posts do and this one also refers to some C++ construct. Emulating C++ is often not a good approach. It is unnecessary for this problem. If you don't know C, why do you answer a C question? – too honest for this site Sep 07 '17 at 13:16
  • @Olaf What do you mean by "If you don't know C, why do you answer a C question?"? I mean, my answer is actually an answer to the actual problem at hand. The most important part of my answer is explaining the difference between pointers and arrays, which is crucial in understanding here. And I also provide functional advice how to solve the problem. In C. You make it sound like as if my answer is the same as "Switch to C++!". You advice me to "Answer C questions with C", which I did. I consider my answer to be an answer in the true meaning of that word and am a little puzzled that you don't. – Aziuth Sep 07 '17 at 22:28
  • The idenomatic way to allocate a 2D array is to use a 2D array. Not some other construct, or emulate a C++ vector. It is as traight-forward as it can be. – too honest for this site Sep 07 '17 at 22:49
  • @Olaf Aren't 2D arrays always rectangular? The example from the question is not. His intention might easily be "How many entries do I have in total?". With a 2D array, the size is rows * columns, which is not the amount of entries if the array is supposed to be ragged. Which is another thing I addressed in my answer, mentioning that the context is crucial for the approach. Also, he might not know bounds at compile time. We have the typical application of reading in an image, usually represented by something like `Color** image_data`. Might also be that he knows only the first dimension. – Aziuth Sep 07 '17 at 23:35
  • Yes, they are. And that's what OP is asking about in the first place. But from the latest comments, I noticed, he seems to not be meaning 2D arrays at all. So that makes the question unclear, because it lacks more information. A good C book would be a good investment for him. – too honest for this site Sep 07 '17 at 23:43
0

Perhaps this might work:

If you can turn the arrays into zero-terminated arrays:

int  array1[]  = {1,2,3,4,5,6,7,8,9,10,0};
int  array2[]  = {11,12,13,14,15,0};
int* array3[2] = {array1,array2};

Then you can use a function like this to get the length of each:

/********************************************************************
** Get the length of a zero-terminated int array.
*/
size_t LengthOfIntArray(int *array)
   {
   int *index = array;

   while(*index)
      ++index;

   return((size_t)(index - array));
   }

And you can print the length of each array like this:

/********************************************************************
** Program start
*/
int main(void)
   {
   int i;
   int array3_x = sizeof(array3)/sizeof(*array3);    // array3_x = 2

   printf("Height of array3: %d\n", array3_x);

   for(i = 0; i < array3_x; ++i)
      printf("Length of array3[%d]: %zd\n", i, LengthOfIntArray(array3[i]));

   return(0);
   }

The output will be:

Height of array3: 2
Length of array3[0]: 10
Length of array3[1]: 5
Mahonri Moriancumer
  • 5,993
  • 2
  • 18
  • 28
0
#include <stdio.h>
#include <stdlib.h>

int main() {
    int array1[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int array2[] = {10, 11, 12, 13, 14};
    int *array3[] = {array1, array2};
    unsigned long int c1, c2, c3;

    c1 = sizeof(array1) / sizeof(*array1);
    c2 = sizeof(array2) / sizeof(*array2);
    c3 = sizeof(array3) / sizeof(*array3);

    printf("size of array1 : %2lu\n", c1);
    printf("size of array2 : %2lu\n", c2);
    printf("size of array3 : %2lu\n", c3);

    /* so far, so good ...
       however, the following "printf"s will fail
       to give assumed results
    */

    c1 = sizeof(array3[0]) / sizeof(*array3[0]);
    c2 = sizeof(array3[1]) / sizeof(*array3[1]);

    printf("size of array1 : %2lu\n", c1);
    printf("size of array2 : %2lu\n", c2);

    return 0;
}

In your code, on line array3_y[i] = sizeof(array3[i])/sizeof(*array3[i]); in the for loop, array3[i] does no more point to an array --the compiler has no information about the length of the variable that it's pointing at, whether it is an array, a single char or an int or something else-- but it is just a plain pointer (presumably a pointer pointing to a default int).

I think your current system is using 32 bits for addressing (sizeof(unsigned int) / sizeof(int)); my system, using 64 bits, spits "2" as a result (i.e. sizeof(unsigned long int) / sizeof(int)).

ssd
  • 2,340
  • 5
  • 19
  • 37
  • Why use type `unsigned long` with `unsigned long int c1, c2, c3` vs. `size_t` or `unsigned` or even `int`? As the return type of `sizeof` matches `size_t`, that would seem to be an initial choice. – chux - Reinstate Monica Sep 07 '17 at 03:43
0

No. You can't. The compiler never knows the array size your pointer is pointing to.

Ref: How to find the 'sizeof' (a pointer pointing to an array)?