Pointers with multi dimensional arrays in C - c

int array[2][3] = {{2,3,6},{4,5,8}};
printf("%d\n",*array);
What will be the output of this and please explain how?
Regards,
Winston

Educate yourself on multidimensional arrays.
Array array is a 2D array:
int array[2][3] = {{2,3,6},{4,5,8}};
*array is the first element of array array because
*array -> * (array + 0) -> array[0]
The first element of array array is array[0], which is {2,3,6}. The type of array[0] is int [3].
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).
So, in this statement
printf("%d\n",*array);
*array will be converted to type int *. The format specifier %d expect the argument of type int but you are passing argument of type int *. The compiler must be throwing warning message for this. Moreover, wrong format specifier lead to undefined behaviour.
If you want to print a pointer, use %p format specifier. Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *.

This call of printf
printf("%d\n",*array);
invokes undefined behavior because there is used incorrect conversion specifier %d with a pointer expression.
If you will write instead
printf("%p\n", ( void * )*array);
then there will be outputted the address of the extent of memory occupied by the array that is the address of the first element of the array.
That is the expression *array has the type int'[3]. Used as an argument in the call of printf it is implicitly converted to pointer to the first element of the type int *. It is the same as to write
printf("%p\n", ( void * )&array[0][0]);

Related

What is the difference between int (*p)[10]=s and int (*o)[5]=&s?

On basis of the convention int (*o)[5]=&s; is the right way for a pointer o to point an array having 5 elements.
We can also write this s in this statement
int (*p)[10]=s;
but why preferring
&s at int (*o)[5]=&s;
as both of them return the same output.
#include <stdio.h>
int main()
{
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
printf("%d\n",*p);
printf("%d\n",**p);
printf("%d\n",&s);
printf("\n");
int (*o)[5]=&s;
printf("%d\n",*o);
printf("%d\n",**o);
printf("%d",&s);
return 0;
}
Output of this program is:
-593812272
10
-593812272
-593812272
10
-593812272
This is not valid:
int s[5]={10,1,2,3,4};
int (*p)[10]=s;
Because you're initializing a variable of type int (*)[10] (a pointer to an array of int of size 10) with an expression of type int *. These types are not compatible.
While this is fine:
int (*o)[5]=&s;
Because the type of the initializer matches the type of the variable.
Also, when printing pointer values, you should use the %p format specifier and cast the argument to void *. Mismatching format specifiers with their associated arguments triggers undefined behavior.
This line
int (*p)[10]=s;
is incorrect. The initializer has the type int * due to the implicit conversion of the array designator s to a pointer to its first element. And the two pointers in the left hand side and in the right hand are not compatible. So the compiler should issue a message.
This line
int (*o)[5]=&s;
is correct. The initializer has the type int ( * )[5] that is the same type of the initialized pointer o.
Pay attention to that to output a value of a pointer you have to use the conversion specifier %p. Otherwise using the conversion specifier %d to output a pointer invokes undefined behavior.
So for example instead of these calls
printf("%d\n",*o);
//...
printf("%d",&s);
you have to write
printf("%p\n", ( void *)*o);
//...
printf("%p\n", ( void * )&s);
The expression *o yields value of the array s that is in turn is implicitly converted to a pointer to its first element.
The values of the expression *o and of the expression &s are the same because it is the address of the extent of memory occupied by the array. But their types are different. The first expression used as an argument of the call of printf has the type int * while the second expression has the type int ( * )[5].

Interpreting lvalue and rvalue with notation arr+4 and arr++

int arr[5];
arr++;
arr+4; //compile with only this
printf("%u", arr);
Why is the C language compiler not able to compile with arr++ saying "lvalue required" but can
compile successfully with arr+4? What is the lvalue concept with arr++ notation?
When you use arr it can naturally decay to a pointer to its first element, i.e. it's equivalent to &arr[0].
When you do arr++ you attempt to modify this pointer (effectively doing arr = arr + 1). This is not possible, since the location of the array is fixed and can not be modified.
With arr + 4 you're doing pointer arithmetic. Here you add 4 to the decayed pointer, but you do not attempt to modify the pointer itself. This is equal to &arr[4] in fact.
There is another small problem in the code you show. I say small but I mean big.
With
printf("%u", arr);
you let the array decay to a pointer. Then you attempt to print this pointer using the "%u" format specifier. But that format specifier is to print int, not pointers. Mismatching format specifier and argument types leads to undefined behavior.
To pint a generic (void *) pointer you need to use the "%p" format, and cast the pointer to void *:
printf("%p", (void *) arr);

Why use the & sign to retrieve an integer's memory address, but not a function's address?

