regarding two dimensional arrays - c

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.)

Related

Why is dereferncing 2 times working and 3 times giving segmentation fault

how does it print element of a 3d array with two dereferencing. i thought it needs something like 3 dereferencing printf("%c",*(*(*(a+0)+1)+1));. having an understanding crisis.
int main()
{
char a[2][3][3] = {'a','b','c','d','e','f','g',
'h','i','j','k','l','m'};
printf("%s ", **a);
getchar();
return 0;
}
The argument supplied for a %s specified should be a pointer. For ’%s,printfuses the pointer to fet characters from memory. Therefore, for a three-dimensional array, applying two*to the name results in the correct type, a pointer tochar`.
For %c, the argument should be an int with a character value. Applying three * to the array accomplishes this.
Note: Although **a provides the correct type for %s, the argument is supposed to point to a character in a null-terminated one-dimensional string. Allowing the characters to continue across array dimensions is dodgy.

array passed as array and pointer-C

Why does this program produce p and q as outputs? What is the difference between passing an array as a pointer or as an array.
#include<stdio.h>
void fun(char i[]){
printf("%c,%c", i[1],i[2]);
}
void fun2(char *i){
printf("\n%c,%c", i,i+1);
}
int main(){
char ar[] = {"Aba"};
fun(ar);
fun2(ar);
return 0;
}
Output:
b,a
p,q
You are printing the ASCII conversion of a pointer address in the second function. You must dereference the pointer via *i and *(i+1).
To print the value you should use either *i and *(i+1) or i[0] and i[1] in both the functions. i contains the first address cell of the array you have passed. In either cases, both pass their address.
what is the difference between passing array as pointer or as an
array.
Both functions, fun and fun2, signatures are equivalent. So, you don't really have an array in fun() as you think.
This is because in C, when you pass an array to a function, it gets converted into a pointer to its first element.
So, this statement in fun2()
printf("\n%c,%c", i,i+1);
doesn't print the chars but the addresses i and i+1. And that's not right either since they don't match with the format specifies you have.
When I compiled your code with gcc, it warns:
In function ‘fun2’:
warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘char *’ [-Wformat=]
printf("\n%c,%c", i,i+1);
^
warning: format ‘%c’ expects argument of type ‘int’, but argument 3 has type ‘char *’ [-Wformat=]
As you can see, the format specifiers and the arguments you pass don't match. To print values that i and i+1
point to, you can print it just like how you do in fun():
int fun2(char *i){
printf("\n%c,%c", i[1],i[2]);
}
Hope my long answer here helps!
I have taken integers, the concept remains the same with any data type: char, floats, etc, etc.
Okay, a quick short lesson on arrays and pointers.
Thumb rule 1: Arrays and pointers are almost always interchangable but there are exceptions!
Taking a 1-D array, we can declare it like this :-
int arr[10];
This declares a variable named arr which can hold 10 integer elements.
I can similarly use the pointer notation to represent this array using a pointer variable or by using the array name (arr) itself.
printf ("%d", arr[2]); // Array method : will print out the third element, indexing starts from 0
Thumb rule 2: Array name(be it 1D 2D 3D 4D) always decays into a pointer or an address.
printf ("%lu", arr) //will print out the base address of the array, i.e address of the first element
How to print the value using a pointer ? Simply, dereference it using * operator.
printf("%d", *arr) //Pointer notation - will print the first value
How to reference the array using another variable?
int *ptr = arr; //Pointer notation - just simply write the array name as it decays into an address
printf("%d", *ptr); //Pointer notation - prints the first element
Many people say int *ptr is pointer to an array.
In reality it's not. It's actually a pointer to an integer not an array. Why?
Because in the first place we are storing the address of the first integer of the array and then we can traverse it by incrementing the pointer. So, in real pointer is storing the address of an integer(First integer).
Now, coming to 2D arrays :-
Declaration:-
int arr[2][3]; // arrays of 2 rows and 3 columns, total 6 elements
Same above rules implies :-
printf("%d", arr[0][1]); //prints the second element of the first row.
printf("%lu", arr) //prints the base address of the 2D array
Coming to Pointer Notation :-
printf("%d", *(*(arr + 0) + 1); // how this works?
arr contains the address. Adding a integer to it with make you jump to that row.
arr + 1 // gives the second row, i.e. arr is currently pointing to the first element of second row.
Now, further adding an integer to it, will make you skip to that specified column in that particular row.
((arr + 1) // second row + 2 ) // will you skip to third element of the second row
This is the implicit pointer notation that language gives you, when you choose to treat the array name as a pointer.
Now coming to your problem : - Explicit Pointer Notation:-
What are you trying to achieve is, storing the base address of the 2D array in a pointer.
How to correctly do that ?
int (*ptr)[3]; //reading it goes like this - ptr is a pointer to a 1D array of 3 ints
The 3 here specifies the number of columns your 2D array has.
So what it is doing is, trying to store the base address of first 1D array of that 2D array (which means 0th row base address) into the pointer.
The rest remains the same.
int (*ptr)[3] = arr; // storing the 2D array in ptr
Now, you can use it as a normal pointer(Pointer notation applies on it)
(ptr + 1) //now ptr is pointer to the Second 1D array of that 2D array or you can say to the second row's first element.
Another way you can catch an array in a function is like this:-
I use it very less though.
int main()
{
int arr[2][2];
fun(arr);
}
void fun(int catch[][])
{
}
// This is simple to understand and as well as to relate. Now, again catch can be used as pointer or as an array. It depends on you :)
void fun1(int (*ptr)[2])
{
//my way
printf("%d", ptr[1][1]);
printf("%d", *(*(ptr + 1) + 1));
//answer will be the same
}
//Ptr now contains that 2D array base address, again can be used as an array or a pointer :)

Why the output is same in all three cases?

Can somebody please explain why the output is same in all three snippets below.
and what exactly does the 0th element of array represents.
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",arr);
return 0;
}
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",&arr);
return 0;
}
int main(void) {
char arr[10];
scanf("%s",&arr[0]);
printf("%s",*&arr);
return 0;
}
& ("address of") and * ("dereference pointer") cancel each other out, so *&foo is the same as foo.
Your second snippet is wrong. It passes &arr (a pointer to an array of 10 chars, char (*)[10]) to printf %s, which expects a pointer to char (char *). It just so happens that on your platform those two types have the same size, use the same representation, and are passed the same way to printf. That's why the output looks correct.
As for the difference: arr is a an array of chars. Evaluating an array (i.e. using it anywhere other than the operand of & or sizeof) yields a pointer to its first element.
&arr yields a pointer to the whole array. An array has no runtime structure (that is, at runtime an array is its elements), so the address of the array is also the address of its first element. It's just that the first element is smaller than the whole array and the two addresses have different types.
arr[0] represents the first element of array arr. &arr[0] is the address of first element of array. In all of the three snippet, scanf is reading a string from standard input and will store in array arr.
In first snippet
printf("%s",arr);
will print the stored string in array arr. %s expects an argument of char * type and &arr[0] is of that type and so is arr after it will decay to pointer to its first element.
In second snippet, &arr is the address of array arr and is of type char (*)[10]. Using wrong specifier will invoke undefined behavior.
In third snippet, applying * on &arr will dereference back it to address of the first element of array arr which is of type char * as said above.
Snippet first and third are correct and will give same output for the same input under the condition that input string should not be greater than 10 characters including '\0'. Third code will invoke undefined behavior and nothing can be said in this case.

Why my 2D array is not functioning right?

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]);

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.

Resources