Why my 2D array is not functioning right? - c

I am newbie in C programming.I want to print 2 as my first element is 2 in the 2D array.But as i knew that n holds the first address of the array so *n should print the first element that is 2.My code
‪#‎include‬ <stdio.h>
int main()
{
int n[3][3]={2,4,3,6,8,5,3,5,1};
printf("%d\n",*n);
return 0;
}
why it is printing an address.Can anyone explain it to me??

A 2d array is just an array of arrays, so *n is actually the first subarray, to print the first element of the first subarray:
printf("%d\n", **n);
Or this is simpler and more clear:
printf("%d\n", n[0][0]);

You need to declare your array like this:
int n[3][3]={{2,4,3},{6,8,5},{3,5,1}};
Note that the first [3] isn't necessary (but there's nothing wrong with specifying it). By the way, if you enable warnings, e.g. with gcc -Wall, the compiler will warn that there are missing braces in your initialiser.
Then to print the first value you can use:
printf("%d\n",n[0][0]);
Or, if you prefer:
printf("%d\n",*n[0]);
You have an array or arrays, so this takes the zeroth element (which is an array), then dereferences it to get the zeroth value.

I think that you got some warning on %d because you are not tried to print the value - just the address only.
For a 2D array, to get any value, you need to dereference twice. i.e **n.
*n is also suitable, but for a 1D array.
Here you can use either **n, *n[0] or n[0][0] instead of *n.

If n would have been an array of integers, *n would have printed the first integer, as you are expecting.
But n is not that. Is a 2-dimensional array. One way of looking at it would be: an array of arrays. So in fact *n is an array.

If you have an 1D array-
int n[9]={2,4,3,6,8,5,3,5,1};
printf("%d\n",*n);
Because If you dereference the 1D array it will fetch the element. Now It will print 2.
But
int n[3][3]={2,4,3,6,8,5,3,5,1};
It is a 2D array so you need to dererence two times. If you dererence one time it will fetch the address of the array only. n, n[0], *n, &n, &n[0] all will represent the starting address of it.
Try -
printf("%d\n",**n);
or
printf("%d\n",n[0][0]);

Related

C programming with pointers

Write a program that creates a random array of 20 integers with a pointer that initially points to the first element of the array. The program will have a while loop that allows the user to do any of the following:
print the array of numbers with the pointed to number highlighted in some way
move the pointer left or right a certain number of items in the array
change the value of the pointed to number
quit the program
All the changes to the list of numbers must be done with pointers (not by referencing the array index),
I have this to start off which is just setting up the array
#include <stdio.h>
#include <stdlib.h>
int main{
int array[20];
for(int i=0; I<20;i++){
array[I]=rand() % 100;
}
int pointer=&array[0];
int i=0;
return 0;
}
I would really appreciate the help
"with a pointer that points to the first element of the array"
Basically means you need to dynamically allocate memory. A memory block that is allocated always return a pointer to the first element of the array:
int* array = calloc(sizeof(int)*20);
// Allocate memory for 20 integers ^
Now you have an array of 20 integers and array points to it's first element. Then, if we don't actually want to reference the index.
*(arr+1)
Will give you the value of the second element since it evaluates to arr[1].
To print them using a while loop, use an integer to keep track of the current index and while(array+index) print it and increment index.
This is so because memory of a computer is like a street with different houses with an integral number along it.

Why Do I need that extra asterix using 2D array?

I know that if arr is an array then arr[i]=*(arr+i); and if is a 2D array then arr[i][j]=*(*(arr+i)+j); So I have this code
main(){
int arr[5][5];
int arr2[25]; // same as arr[5][5];
int i,j;
for(i=0;i<5;i++)
for(j=0;j<5;j++){
arr[i][j]=i+j;
printf("arr[%d][%d] is at %p\n",i,j,&arr[i][j]);
}
printf("*(arr+i)=%d\n",*(arr+1)); // why this dont work
for(i=0;i<24;i++){
arr2[i]=i;
printf("arr2[%d] is at %p\n",i,(arr2+i));
}
printf("*(arr+i)=%d\n",*(arr2+1)); // prints 1 as expected
}
I know that in C there's no such thing as 2D array, its basically a linear row major contiguous blob of memory. So I'm wondering why I cant print the value of 2D arr using *(arr+1), which means add 1*5*4 bytes to the base of arr and dereference the value at that address. I know that **(arr+1) works but I dont know why I need that extra asterix ? Also If I do this printf("*(arr+i)=%p\n",*(arr+1)); is the same as I would use (arr+i) to interpret as an address
arr is an array of arrays of ints. Its type is int [5][5]. So, the elements of arr is 1D arrays. When used in expression, in most cases, arrays converted to a pointer to its first element. In *(arr + 1), arr is converted to pointer to arr[0], i.e, first 1D array. Adding 1 will increment it by 5*4 = 20 bytes, i.e, next element of array arr which is arr[1].
Since arr[1] is an array, it can't be printed (as a whole), but its address can be. arr[1] is itself an array and it will decay to pointer to its first element, i.e, arr[1][0]. To print its element you need another dereference which is acheived by arr[1][j] (j is columns).
arr[1][j] is equivalent to *(arr[1] + j) which is ultimately equivalent to *(*(arr + 1) + j).
Suggested Reading: What exactly is the array name in c?
As you said, a 2D array in C is basically an array of 1D arrays. You might think of this as an array of rows.
The rightmost * will dereference the outer array, selecting the row you want.
*(arr+i) //this gives me a pointer to the row I want
The * to the left of that will dereference in the inner array, selecting an element from the row.
*(*(arr+i)+j) //this gives me an element in the row
**(arr+i) is just a special case of the above where the column number j is 0.
The type of *(arr+1) = the type of arr[1] = int [5], which will decay to int* when used in printf.
To print the pointer, use:
printf("*(arr+i)=%p\n", *(arr+1));
To print the object it points to, use:
printf("*(*(arr+i))=%d\n", *(*(arr+1)));
You can make your code easier to read by using:
printf("arr[1] = %p\n", arr[1]); // Print the pointer
printf("arr[1][0] = %d\n", arr[1][0]); // Print the value