I'm currently following along with the Big Nerd Ranch's Objective-C guide, and one of the examples is as follows:
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i); return 0;
}
// output => i stores its value at 0xbffff738
int main(int argc, const char * argv[])
{
int i = 17;
printf("i stores its value at %p\n", &i);
printf("this function starts at %p\n", main); return 0;
}
// output => i stores its value at 0xbffff738
// this function starts at 0x100000ed0
I tried using the "&" symbol in front of main, and I get the same result- 0x100000ed0. But when I remove the ampersand from in front of "i", I see only 0x11 instead of 0xbffff738.
Question- why the difference? And why does one work with or without an ampersand, while the other seems to require it in order to produce the expected output?
An expression of function type (including a function name) is implicitly converted to a pointer to the function in most contexts. The exceptions are when it's the argument to a unary sizeof or & operator. sizeof function_name is illegal, but in &function_name the subexpression function_name is not converted to a pointer; the & operator then yields the function's address.
So given that foo is the name of a function, these expressions:
foo
&foo
*foo
**foo
***foo
...
all yield the address of the function.
There are similar rules for array expressions, which are usually converted to the address of the array's first element. There's one additional exception (a string literal used in an initializer for an array object), and &array_name is valid (it yields the address of the array object, which refers to the same address but has a different type than the address of the first element).
Incidentally, the %p format expects an argument of type void*. On many systems, all pointers have the same representation, so you can probably get away with passing any pointer value -- but there's no guarantee that it will work. For maximum safety and portability, you should print a pointer value by casting it to void*:
printf("i stores its value at %p\n", (void*)&i);
And there is no standard format for printing a function pointer value. This:
printf("this function starts at %p\n", (void*)main);
is likely to work, but strictly speaking the behavior of the conversion from int (*)(int, char **) (the type of the address of main) to void* is undefined. See this question for more information.
For 100% portability, you can extract the representation of a function pointer by treating it as an array of unsigned char, but it's probably not necessary.
i is not a pointer type but an integer type. You need the & operator to get its address.
main is a function designator and in an expression is converted to a pointer to a function in the usual conversion rules.
printf("this function starts at %p\n", &main); // OK, & yields a pointer to main
printf("this function starts at %p\n", main); // OK also, usual conversion rules
// yields a pointer to main
Note that the printf call is technically undefined behavior as p conversion specifier requires an argument of type void *.
In C, like array names which are converted to pointers to array's first element when passed to a function, function names are converted to the pointer to that function. In case of
printf("i stores its value at %p\n", (void *)&i);
i is not a pointer type and hence you need to pass a pointer type argument and this would be done by placing & before i in the argument.
in C, function name is handled specially. you can see three of these give the same output:
main
*main
&main
http://ideone.com/jMz0W4
unlike data identifiers, which have type tree system, function identifiers have no.

C pointer to pointer

