what are the initial values of pointers in "array of pointers"? - c

Before putting my question, I want to quote "Expert C Programming" [Page :276, last paragraph]:
"The beauty of Illiffe vector data structre is that it allows arbitrary arrays of pointers to strings to be passed to functions, but only arrays of pointers, and only pointers to strings.
This is because both strings and pointers have the convention of an explicit out-of-bound value(NUL and NULL, respectively) that can be used as an end marker."
So, What I understood from above text is that if there is an array of pointers they have explicit out-of-bound value like NULL.( Correct me , if I'm wrong...)
So, it left me wondering what are the default values of an array of pointers(thinking that an array of pointers would have last pointer as NULL). Tried below code-snippets and result was very different.
int *x[2];
printf("%p %p",x[0],x[1]);
Output is: (nil) 0x400410
int *x[3];
printf("%p %p %p",x[0],x[1],x[2]);
Output is: 0xf0b2ff 0x400680 (nil)
int *x[4];
printf("%p %p %p %p", x[0],x[1],x[2],x[3]);
Output is: (nil) 0x4003db 0x7fffe48e4776 0x4006c5
So, with the above outputs , it is clear that there is an explicit Out-of-Bound (nil) value assigned to one of the pointers(one pointer is NIL), but is it truly the end-marker? No.
Is it one of those "Implementation defined" things of C-language?
I'm using a GCC compiler(4.6.3) on a Ubuntu machine.

Is it one of those "Implementation defined" things of C-language?
No, that's not implementation-defined - it's plain "undefined". The same is true for arrays of all types: the values that you see in them are undefined until explicitly initialized.
What I understood from above text is that if there is an array of pointers they have explicit out-of-bound value like NULL.
The author wanted to say that there is a value (specifically, NULL value) that can be used to mark a "no value" in an array of pointer. The author did not mean to imply that such a no-value marker would be placed into an array of pointers by default.

An array, or any object, with automatic storage duration (i.e., any object defined within a function body without the static keyword) has no default initial value unless you specify one. Its initial value is garbage, and you must not access that value before assigning something to it.
An object with static storage duration (i.e., any object defined outside any function and/or with the static keyword) is initialized to zero, with the meaning of "zero" (0 for integers, 0.0 for floating-point, null for pointers) applied recursively to subobjects.
You can use an initializer to ensure that a pointer object is set to a null pointer, or to whatever value you like:
int *x[2] = { NULL, NULL };
or, more simply:
int *x[2] = { 0 }; /* sets first element to 0, which is converted to a null
pointer; other elements are implicitly set to null
pointers as well */

You are misreading the quotation from "Expert C Programming." The key phrase there is the following:
This is because both strings and pointers have the *convention* of an explicit
out-of-bound value (NUL and NULL, respectively).
It is possible and even conventional to have an array of strings such that the last pointer is set to NULL. This can allow one to iterate over the array quite easily without knowing exactly how many elements there are in the array:
char* dwarves[] = { "Dopey",
"Grumpy",
"Sleepy",
"Happy",
"Sneezy",
"Bashful",
"Doc",
NULL
};
But you have to explicitly set the last pointer to NULL. Such structures are useful because they allow elegant code. So if you want to print or otherwise manipulate the array, you don't need to worry about how many strings are in it, as the NULL pointer will signal the end:
for (char** pWalk = dwarves; *pWalk; pWalk++)
printf ("%s\n", *pWalk);
The beauty of this particular type of ragged-array structure is that strings by definition have a built-in NUL terminator, and the array of pointers is terminated with the NULL, so the endpoints of both dimensions are known. However, the NULL as the last pointer in the array is not something that's built into the language. It has to be explicitly set. Failing to do so would be the equivalent of declaring an array of char but not terminating it with a NUL:
char myString[] = { 'H', 'e', 'l', 'l', 'o' } // No NUL termination
Just as you would have to know how many characters there are in this array if you want to manipulate it in any useful way, without the NULL at the end of the array of pointers, manipulating it would be more difficult.
That's really all that Peter van der Linden is saying in the paragraph you quoted about Illiffe data structures.

There is no requirement in C that any local variable should have any 'default' value. So, when the compiler reserves two (or three) memory locations, the initial value is whatever that these memory locations contained before - there will not be any default initialization.

Unless your array was declared at file scope (outside of any function) or with the static keyword, the array contents will not be initialized; each element will contain some random bit pattern that may or may not correspond to a valid address.
If your array was declared at file scope or with the static keyword, then each element would be implicitly initialized to NULL. Note that attempting to dereference a NULL pointer results in undefined behavior, so you will want to check that your pointer isn't NULL before doing something with it.
A null pointer represents a well-defined "nowhere", guaranteed to compare unequal to any valid memory address. Note that there is a null pointer constant1 and a null pointer value2, and the two are not necessarily the same. In your source code, the macro NULL is set to the null pointer constant. During translation, each occurence of NULL in your source code is replaced with the real null pointer value.
There are invalid pointer values other than NULL; it's just that NULL is well-defined and works the same everywhere.
1. Any 0-valued integral expression, as used in a pointer context. Could be a naked 0, or (void *) 0, or something else that evaluates to 0.
2. Value used by the platform to represent a null pointer, which does not have to be 0.

Related

Difference between array of pointers and pointer to array?

char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
//I want to know differences between string1Ptr(pointer to array mentioned in question) and string(array of pointers mentioned in question). I only typed string1 here to give string1Ptr an address to strings
Besides the fact that string can point to strings of any size and string1Ptr can only point to strings of size 4 only(otherwise pointer arithmetic would go wrong), I don't see any differences between them.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for assuming string and string1Ptr are almost similar besides for the difference I stated above)
So what are the differences between string and string1Ptr? Any reason to use one over the other?
PS: I'm a newbie so please go easy on me.
Also, I did check C pointer to array/array of pointers disambiguation, it didn't seem to answer my question.
char string1[3][4]={"koo","kid","kav"}; //This is a 2D array
char * string[3]={"koo","kid","kav"}; //This is an array of 3 pointers pointing to 1D array as strings are stored as arrays in memory
char (*string1Ptr)[4]=string1; //This is a pointer to a 1D array of 4 characters
Besides the fact that string can point to strings of any size and
string1Ptr can only point to strings of size 4 only(otherwise
pointer arithmetic would go wrong), I don't any differences between
them.
They are absolutely, fundamentally different, but C goes to some trouble to hide the distinction from you.
string is an array. It identifies a block of contiguous memory wherein its elements are stored. Those elements happen to be of type char * in this example, but that's a relatively minor detail. One can draw an analogy here to a house containing several rooms -- the rooms are physically part of and exist inside the physical boundaries of the house. I can decorate the rooms however I want, but they always remain the rooms of that house.
string1Ptr is a pointer. It identifies a chunk of memory whose contents describe how to access another, different chunk of memory wherein an array of 4 chars resides. In our real estate analogy, this is like a piece of paper on which is written "42 C Street, master bedroom". Using that information, you can find the room and redecorate it as you like, just as in the other case. But you can also replace the paper with a locator for a different room, maybe in a different house, or with random text, or you can even burn the whole envelope, without any of that affecting the room on C Street.
string1, for its part, is an array of arrays. It identifies a block of contiguous memory where its elements are stored. Each of those elements is itself an array of 4 chars, which, incidentally, happens to be just the type of object to which string1Ptr can point.
For example,
printf("%s\n", string1[2]); // All print the same thing, ie, the word "kav"
printf("%s\n", string1Ptr[2]);
printf("%s\n", string[2]);
They all seem to perform the same pointer arithmetic.(My reason for
assuming string and string1Ptr are almost similar besides for the
difference I stated above)
... and that is where C hiding the distinction comes in. One of the essential things to understand about C arrays is that in nearly all expressions,* values of array type are silently and automatically converted to pointers [to the array's first element]. This is sometimes called pointer "decay". The indexing operator is thus an operator on pointers, not on arrays, and indeed it does have similar behavior in your three examples. In fact, the pointer type to which string1 decays is the same as the type of string1Ptr, which is why the initialization you present for the latter is permitted.
But you should understand that the logical sequence of operations is not the same in those three cases. First, consider
printf("%s\n", string1Ptr[2]);
Here, string1Ptr is a pointer, to which the indexing operator is directly applicable. The result is equivalent to *(string1Ptr + 2), which has type char[4]. As a value of array type, that is converted to a pointer to the first element (resulting in a char *).
Now consider
printf("%s\n", string1[2]);
string1 is an array, so first it is converted to a pointer to its first element, resulting in a value of type char(*)[4]. This is the same type as string1Ptr1, and evaluation proceeds accordingly, as described above.
But this one is a bit more different:
printf("%s\n", string[2]);
Here, string is a pointer, so the indexing operation applies directly to it. The result is equivalent to *(string + 2), which has type char *. No automatic conversions are performed.
Any reason to use one over the other?
Many, in both directions, depending on your particular needs at the time. Generally speaking, pointers are more flexible, especially in that they are required for working with dynamically allocated memory. But they suffer from the issues that
a pointer may be in scope, but not point to anything, and
declaring a pointer does not create anything for it to point to. Also,
even if a pointer points to something at one time during an execution of the program, and its value is not subsequently written by the program, it can nevertheless stop pointing to anything. (This most often is a result of the pointer outliving the object to which it points.)
Additionally, it can be be both an advantage and a disadvantage that
a pointer can freely be assigned to point to a new object, any number of times during its lifetime.
Generally speaking, arrays are easier to use for many purposes:
declaring an array allocates space for all its elements. You may optionally specify initial values for them at the point of declaration, or in some (but not all) cases avail yourself of default initialization.
the identifier of an array is valid and refers to the array wherever it is in scope.
Optionally, if an initializer is provided then an array declaration can use it to automatically determine the array dimension(s).
* But only nearly all. There are a few exceptions, with the most important being the operand of a sizeof operator.
The difference between string1 and string is the same as the difference between:
char s1[4] = "foo";
char *s2 = "foo";
s1 is a writable array of 4 characters, s2 is a pointer to a string literal, which is not writable. See Why do I get a segmentation fault when writing to a string initialized with "char *s" but not "char s[]"?.
So in your example, it's OK to do string1[0][0] = 'f'; to change string1[0] to "foo", but string[0][0] = 'f'; causes undefined behavior.
Also, since string is an array of pointers, you can reassign those pointers, e.g. string[0] = "abc";. You can't assign to string1[0] because the elements are arrays, not pointers, just as you can't reassign s1.
The reason that string1Ptr works is because the string1 is a 2D array of char, which is guaranteed to be contiguous. string1Ptr is a pointer to an array of 4 characters, and when you index it you increment by that number of characters, which gets you to the next row of the string1 array.

C when should char** be null terminated?

Couldn't find any questions on StackOverflow that addresses this question.
I realize that char* arrays don't have to be NULL terminated, but was wondering when you would want it to be?
For example, when debugging my code, I use a lot of printf() to see if my variable is correct at certain stage of the code.
I have an char** values that holds 4 char*, I made the last char* NULL.
With NULL terminating, printfs from values[0] to values[3] give me this
note: names is just another array that I print right after I finish printing the values array
Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
Testing values1[3]: (null)
Testing names2[0]: PATH
Testing names2[1]: IDIR
Testing names2[2]: LIBDIR
I have an char** with 3 char*, all of which are valid char*.
Without NULL terminating, printf from values[0] to values[3] gives me this (names doesn't show)
Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
I think when printf(...., values[3]) would be an undefined behavior, such as printing a garbage value, but as shown in the output above, everything including and after printf(...., values[3]) seems to not have been executed.
There's a lot of confusion here. First of all:
NULL refers to a null pointer constant which you only use for setting a pointer to point at "nothing", an invalid memory location.
Null termination, sometimes spelled "nul" to not confuse it with the above, means putting a zero character '\0' (sometimes called "nul character") at the end of a character array to state where your string ends. It has nothing to do with NULL pointers what so ever. A better name than "null termination" might be zero termination, as that is less confusing.
Now as it happens, 0, NULL and '\0' all give the value zero, so they could in practice be used for the wrong purpose and the code will still work. What you should do, however, is this:
Use 0 for integers.
Use NULL for pointers.
Use '\0' to terminate a characer array and thereby making it a C string.
Next matter of confusion:
I have an char** values that holds 4 char*
Pointers do not hold values. Arrays hold values. Pointers are not arrays, arrays are not pointers. Pointer-to-pointer is not an array, nor is it a 2D array.
Though in some circumstances, you can get a pointer to the first element from an array.
An array of pointers to strings of variable length can be declared as: char* string_array [N];. You could iterate through this array by using a pointer-to-pointer, but that's not a good idea. A better idea is to use array indexing: string_array[i].
Overall, there exists very few cases where you actually need to use a pointer-to-pointer. Returning a pointer to an allocated resource through a function parameter is the normal use for them. If you find yourself using pointer-to-pointers elsewhere, it is almost a certain indication of bad program design.
For example, one particular case of very wide-spread but 100% incorrect use of pointer-to-pointer is when allocating 2D arrays dynamically on the heap.
when should char** be null terminated?
Never. That doesn't make any sense, as explained above. Your should most likely not use char** to begin with.
You could however end a character pointer array with NULL, to indicate the end of the array. This is common practice, but don't confuse this with zero termination of strings.
Example:
const char* str_array [] =
{
"hello",
"world",
NULL
};
for(size_t i = 0; str_array[i] != NULL; i++)
{
puts(str_array[i]);
}
I got an answer from my TA, as a response to "when should char** be null terminated?" which I find reasonable. It would be cool if there are other reasons to why you would do this.
"This is a good conceptual question, and you can think of it as analogous to why C strings are null-terminated.
Suppose you didn't want to explicitly store the length of an array (because it's extra data for you to manage and pass around, etc). How would you know where the array ends? The NULL at the end acts as a sentinel value so you can simply iterate over it until you reach the magic end-of-array value.
If you have a fixed array size or are storing it in some other way, the NULL end isn't necessary."
Each string needs to be null terminated. Easy option would be to memset the full array with null (i.e. 0 or '\0').
Alternatively, if you don't want to null terminate, then you need to keep track of the length of the string.
As per C11, chapter §7.21.6.1, fprintf(), %s conversion specifier
s If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type.
So, you may not pass a NULL as the argument. It invokes undefined behavior. You cannot predict the behaviour of UB.
What you can do is, put a check on the argument to be != NULL and then, pass the variable. Something like
if (values[n])
puts(values[n]);
In C99 (& POSIX), the only array of char* which is required to be NULL terminated is the argv second argument to main. Hence your main function is (or should be) declared as
int main(int argc, char**argv);
and (at least on POSIX systems) it is required (and enforced by the runtime crt0) and you should expect that:
argc is positive
argv is an array of argc+1 pointers, each of them being a C string (so ending with a \0 byte)
its last element argv[argc] is required to be the NULL pointer
two different pointers in argv (i.e. argv[i] and argv[j] with both i and j being non-negative and less than argc+1) are not pointer aliases (that is the same pointer value)
Of course, some libraries may also have functions whose argument might have similar requirements. That should be documented.

Differences between arrays, pointers and strings in C

Just have a question in mind that troubles me.
I know pointers and arrays are different in C because pointers store an address while arrays store 'real' values.
But I'm getting confused when it comes to string.
char *string = "String";
I read that this line does several things :
An array of chars is created by the compiler and it has the value String.
Then, this array is considered as a pointer and the program assigns to the pointer string a pointer which points to the first element of the array created by the compiler.
This means, arrays are considered as pointers.
So, is this conclusion true or false and why ?
If false, what are then the differences between pointers and arrays ?
Thanks.
A pointer contains the address of an object (or is a null pointer that doesn't point to any object). A pointer has a specific type that indicates the type of object it can point to.
An array is a contiguous ordered sequence of elements; each element is an object, and all the elements of an array are of the same type.
A string is defined as "a contiguous sequence of characters terminated by and including the first null character". C has no string type. A string is a data layout, not a data type.
The relationship between arrays and pointers can be confusing. The best explanation I know of is given by section 6 of the comp.lang.c FAQ. The most important thing to remember is that arrays are not pointers.
Arrays are in a sense "second-class citizens" in C and C++. They cannot be assigned, passed as function arguments, or compared for equality. Code that manipulates arrays usually does so using pointers to the individual elements of the arrays, with some explicit mechanism to specify how long the array is.
A major source of confusion is the fact that an expression of array type (such as the name of an array object) is implicitly converted to a pointer value in most contexts. The converted pointer points to the initial (zeroth) element of the array. This conversion does not happen if the array is either:
The operand of sizeof (sizeof array_object yields the size of the array, not the size of a pointer);
The operand of unary & (&array_object yields the address of the array object as a whole); or
A string literal in an initializer used to initialize an array object.
char *string = "String";
To avoid confusion, I'm going to make a few changes in your example:
const char *ptr = "hello";
The string literal "hello" creates an anonymous object of type char[6] (in C) or const char[6] (in C++), containing the characters { 'h', 'e', 'l', 'l', 'o', '\0' }.
Evaluation of that expression, in this context, yields a pointer to the initial character of that array. This is a pointer value; there is no implicitly created pointer object. That pointer value is used to initialize the pointer object ptr.
At no time is an array "treated as" a pointer. An array expression is converted to a pointer type.
Another source of confusion is that function parameters that appear to be of array type are actually of pointer type; the type is adjusted at compile time. For example, this:
void func(char param[10]);
really means:
void func(char *param);
The 10 is silently ignored. So you can write something like this:
void print_string(char s[]) {
printf("The string is \"%s\"\n", s);
}
// ...
print_string("hello");
This looks like just manipulating arrays, but in fact the array "hello" is converted to a pointer, and that pointer is what's passed to the print_string function.
So, is this conclusion true or false and why ?
Your conclusion is false.
Arrays and pointers are different. comp.lang.c FAQ list · Question 6.8 explains the difference between arrays and pointers:
An array is a single, preallocated chunk of contiguous elements (all of the same type), fixed in size and location. A pointer is a reference to any data element (of a particular type) anywhere. A pointer must be assigned to point to space allocated elsewhere, but it can be reassigned (and the space, if derived from malloc, can be resized) at any time. A pointer can point to an array, and can simulate (along with malloc) a dynamically allocated array, but a pointer is a much more general data structure.
When you do
char *string = "String";
and when a C compiler encounters this, it sets aside 7 bytes of memory for the string literal String. Then set the pointer string to point to the starting location of the allocated memory.
When you declare
char string[] = "String";
and when a C compiler encounters this, it sets aside 7 bytes of memory for the string literal String. Then gives the name of that memory location, i.e. the first byte, string.
So,
In first case string is a pointer variable and in second case it is an array name.
The characters stored in first case can't be modified while in array version it can be modified.
This means arrays is not considered as pointers in C but they are closely related in the sense that pointer arithmetic and array indexing are equivalent in C, pointers and arrays are different.
You have to understand what is happening in memory here.
A string is a contiguous block of memory cells that terminates with a special value (a null terminator). If you know the start of this block of memory, and you know where it ends (either by being told the number of memory cells or by reading them until you get to the null) then you're good to go.
A pointer is nothing more than the start of the memory block, its the address of the first memory cell, or its a pointer to the first element. All those terms mean the same thing. Its like a cell reference in a spreadsheet, if you have a huge grid you can tell a particular cell by its X-Y co-ordinates, so cell B5 tells you of a particular cell. In computer terms (rather than spreadsheets) memory is really a very, very long list of cells, a 1-dimensional spreadsheet if you like, and the cell reference will look like 0x12345678 rather than B5.
The last bit is understanding that a computer program is a block of data that is loader by the OS into memory, the compiler will have figured out the location of the string relative to the start of the program, so you automatically know which block of memory it is located in.
This is exactly the same as allocating a block of memory on the heap (its just another part of the huge memory space) or the stack (again, a chunk of memory reserved for local allocations). You have the address of the first memory location where your string lives.
So
char* mystring = "string";
char mystring[7];
copy_some_memory(mystring, "string", 7);
and
char* mystring = new char(7);
copy_some_memory(mystring, "string", 7);
are all the same thing. mystring is the memory location of the first byte, that contains the value 's'. The language may make them look different, but that's just syntax. So an array is a pointer, its just that the language makes it look different, and you can operate on it with slightly different syntax designed to make operations on it safer.
(note: the big difference between the 1st and other examples is that the compiler-set set of data is read-only. If you could change that string data, you could change your program code, as it too it just a block of CPU instructions stored in a section of memory reserved for program data. For security reasons, these special blocks of memory are restricted to you).
Here's another way to look at them:
First, memory is some place you can store data.
Second, an address is the location of some memory. The memory referred to by the address may or may not exist. You can't put anything in an address, only at an address - you can only store data in the memory the address refers to.
An array is contiguous location in memory - it's a series of memory locations of a specific type. It exists, and can have real data put into it. Like any actual location in memory, it has an address.
A pointer contains an address. That address can come from anywhere.
A string is a NUL-terminated array of characters.
Look at it this way:
memory - A house. You can put things in it. The house has an address.
array - A row of houses, one next to the other, all the same.
pointer - a piece of paper you can write an address on. You can't store anything in the piece of paper itself (other than an address), but you can put things into the house at the address you write on the paper.
We can create an array with the name 'string'
char string[] = "Hello";
We can allocate a pointer to that string
char* stringPtr = string;
The array name is converted to a pointer
So, an array name is similar to the pointer. However, they're not the same, as the array is a contiguous block of memory, whereas the pointer references just a single location (address) in memory.
char *string = "String";
This declaration creates the array and sets the address of the pointer to the block of memory used to store the array.
This means, arrays are considered as pointers. So, is this conclusion true or false
False, arrays are not pointers. However, just to confuse(!), pointers can appear to be arrays, due to the dereference operator []
char *string = "String";
char letter = string[2];
In this case string[2], string is first converted to a pointer to the first character of the array and using pointer arithmetic, the relevant item is returned.
Then, this array is considered as a pointer and the program assigns to the pointer string a pointer which points to the first element of the array created by the compiler.
Not really great wording here. Array is still an array and is considered as such. The program assigns a pointer-to-first-element value (rvalue) to pointer-to-char variable (lvalue in general). That is the only intermediate/non-stored pointer value here, as compiler and linker know array's address at compile-link time. You can't directly access the array though, because it is anonymous literal. If you were instead initializing an array with literal, then literal would disappear (think like optimized-out as separate entity) and array would be directly accessible by its precomputed address.
char s[] = "String"; // char[7]
char *p = s;
char *p = &s[0];

Why is setting an array of characters to NULL illegal? Passing to function changes behavior

The name of an array is a synonym for the address of the first element of the array, so why can't this address be set to NULL? Is it a language rule to prevent a memory leak?
Also, when we pass an array to a function, it's behavior changes and it becomes possible to set it to NULL.
I don't understand why this occurs. I know it has something to do with pointers, but I just can't wrap my mind around it.
Example:
void some_function(char string[]);
int main()
{
char string[] = "Some string!";
some_function(string);
printf("%s\n", string);
return 0 ;
}
void some_function(char string[])
{
string = NULL;
}
Output: Some string!
I read that when an array is passed into a function, what's actually passed are pointers to each element, but wouldn't the name of the array itself still be a synonym for the address of the first element? Why is setting it to NULL here even allowed, but not in the main function?
Is it at all possible to set an array to NULL?
An array is not a pointer - the symbol string in your case has attributes of address and size whereas a pointer has only an address attribute. Because an array has an address it can be converted to or interpreted as a pointer, and the language supports this implicitly in a number of cases.
When interpreted as a pointer you should consider its type to be char* const - i.e. a constant pointer to variable data, so the address cannot be changed.
In the case of passing the array to a function, you have to understand that arrays are not first class data types in C, and that they are passed by reference (i.e. a pointer) - loosing the size information. The pointer passed to the function is not the array, but a pointer to the array - it is variable independent of the original array.
You can illustrate what is effectively happening without the added confusion of function call semantics by declaring:
char string[] = "Some string!";
char* pstring = string ;
then doing:
pstring = NULL ;
Critically, the original array data cannot just "disappear" while it is in scope (or at all if it were static), the content of the array is the variable, whereas a pointer is a variable that refers to data. A pointer implements indirection, and array does not. When an array is passed to a function, indirection occurs and a pointer to the array is passed rather than a copy of the array.
Incidentally, to pass an array (which is not a first class data type) by copy to a function, you must wrap int within a struct (structs in C are first class data types). This is largely down to the original design of C under constraints of systems with limited memory resources and the need to to maintain compatibility with early implementations and large bodies of legacy code.
So the fact that you cannot assign a pointer to an array is hardly the surprising part - because to do so makes little sense. What is surprising perhaps is the semantics of "passing an array" and the fact that an array is not a first class data type; leading perhaps to your confusion on the matter.
You can't rebind an array variable. An array is not a pointer. True, at a low level they are approximately similar, except pointers have no associated dimension / rank information.
You cant assign NULL to the actual array (same scope), but you can assign to a parameter since C treats it like a pointer.
The standard says:
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to type’’,
So in the function the NULL assignment is legal.

question regarding pointer in c language

char *sample = "String Value";
&sample is a pointer to the pointer of "String Value"
is the above statement right?
If the above statement right, what is the equivalent of &sample if my declaration is
char sample[] = "String Value"
In the first one, there are two objects being created.
One is a char * (pointer-to-char) called sample, and the other is an unnamed array of 13 chars containing the characters of the string. In this case, &sample gives the address of the object sample, which is the address of a pointer-to-char - so, a pointer-to-pointer-to-char.
In the second example, there's only one object being created; an array of 13 chars called sample, initialised with the characters of the string. In this case, &sample gives the address of the object sample - so, a pointer-to-array-of-13-chars.
In the second example, there is no "equivalent" to &sample in the first example, in the sense of a pointer-to-pointer-to-char value. This is because there is no pointer-to-char value to take the address of. There is only the array.
While pointers provide enormous power and flexibility to the programmers, they may use cause manufactures if it not properly handled. Consider the following precaustions using pointers to prevent errors. We should make sure that we know where each pointer is pointing in a program. Here are some general observations and common errors that might be useful to remember. *ptr++, *p[],(ptr).member
In the first part &sample will return the address of 'sample' pointer created and in the second case the starting address of the string created as object.
In C arrays and pointers are more or less interchangable. You can treat an array name like it is a pointer, and a pointer like it is an array name.
If you take the address of (&) of a pointer, of course you get a pointer to a pointer.
&sample is the address of the pointer that points to "String Value".
For the second example, since an array name that is not followed by a subscript is interpreted as the pointer to the initial element of the array, which means
sample
and
&sample[0]
are the same, therefore &sample is also the address of the pointer that points to the string.

Resources