2D array and pointers

int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%u %u",*(stud+1),stud+1);
printf("%u, %u", &stud,stud);
Why this statement prints similar values, stud[1] or *(stud+1) is actually an array hence must get the base address i.e &stud[0][0], but stud itself is a pointer to an array of array. Also the third statement prints identical values.
Your observations are correct concerning the expressions are all address-results. But the types of those addresses per the standard are different. Your phrase "but stud itself is a pointer to an array of array". is not accurate. stud is an array of arrays. Pointers are not arrays. After decades of trying to come up with a solid vernacular that describes how it works, and refusing steadfastly to walk the "decay" plank (a word that appears exactly one times in the C standard and even there it is used as a verb-footnote), the best I could come up with is this:
Pointers are not arrays. A pointer holds an address. An array is an address.
Each expression is shown below Given int stud[5][2];
stud int (*)[2]
stud+1 int (*)[2]
*(stud+1) int *
&stud int (*)[5][2]
Remembering that, per the standard, the expressive value of an array is the address of its first element, and pointer-to-element-type is the type of said-address. In both outputs each pair of expressions have equivalent addresses, but they're different types. This is verifiable with some expansion of the original code:
#include <stdio.h>
int main()
{
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
printf("%p %p\n", *(stud+1), stud+1);
printf("%p %p\n", &stud,stud);
int (*p1)[2] = stud+1; // OK
// int (*p2)[2] = *(stud+1); // incompatible types
int *p3 = *(stud+1); // OK
int (*p4)[5][2] = &stud; // OK
return 0;
}
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
The above statement defined stud to be an array of 5 elements where each element is of type int[2], i.e., an array of 2 integers. It also initializes the array with an initializer list.
Now, in the expression stud + 1, the array stud decays into a pointer to its first element. Therefore, stud + 1 evaluates to &stud[1] and is of type int (*)[2], i.e., a pointer to an array of 2 integers . *(stud + 1) is then *(&stud[1]), i.e., stud[1]. stud[1] is again an array type, i.e., int[2], so it again decays to a pointer to its first element, i.e., &stud[1][0] (which is the base address of second element of the array stud[1]) in the printf call.
Please note that stud + 1 and *(stud + 1) evaluate to the same address but they are not the same type.
Similarly, &stud and stud decay to the same address but they are different types. stud is of type int[5][2] where as &stud is of type int (*)[5][2].
Why this statement prints similar values, stud[1] or *(stud+1) is actually an array hence must get the base address i.e &stud[0][0], but
stud itself is a pointer to an array of array.
You are wrong here. The base address of stud[1] or *(stud + 1) is &stud[1][0] and not &stud[0][0]. Also, stud is not a pointer but an array type. It decays to a pointer to its first element in some cases like here but it does mean it is a pointer.
Also, you should use %p conversion specifier for printing addresses.
Without using any decaying syntax it may be clearer (these are the same addresses as your code; the first line is in the opposite order; and my parentheses are redundant but hopefully it improves clarity of this example):
printf( "%p %p\n", &(stud[1]), &(stud[1][0]) );
printf( "%p %p\n", &(stud), &(stud[0]) );
In both cases the first address on the line matches the second because the first element of an array lives at the same address as the array. Arrays can't have initial padding, and in C the address of an object is the address of its first byte.
The first element of stud is stud[0], and the first element of stud[1] is stud[1][0].
Since all of those values you are trying to display are all pointers you should use %p instead of %u. If you do that you will see that the addresses pointed to:
printf("%p, %p", &stud,stud);
are different than:
printf("%p %p",*(stud+1),stud+1);
because as you said stud is a pointer to an array of array.
Lets analyze the program
int stud[5][2] = {{1,2},{3,4},{5,6},{7,8},{9,8}};
Now address will be like this (assuming 2 byte integer). Brackets denote corresponding elements in array.
1 element of 2-D array ---> 4001(1) 4003(2)
2 element of 2-D array ---> 4005(3) 4007(4)
3 element of 2-D array ---> 4009(5) 4011(6)
4 element of 2-D array ---> 4013(7) 4015(8)
5 element of 2-D array ---> 4017(9) 4019(8)
We know that arr[i] gives the ith element of array. So when we say stud[0] we expect 0th element of array stud[5][2].
We can assume 2-d array as collection of 1-d array. So with statement like printf("%u",stud[0]) we exptect 0th element to get printed and what is 0th element for this array. It is one dimensional array. We know that just mentioning 1-D array gives its base address. Hence printf would print base address of 0th 1-D array and so on.
With this information we can analyze your problem.
Remember stud is 2-D array. stud is treated as pointer to zeroth element of 2-D array. So (stud + 1) would give address of 2nd element of 2-D array. And thus printing (stud+1) would print address of 2nd element of stud array. What is it. It will be 4005 from above addresses.
Now lets see why *(stud +1) also gives the same value.
Now we know that *(stud +1) is equivalent to stud[1]. From above we know stud[1] would print base address of 2nd 1-D array. What is 1-d array at 2nd position it is (3,4) with address (4005,4007). So what is it base address. It is 4005. Thus *(stud+1) also prints 4005.
Now you say stud[0] and &stud[0] print the same value.
From above stud[0] is 1-d array and printing it gives its base address. Now so &stud[0] should give address of 1-D array which is same as its base address. Thus they print the same address.
Similar explanation will hold for other cases.