Does
int **p
and
int *p[1]
mean the same thing? as both can be passed to functions allowing the change the pointer object, also both can be accessed via p[0], *p ?
Update, thanks for your help, tough Memory management seems different. does the access mechanism remain the same
*eg: p[0] becomes *(p+0) & *p (both pointing to something)
Thanks
Not quite.
int **p;
declares a pointer p, which will be used to point at objects of type int *, ie, pointers to int. It doesn't allocate any storage, or point p at anything in particular yet.
int *p[1];
declares an array p of one pointer to int: p's type can decay to int ** when it's passed around, but unlike the first statement, p here has an initial value and some storage is set aside.
Re. the edited question on access syntax: yes, *p == p[0] == *(p+0) for all pointers and arrays.
Re. the comment asking about sizeof: it deals properly with arrays where it can see the declaration, so it gives the total storage size.
void foo()
{
int **ptr;
int *array[10];
sizeof(ptr); // just the size of the pointer
sizeof(array); // 10 * sizeof(int *)
// popular idiom for getting count of elements in array:
sizeof(array)/sizeof(array[0]);
}
// this would always discard the array size,
// because the argument always decays to a pointer
size_t my_sizeof(int *p) { return sizeof(p); }
To simplify things, you could factor out one level of pointers since it's not relevant to the question.
The question then becomes: what's the difference between T* t and T t[1], where T is some type.
There are several differences, but the most obvious one has to do with memory management: the latter allocates memory for a single value of type T, whereas the the former does not (but it does allocate memory for the pointer).
They are not the same thing, although in many cases they can appear to behave the same way.
To make the discussion below flow better, I'm going to take the liberty of renaming your variables:
int **pp; // pointer to pointer
int *ap[1]; // array of pointer
If an expression of type "N-element array of T" appears in most contexts, it will be converted to an expression of type "pointer to T" whose value is the address of the first element in the array (the exceptions to this rule are when the array expression is an operand of either the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration).
So, suppose you write something like
foo(ap);
The expression ap has type "1-element array of pointer to int", but by the rule above it will be converted to an expression of type "pointer to pointer to int"; thus, the function foo will receive an argument of type int **, not int *[1].
On the other side of the equation, subscripting is defined in terms of pointer arithmetic: E1[E2] is defined as *(E1 + E2) where one of the expressions is a pointer value and the other is an integral value. Thus you can use a subscript operator on pp as though it were an array. This is why we can treat dynamically-allocated buffers as though they were regular arrays:
pp = malloc(sizeof *pp * N); // allocate N pointers to int (type of *pp == int *)
if (pp)
{
size_t i;
for (i = 0; i < N; i++)
pp[i] = ...; // set pp[i] to point to some int value
}
Now for some major differences. First of all, array expressions may not be the target of an assignment; for example, you can't write something like
ap = some_new_pointer_value();
As mentioned above, array expressions will not be converted to pointer types if they are the operands of either the sizeof or unary & operators. Thus, sizeof ap tells you the number of bytes required to store a 1-element array of type int *, not a pointer to a pointer to int. Similarly, the expression &ap has type int *(*)[1] (pointer to 1-element array of pointer to int), rather than int *** (which would be the case for &pp).
No, they are not the same.
int **p is a pointer to a pointer to int.
int *p[1] is an array (of length 1) of pointers to int.
They are not same:
int **p
Is a pointer which points to another pointer whose type is int *
while,
int *p[1];
Is an array of size 1 to the type int *
They are different.
int **p
means a pointer to a pointer to an int.
int *p[1]
means an array containing one element, with that element being a pointer to an int.
The second form can be treated the same as the first in some situations, e.g. by passing it to a function.

Why can't I assign an array to pointer directly in C?

I have the following program. However, I can't understand why I have to pass the address of the array. When they are both pointing to the same address. Which is the address of the first element of the array of int's.
I get a warning when I try and do this "assignment from incompatible pointer type":
ptr = var;
Complete source code:
void print_values(int (*ptr)[5])
{
size_t i = 0;
for(i = 0; i < 5; i++) {
printf("%d: [ %d ]\n", i, (*ptr)[i]);
}
}
int main(void)
{
/* declare a pointer to an array integers */
int (*ptr)[5] = NULL;
/* array of integers */
int var[] = {1, 2, 3, 4, 5};
/* assign the address of where the array is pointing to (first element) */
ptr = &var;
/* Both are pointing to the exact same address */
printf("var [ %p ]\n",(void*)var);
printf("&var [ %p ]\n", (void*)&var);
print_values(ptr);
return 0;
}
I compile the code with gcc 4.4.4 c89 -Wall -Wextra -O0
It's purely a type issue.
In most expression contexts the name of an array (such as var) decays to a pointer to the initial element of the array, not a pointer to the array. [Note that this doesn't imply that var is a pointer - it very much is not a pointer - it just behaves like a pointer to the first element of the array in most expressions.]
This means that in an expression var normally decays to a pointer to an int, not a pointer to an array of int.
As the operand of the address-of operator (&) is one context where this decay rule doesn't apply (the other one being as operand of the sizeof operator). In this case the type of &var is derived directly from the type of var so the type is pointer to array of 5 int.
Yes, the pointers have the same address value (the address of an arrays first element is the address of the array itself), but they have different types (int* vs int(*)[5]) so aren't compatible in the assignment.
ISO/IEC 9899:1999 6.3.2.1/4:
Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression of type "pointer to type" that points to the initial element of the array object and is not an lvalue. ...
var itself is a (*int) pointing to the first element in your array. Pointers and arrays in C extremely similar. Change int (*ptr)[5] = NULL; to int* ptr = NULL; and ptr = &var; to ptr = var;
C is a strongly typed language. When a function expects a parameter of type int *, you have to pass an argument of type int *. Not double *, not char *, but int *. Even if the actual numerical address in those double * or char * is "the same" as the one you want to pass, it still doesn't change anything - you still have to pass an int *. The language prohibits you from passing the value of wrong type.
This is exactly what happens in your case. The function takes a parameter of type int (*)[5]. That means that you have to pass the argument of that type. Passing an int * instead is not allowed. Whether the address is the same makes no difference.
From what I can tell you are assigning an array pointer (var) to a pointer that points to an array pointer ((*ptr)[5]), so that's why you get that warning.
Instead, try using
int *ptr = NULL;

Resources