1

These two are different programs for declaring a 2D array

1)i think they are same because both are 2D array?

2)can we access both using a[i][j] and p[i][j]?

3)Why *a or a are same and p or *p are different

#include<stdio.h>
#include<stdlib.h>
int main(){
   int a[100][100];
   printf("%d\n",a);
   printf("%d\n",*a);


   int **p=malloc(sizeof(int*)*100);
   for(int i=0;i<100;i++){
     p[i]=malloc(sizeof(int)*100);
   }
   printf("%d",p);
   printf("%d",*p);

   }
newby
  • 189
  • 2
  • 12
  • 1
    Aside: some `#include`s are missing. Please start by enabling all compiler warnings and fixing them. – Weather Vane Oct 08 '18 at 21:40
  • `int **p=malloc(sizeof(int*)*100);` how does this compile on your end without throwing an error 0.0? – Yucel_K Oct 08 '18 at 21:43
  • 2
    @Yucel_K because that part is valid C code (with the right library header). It allocates memory for a pointer which can be used as an array of 100 pointers to `int`. – Weather Vane Oct 08 '18 at 21:46
  • @Weather Vane. hmm in my xcode, I'm getting `can not initialize type int** with an rvalue of void*` – Yucel_K Oct 08 '18 at 21:50
  • 1
    @Yucel_K Are you using a C++ compiler? Because it is not valid C++ code. – Christian Gibbons Oct 08 '18 at 21:52
  • @Christian Gibbons it could well be that. suppose to support c but i guess needs some settings to the xcode. – Yucel_K Oct 08 '18 at 21:53
  • 3
    @Yucel_K in C here is no cast required from `malloc` return value of type `void*` and is even undesirable. – Weather Vane Oct 08 '18 at 21:53
  • 1
    @Yucel_K You can't even find difference between c and c++, Go get some sleep sir – newby Oct 08 '18 at 21:54
  • 3
    One thing to remember is that C does not actually specify multi-dimensional arrays as some special case, but they are rather possible because an array is a type like any other. Thus, a 2-D array is really an array of arrays. So, when you declare `a`, you are really declaring 100 arrays. In this case, it seems that your compiler allocated space for 10,000 ints contiguously. But, when you do the dynamic allocation of p, you have not done that. That's why your `printf`s yield different outputs. Also, note that you should use the `%p` format specified with pointers. – bruceg Oct 08 '18 at 21:55
  • 2
    The other warnings I am getting is as @bruceg writes, the way you output pointer values, which in C should be `printf("%p\n", (void*)a);` in the first case. – Weather Vane Oct 08 '18 at 21:58
  • but why a[i][j] and p[i][j] works in same manner @bruceg – newby Oct 08 '18 at 22:00
  • 3
    Because of the way the language works. In the first case the compiler knows that `a` is a 2-D array and treats it so. In the second case the compiler knows that `p` is a pointer to an array of pointers, and does the right, but different, thing. Essentially, `a` is a 1-D array and the compiler figures out the indexing because the memory is contiguous, but in the case of `p` the memory layout is quite different. – Weather Vane Oct 08 '18 at 22:08
  • @WeatherVane Got it Sir Thanx – newby Oct 08 '18 at 22:15
  • I recommend @Lundin's amazing answer to a very similar question: https://stackoverflow.com/a/43909688/1212725 – bruceg Oct 08 '18 at 23:51
  • Note, too, that you *can* allocate genuine 2D arrays dynamically, and it's in fact simpler than is allocating an array of pointers and then allocating memory for all those to point to. – John Bollinger Oct 09 '18 at 00:39

3 Answers3

3

the big difference is that in case with a[100][100] the compiler knows the full size of the array and allocates a contiguous memory region on a stack (as in your case) or in static area. When accessing an array element, the compiler is free to calculate its address based on the array dimensions and use a single reference to access it. like this

[0,0][0,1][0,2]...[0,99][1,0][1,1][1,2]...[99,0]...[99,99]
+-------0------...-----+----- 1 -------...+----- 99 -----+

In case of the dynamic allocation, which you used, the memory is allocated contiguously only for a single dimension of the array. So, you allocate 100 pointers, every one of each points to a single dimensional array of integers. Those arrays can be placed at arbitrary memory locations. As a result, the compiler has to do at least 2 references in this case, use first index to get a pointer to the second array, than use the second index to get the element in the second array.

pointers[index0] : [0][1][2]..[99]
                    /  |  \
                   /   |   |
                   V   V   V
                  [0] [0] [0]     
                  [1] [1] [1]
                  ... ... ...