regarding two dimensional arrays

if i have created an array like
int marks[4][2];
then the name of the array must give me the address of the first element,as is in case of one dimensional array,but it is not so?
& also
printf("%d",marks[0]);
&
printf("%d",marks);
yield the same result?????????
printf("%d",marks);
Giving a wrong format-specifier leads to undefined-behavior. marks leads to a pointer to 1D array( i.e., pointer pointing to the first element of first row ).
So, to print a pointer's content %p should be used instead.
printf("%p",marks);
And it seems you are trying to print the value at a location 0*0. So -
printf("%d",marks[0][0]); // [m][n] is the way of accessing 2D array elements.
It behaves as expected for me:
#include <stdio.h>
int main(int argC,char* argV[])
{
int marks[4][2]={0};
printf("%x %x %x\n"
"%x %x %x\n"
"%x %x\n",
marks,marks[0],marks[0][0],
*marks,&marks,**marks,
&marks[0],&marks[0][0]);
return 0;
}
Has output:
12ff44 12ff44 0
12ff44 12ff44 0
12ff44 12ff44
All pointers to the first element of the list (except the zero which is the first element of the list).
In C , for example A 2D array is treated as a 1D array whose elements are 1D arrays.So if you want to get the address of any of the elements you will have to use
printf("%8u\n",&a[i][j]);
Both the print statements print the same result because both marks and marks[0] are pointing to the starting of the first row of the two dimensional array.
When you use %d in a printf format, the corresponding argument (after default promotions) MUST have type int. Since you broke that rule in both cases, anything could happen.
marks has type int[4][2] and decays to int(*)[2], which is not int.
marks[0] has type int[2] and decays to int*, which is not int.
(But I'm still surprised an actual implementation would output different addresses.)

dreferencing 2 d array

Please look at this peice of code :-
#include<stdio.h>
int main()
{
int arr[2][2]={1,2,3,4};
printf("%d %u %u",**arr,*arr,arr);
return 0;
}
When i compiled and executed this program i got same value for arr and *arr which is the starting address of the 2 d array.
For example:- 1 3214506 3214506
My question is why does dereferencing arr ( *arr ) does not print the value stored at the address contained in arr ?
*arr is type integer array of length 2, so it shares the same address as arr. They both point to the beginning of their arrays, which is the same location.
in C, a 2d array is not represented in memory as an array of arrays; rather, it is a regular 1d array, in which the first given dimension is needed in order to calculate the right offset within the array at execution time. This is why in a multi-dimensional array you always need to specify all the dimensions except the last one (which is not required); for example, if you declare an array like
int a[2][3][4];
the array would be represented in memory as a single array of 2*3*4 elements in total. Trying to access the element at position (i,j,k), will actually be translated into accessing the element 3*i+4*j+k in the plain array. In some sense, the initial dimensions are needed to know where to put "row breaks" in the 1d array.

Resources