Related
This question already has an answer here:
Are "array" and "&array[0]" completely interchangeable? [duplicate]
(1 answer)
Closed 2 years ago.
#include<stdio.h>
#include<conio.h>
int main()
{
int a[3][4] = {1, 2, 3, 4, 4, 3, 2, 1, 7, 8, 9, 0};
clrscr();
printf("%u \n",a);
printf("%u, %u\n", a+1, &a+1);
getch();
return 0;
}
Output:
65502
65510
65526
How does this program work if sizeof(int)=2 and base address is 65502?
When you use an array like a in an expression, it usually goes through “pointer decay” which means that you get a pointer to the first element of the array.
So, a has type int[3][4], and it decays to int (*)[4]. When you write a+1, you get the address of a[1]… which is sizeof(*a) bytes after a, which is sizeof(int)*4, which is 8 on your system.
When you use &, pointer decay does not happen. &a is not an array (it is already a pointer), so when you write &a+1, you get the address “one past the end” of a… which is sizeof(a) bytes after a, which is sizeof(int)*12, or 24 bytes on your system.
Note that, strictly speaking, the correct way to print pointers is with %p.
printf("%p\n", a);
printf("%p, %p\n", a+1, &a+1);
(Technically, you also have to cast to char * or void * but that’s hardly ever important.)
printf("%u, %u\n", a+1, &a+1);
a+1 - Here a decays into a pointer to its first element. In this case a pointer to an array of 4 int (type int (*)[4]). Have a look at What is array to pointer decay? for more information.
Thereafter you increment this pointer by one. So, now the gained address is the one of one array element of 4 int of the 2D array forward, which matches to your output as sizeof(int) == 2 * 4 = 8. The difference between 65502 and 65510 is 8.
&a+1 - &a is first evaluated. When the & operator is applied, a doesn't decay to a pointer to its first element. Rather &a gains a pointer to the whole 2D array/ a pointer to an array of 3 arrays of 4 int (type int (*)[3][4]).
Incrementing this pointer by one gets you one the size of the whole 2D array forward which also matches to your output because the difference between 65502 65526 is 24 which is correct because sizeof(int) == 2 * (3 * 4) = 24. (3 * 4) is the amount of elements in the 2D array.
Note: Printing a pointer with the %u format specifier invokes strictly seen undefined behavior. You need the %p format specifier for pointers and need to cast the pointer argument to void * to be standard-compliant.
printf("%p\n", (void*) a);
printf("%p, %p\n", (void*) a+1, (void*) &a+1);
Correct format specifier to print pointer or address?
When you increment a pointer, it gets incremented in steps of the object size that the pointer can point to.
Type of a is int (*)[4]1) i.e. pointer to an object which is an array of 4 int type. So, the a + 1 will be a pointer obtained by adding size of array of 4 integers to pointer evaluated from a in the expression.
Type of &a is int (*)[3][4]1) i.e. pointer to an object which is a 2D array of int type with dimension 3x4. So, the &a + 1 will be a pointer obtained by adding size of 2D array of integers with dimension 3x4 to pointer evaluated from &a in the expression.
When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule).
Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0
Consider the program,
#include <stdio.h>
int main(){
int a[][4] = {2,3,4,5,
43,32,76,3
};
int *p;
int (*q)[4];
p = (int *)a;
q = a;
printf("%u\t%u", (unsigned int)p,(unsigned int)q);
printf("\n%d\t%d",*(++p),*(++q));
return 0;
}
In the above program, I have defined two pointers,
1) Integer pointer
2) Pointer to an Array
When compiled using the GCC compiler, I met with two doubts,
Question 1:
Why is that, the statement,
printf("\n%d\t%d",*(++p),*(++q));
returns an address when I try to dereference (++q)?
Question 2:
Is there any way I can use a "Pointer to an array" variable('q' - in this program) to access the consecutive element in a row?
Compiler: GCC; OS: Ubuntu
*(++q) does not "return an address". It returns a result of type int[4], which is an lvalue of array type. That lvalue refers to a[1] subarray of array a.
This means that the title of your question is no accurate at all: the dereference operator in this case does return exactly what it is supposed to return. The pointer is declared as a pointer to an array, and the dereference operator evaluates to an lvalue of array type.
However, immediately after that you use that array lvalue in a context where it decays to pointer type, just like any other array would (see What is array decaying?, Why do arrays in C decay to pointers?). Passing an array as an argument to printf happens to be such a context. So, that original array lvalue decays to a pointer. That pointer value points to the beginning of a[1], which is the same as &a[1][0]. That pointer value is passed to printf and you attempt to print it with %d.
(Note that using %d in printf to print pointer values triggers undefined behavior.)
Well, you can access them in any way you wish
q = a;
q[1][1] = 42; // accesses `a[1][1]`
++q;
(*q)[2] = 5; // accesses `a[1][2]`
This declaration
int (*q)[4];
declares a pointer to objects of type int[4]. To simplify the understanding you could introduce a typedef the following way
typedef int T[4];
T *q;
q = a;
So dereferencing the pointer you will get the pointed object of the type T that represents an array of type int[4]. As result using this object in the printf function
printf("\n%d\t%d",*(++p),*(++q));
^^^^^
you will get the second "row" (due to incrementing the pointer ++q) of the array a that is in turn a one-dimensional array of type int[4] that in turn is implicitly converted to pointer to its first element.
Thus the expression *(++q) has the type int * and points to the first element of the second "row" of the array a.
If you want to use this pointer to traverse the elements of the array a you can do it the following way
#include <stdio.h>
int main(void)
{
int a[][4] = { { 2, 3, 4, 5 }, { 43, 32, 76, 3 } };
int ( *q )[4] = a;
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
for ( size_t j = 0; j < sizeof( *q ) / sizeof( **q ); j++ )
{
printf( "%2d ", q[i][j] );
}
printf( "\n" );
}
return 0;
}
The program output is
2 3 4 5
43 32 76 3
That is q[0] is the first "row" of the array a. You can write also just *q. q[1] is the second "row" of the array a. You may can write also like *( q + 1 ). To get access to the elements of each row you can apply the subscript operator like (the first row)
q[0][i] where i is some index value. Or you can write the same like ( *q )[i]
and like (the second row) q[1][i] or ( *( q + 1 ) )[i]
And the special expression like **q yields the first element of the first row of the array a.
TL;DR answer, dereferencing a pointer-to-an array produces an array, which, once passed as a function argument, decays to pointer to the first element of the array. So, the final value is of pointer type (the former and the later are of pointer to different type, but they are pointers, nonetheless).
That said, first of all
printf("%u\t%u", (unsigned int)p,(unsigned int)q);
is implementation dependent behaviour as conversion of a pointer to an integer is implementation defined. If at all, you can cast the pointer to uintptr_t type and print using PRIuPTR format specifier to print the value.
Secondly, pointer arithmetic honors the data type. q is a pointer to an array of 4 ints. Once incremented, it points past the first array. But then, there's a mismatch in the supplied format specifier.
printf("\n%d\t%d",*(++p),*(++q));
^^ ^^^^^^
To elaborate, q is of type pointer-to-array. Dereferencing that produces an array, now once the array is passed as an argument to a function, it decays to the pointer to the first element of the array. So, essentially, you're passing a pointer as the argument to %d format specifier, which is the mismatch, leading to undefined behavior.
Finally, regarding the access to individual elements, you can either use
(*(q+m))[n] --> First dereference q to obtain the array, then use indexing
q[m][n] --> q[m] produces the array, then n is used as indexing to get individual element.
someone please explain the output of the following code..
#include <stdio.h>
int main()
{
int arr[5];
// Assume base address of arr is 2000 and size of integer is 32 bit
printf("%u %u", arr + 1, &arr + 1);
return 0;
}
also explain the out when the "printf" statement is replaced by following
1. printf("%u %u", arr + 1, &(arr + 1));
2. printf("%u %u", arr + 1, &arr + 2);
First of all it is better to use format specifier %p that is specially designed for pointers instead of format specifier %u
In this statement
printf("%u %u", arr + 1, &arr + 1);
in expression arr + 1 array arr is converted to pointer to its first element. So it has type after conversion int * and correspondingly the element it points to has type int. Due to the pointer arithmetic expression arr + 1 will point to the next element of the array that is to the second element. So the value of pointer arr+ 1is greater than the value of pointerarrbysizeof( int )`
In this expression &arr + 1 pointer &arr has type int ( * )[5] . The element it points to (that is array arr) has type int[5] . So the value of expression &arr + 1 greater than the value of &arr by sizeof( int[5] )
As for expression &(arr + 1) then it will not compile because arr + 1 is a temporary object and you may not take the address of a temporary object.
Output of 1st printf will be(According to assumption you specified) -2032 2160
as arr+1 points to next element that is arr[1] and &arr+1 in this arr is a int(*)[5] points to int[5] thus address of arr that is base address plus size of int[5] (here in your case 5*32).
In your second printf &(arr+1) is not lvalue thus does not occupy some identifiable location in memory.Thus will give an error.
Thrid printf will give output as 2032 2320.Can be evaluated as done in 1st printf.
The output of above code is 2004 2020.
The value arr and &arr yield to same result as the array is uninitialized it will print the value of address on place of its value.
This is due of the fact bcz when u print (arr+1) ,it adds the size of arraytype i.e int (4byte) to result
But when u do ( &(arr+1)) ,it will adds the size of whole array i.e (5*4=20 bytes )to base address.
When u print &(arr+1) it will produce error bcz it will now treat & as unary& not as addressing operator
Is an array's name a pointer in C?
If not, what is the difference between an array's name and a pointer variable?
An array is an array and a pointer is a pointer, but in most cases array names are converted to pointers. A term often used is that they decay to pointers.
Here is an array:
int a[7];
a contains space for seven integers, and you can put a value in one of them with an assignment, like this:
a[3] = 9;
Here is a pointer:
int *p;
p doesn't contain any spaces for integers, but it can point to a space for an integer. We can, for example, set it to point to one of the places in the array a, such as the first one:
p = &a[0];
What can be confusing is that you can also write this:
p = a;
This does not copy the contents of the array a into the pointer p (whatever that would mean). Instead, the array name a is converted to a pointer to its first element. So that assignment does the same as the previous one.
Now you can use p in a similar way to an array:
p[3] = 17;
The reason that this works is that the array dereferencing operator in C, [ ], is defined in terms of pointers. x[y] means: start with the pointer x, step y elements forward after what the pointer points to, and then take whatever is there. Using pointer arithmetic syntax, x[y] can also be written as *(x+y).
For this to work with a normal array, such as our a, the name a in a[3] must first be converted to a pointer (to the first element in a). Then we step 3 elements forward, and take whatever is there. In other words: take the element at position 3 in the array. (Which is the fourth element in the array, since the first one is numbered 0.)
So, in summary, array names in a C program are (in most cases) converted to pointers. One exception is when we use the sizeof operator on an array. If a was converted to a pointer in this context, sizeof a would give the size of a pointer and not of the actual array, which would be rather useless, so in that case a means the array itself.
When an array is used as a value, its name represents the address of the first element.
When an array is not used as a value its name represents the whole array.
int arr[7];
/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */
/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */
If an expression of array type (such as the array name) appears in a larger expression and it isn't the operand of either the & or sizeof operators, then the type of the array expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element in the array.
In short, the array name is not a pointer, but in most contexts it is treated as though it were a pointer.
Edit
Answering the question in the comment:
If I use sizeof, do i count the size of only the elements of the array? Then the array “head” also takes up space with the information about length and a pointer (and this means that it takes more space, than a normal pointer would)?
When you create an array, the only space that's allocated is the space for the elements themselves; no storage is materialized for a separate pointer or any metadata. Given
char a[10];
what you get in memory is
+---+
a: | | a[0]
+---+
| | a[1]
+---+
| | a[2]
+---+
...
+---+
| | a[9]
+---+
The expression a refers to the entire array, but there's no object a separate from the array elements themselves. Thus, sizeof a gives you the size (in bytes) of the entire array. The expression &a gives you the address of the array, which is the same as the address of the first element. The difference between &a and &a[0] is the type of the result1 - char (*)[10] in the first case and char * in the second.
Where things get weird is when you want to access individual elements - the expression a[i] is defined as the result of *(a + i) - given an address value a, offset i elements (not bytes) from that address and dereference the result.
The problem is that a isn't a pointer or an address - it's the entire array object. Thus, the rule in C that whenever the compiler sees an expression of array type (such as a, which has type char [10]) and that expression isn't the operand of the sizeof or unary & operators, the type of that expression is converted ("decays") to a pointer type (char *), and the value of the expression is the address of the first element of the array. Therefore, the expression a has the same type and value as the expression &a[0] (and by extension, the expression *a has the same type and value as the expression a[0]).
C was derived from an earlier language called B, and in B a was a separate pointer object from the array elements a[0], a[1], etc. Ritchie wanted to keep B's array semantics, but he didn't want to mess with storing the separate pointer object. So he got rid of it. Instead, the compiler will convert array expressions to pointer expressions during translation as necessary.
Remember that I said arrays don't store any metadata about their size. As soon as that array expression "decays" to a pointer, all you have is a pointer to a single element. That element may be the first of a sequence of elements, or it may be a single object. There's no way to know based on the pointer itself.
When you pass an array expression to a function, all the function receives is a pointer to the first element - it has no idea how big the array is (this is why the gets function was such a menace and was eventually removed from the library). For the function to know how many elements the array has, you must either use a sentinel value (such as the 0 terminator in C strings) or you must pass the number of elements as a separate parameter.
Which *may* affect how the address value is interpreted - depends on the machine.
An array declared like this
int a[10];
allocates memory for 10 ints. You can't modify a but you can do pointer arithmetic with a.
A pointer like this allocates memory for just the pointer p:
int *p;
It doesn't allocate any ints. You can modify it:
p = a;
and use array subscripts as you can with a:
p[2] = 5;
a[2] = 5; // same
*(p+2) = 5; // same effect
*(a+2) = 5; // same effect
The array name by itself yields a memory location, so you can treat the array name like a pointer:
int a[7];
a[0] = 1976;
a[1] = 1984;
printf("memory location of a: %p", a);
printf("value at memory location %p is %d", a, *a);
And other nifty stuff you can do to pointer (e.g. adding/substracting an offset), you can also do to an array:
printf("value at memory location %p is %d", a + 1, *(a + 1));
Language-wise, if C didn't expose the array as just some sort of "pointer"(pedantically it's just a memory location. It cannot point to arbitrary location in memory, nor can be controlled by the programmer). We always need to code this:
printf("value at memory location %p is %d", &a[1], a[1]);
I think this example sheds some light on the issue:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
int **b = &a;
printf("a == &a: %d\n", a == b);
return 0;
}
It compiles fine (with 2 warnings) in gcc 4.9.2, and prints the following:
a == &a: 1
oops :-)
So, the conclusion is no, the array is not a pointer, it is not stored in memory (not even read-only one) as a pointer, even though it looks like it is, since you can obtain its address with the & operator. But - oops - that operator does not work :-)), either way, you've been warned:
p.c: In function ‘main’:
pp.c:6:12: warning: initialization from incompatible pointer type
int **b = &a;
^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
printf("a == &a: %d\n", a == b);
C++ refuses any such attempts with errors in compile-time.
Edit:
This is what I meant to demonstrate:
#include <stdio.h>
int main()
{
int a[3] = {9, 10, 11};
void *c = a;
void *b = &a;
void *d = &c;
printf("a == &a: %d\n", a == b);
printf("c == &c: %d\n", c == d);
return 0;
}
Even though c and a "point" to the same memory, you can obtain address of the c pointer, but you cannot obtain the address of the a pointer.
The following example provides a concrete difference between an array name and a pointer. Let say that you want to represent a 1D line with some given maximum dimension, you could do it either with an array or a pointer:
typedef struct {
int length;
int line_as_array[1000];
int* line_as_pointer;
} Line;
Now let's look at the behavior of the following code:
void do_something_with_line(Line line) {
line.line_as_pointer[0] = 0;
line.line_as_array[0] = 0;
}
void main() {
Line my_line;
my_line.length = 20;
my_line.line_as_pointer = (int*) calloc(my_line.length, sizeof(int));
my_line.line_as_pointer[0] = 10;
my_line.line_as_array[0] = 10;
do_something_with_line(my_line);
printf("%d %d\n", my_line.line_as_pointer[0], my_line.line_as_array[0]);
};
This code will output:
0 10
That is because in the function call to do_something_with_line the object was copied so:
The pointer line_as_pointer still contains the same address it was pointing to
The array line_as_array was copied to a new address which does not outlive the scope of the function
So while arrays are not given by values when you directly input them to functions, when you encapsulate them in structs they are given by value (i.e. copied) which outlines here a major difference in behavior compared to the implementation using pointers.
NO. An array name is NOT a pointer. You cannot assign to or modify an array name, but you can for a pointer.
int arr[5];
int *ptr;
/* CAN assign or increment ptr */
ptr = arr;
ptr++;
/* CANNOT assign or increment arr */
arr = ptr;
arr++;
/* These assignments are also illegal */
arr = anotherarray;
arr = 0;
From K&R Book:
There is one difference between an array name and a pointer that must
be kept in mind. A pointer is a variable, but an array name is not a
variable.
sizeof is the other big difference.
sizeof(arr); /* size of the entire array */
sizeof(ptr); /* size of the memory address */
Arrays do behave like or decay into a pointer in some situations (&arr[0]). You can see other answers for more examples of this. To reiterate a few of these cases:
void func(int *arr) { }
void func2(int arr[]) { } /* same as func */
ptr = arr + 1; /* pointer arithmetic */
func(arr); /* passing to function */
Even though you cannot assign or modify the array name, of course can modify the contents of the array
arr[0] = 1;
The array name behaves like a pointer and points to the first element of the array. Example:
int a[]={1,2,3};
printf("%p\n",a); //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0
Both the print statements will give exactly same output for a machine. In my system it gave:
0x7fff6fe40bc0