some addition about a and *a. In 'c' when the name of the array is used in a pointer like context, it is interpreted as an address of the array. So, in printf a points to the beginning of the two-dimensional array. *a for same reason is supposed to provide you an address of the first column. Which in this case is the same as the start or the array. **a will point you to the very first array element a[0][0]. And by the way, it is better to use %p there instead of %d for pointers.

You can see that for the dynamic array p gives you the address of the array of pointers, whether *p gives you the value of its first element p[0] which by itself is a pointer to the column. The addresses are definitely different.

But in both cases you can use a[i][j] and p[i][j] to access array elements.

alk
  • 69,737
  • 10
  • 105
  • 255
Serge
  • 11,616
  • 3
  • 18
  • 28
  • good answer - i was going to type the same thing but a) I suck at ascii art b) I could not remember if c is row/col or col/row for 2d array – pm100 Oct 08 '18 at 23:23
2

They are not the same. The first (int a[100][100]) is a single variable that is a compound object. The other (int **p) is a collection of arrays that you are using as a data structure for matrices.

If you want to have an actual 2D array in dynamic storage, this is how you do it:

#include <stdlib.h>

int main()
{
    int (*m)[100][100];

    m = malloc(sizeof *m);
    for (int i = 0; i < 100; i++)
        for (int j = 0; j < 100; j++)
            (*m)[i][j] = 0;
}

Of course, the syntax is a bit weird, and you would rather have a dynamic matrix with variadic number of columns and rows, which is why you would prefer to declare a matrix pointed by int **p.

The reason why a and *a give the same output is because both decay to a pointer to the first element of a, which is a[0][0]. On the other hand, p is a pointer itself, and *p is the contents of the variable pointed by p. They are just as different as they would be if you did this:

int d = 0;
int *p = &d;
printf("%p\n", p);
printf("%d\n", *p);

Now back to your int **p.

Yes, you can access both int a[][100] and int **p with double indexing. However, there is a fundamental difference in the way the compiler treats a[i][j] and p[i][j].

In a[i][j], each a[i] is an array of 100 integer objects. So in order to access the i-th element, and then the j-th element, the compiler has to acess the i*100+j-th element from a[0][0]. This access can be performed in a single step with some index arithmetic.

In v[i][j], each v[i] is a pointer which may point to objects far from each other in memory. In order to acess the element v[i][j], the compiler must first follow p to the array *p, then find the i-th element in this array, which is a pointer to the array p[i]. And then with some pointer arithmetic it will find the j-th element of this array.

giusti
  • 3,156
  • 3
  • 29
  • 44
-2

a is the address of the array in memory, its value depends on how your compiler and operating system layout memory. *a is the value in memory at that location, again depending on your operating system this is either random or set to some pre-determined value. Similarly for p and *p

For ease of debugging most operating systems set memory to some deliberate fixed value. Unix typically sets malloc() memory to zero. Windows has a range of default contents depending on how the memory was allocated see: When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • 1
    The C standard does not require `malloc` to initialise the memory allocated, but `calloc` does. – Weather Vane Oct 08 '18 at 22:00
  • Yes but all Unix implementations I have ever seen set it to zero, that's why I said 'typically' – Martin Beckett Oct 08 '18 at 22:00
  • 2
    I am not on Unix and there is no OS tag in the question. Just stick to the C standard please. Anything else is for a debugging aid or anti-snooping policy and cannot be relied on. – Weather Vane Oct 08 '18 at 22:01
  • 1
    The code in the question shows `a` declared as `int a[100][100];`. For this `a`, `*a` is not the value in memory at `a` or any other address. Nominally, `*a` is the first element of `a`. That first element is an array of 100 `int`. In most uses, that array will be automatically converted to a pointer to its first element. – Eric Postpischil Oct 08 '18 at 22:10
  • 3
    `malloc` does not typically set memory to zero on Unix implementations. When the operating system gives a process memory, it typically sets to zero (if it is not being mapped from a file). The primary purpose for that is to erase any data from other processes, for security, rather than for debugging ease. Consequentially, most of the memory provided by `malloc` may be zero the first time it is provided. However, after it is used, freed, and reallocated, it is not generally zero. The link you point to is for debugging mode, not normal operation. – Eric Postpischil Oct 08 '18 at 22:12
  • I am on Linux, and in release mode, `malloc` definitely does NOT set allocated memory to any particular value. You just get a pointer to a memory location that's the size you asked for (or NULL in case of failure). The values stored in the memory that has been allocated for you is usually just what was stored in them by the previous user of that space before the memory was `free`d. – bruceg Oct 08 '18 at 22:13
  • @EricPostpischil That's very interesting. Does it also explain why local variables seem to be initialized with zero? I was assuming GCC started initializing automatic storage. – giusti Oct 09 '18 at 00:37