Passing NULL for array parameter in C/C++ - c++

void DoSomeThing(CHAR parm[])
{
}
int main()
{
DoSomeThing(NULL);
}
Is the passing NULL for array parameter allowed in C/C++?

What you cannot do is pass an array by value. The signature of the function
void f( char array[] );
is transformed into:
void f( char *array );
and you can always pass NULL as argument to a function taking a pointer.
You can however pass an array by reference in C++, and in that case you will not be able to pass a NULL pointer (or any other pointer):
void g( char (&array)[ 10 ] );
Note that the size of the array is part of the type, and thus part of the signature, which means that g will only accept lvalue-expressions of type array of 10 characters

Short answer is yes, you can pass NULL in this instance (at least for C, and I think the same is true for C++).
There are two reasons for this. First, in the context of a function parameter declaration, the declarations T a[] and T a[N] are synonymous with T *a; IOW, despite the array notation, a is declared as a pointer to T, rather than an array of T. From the C language standard:
6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
The second reason is that when an expression of array type appears in most contexts (such as in a function call), the type of that expression is implicitly converted ("decays") to a pointer type, so what actually gets passed to the function is a pointer value, not an array:
6.3.2.1 Lvalues, arrays, and function designators
...
3 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 with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.

First off, what you're passing to the function is a pointer and not an array. The array notation used for the parm parameter is just syntactic sugar for CHAR *parm.
So yes, you can pass a NULL pointer.

The only issue would be if DoSomeThing were overloaded, in which case the compiler might not be able to distinguish which function to call. But casting to the appropriate type would theoretically fix that.

Related

What's the use of multiple asterisks in the function call?

I can't think of any practical use of multiple asterisks in the function call:
void foo(int a, char b)
{
}
int main(void)
{
(**************foo)(45, 'c');
//or with pointer to function:
void (*ptr)(int, char) = foo;
(******ptr)(32, 'a');
}
Why is this thing allowed both in C and C++?
One of the standard conversions, in both C and C++, is the function-to-pointer conversion; when a function name appears in an expression, it can be converted into a pointer to that function. So:
foo is equivalent to &foo
*foo is equivalent to *(&foo), or foo
**foo is eqivalent to **(&foo), or *foo, or foo
and so on.
This means that you can legally add as many * as you like before a function name without changing its meaning. There's no reason to do that, though.
Why is this thing allowed both in C and C++?
I can't speak for C++, but for C at least a function designator is converted to a pointer:
6.3.2.1 - 4
A function designator is an expression that has function type. Except
when it is the operand of the sizeof operator or the unary & operator,
a function designator with type ‘‘function returning type’’ is
converted to an expression that has type ‘‘pointer to function
returning type’’.
Applying the indirection operator yields a function designator:
6.5.3.2 - 3
The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator
So no matter how many times you apply the indirection operator you'll get the same thing: a function designator that's immediately converted to a pointer.
In my opinion there's little or no use in doing this.
Because the * operator expects an address value. And whenever a value is expected (as opposed to an object or function glvalue), the lvalue to rvalue, function to pointer and array to pointer conversions are applied on an operand. So the dereferenced function immediately again converts to a pointer when again dereferenced.
These all either read values from objects or produce a pointer value that refers to the beginning of an array or function respectively.
These rows of dereferences have no purpose other than for the lulz of it.
The way i understand it is
* is a pointer to a memory address
& is the value at the Memory address
*foo means pointer to foo memory address
**foo means *(*foo) *(foo memory address) This is a different value from *foo
it continues like that...

C/C++ int[] vs int* (pointers vs. array notation). What is the difference?

I know that arrays in C are just pointers to sequentially stored data. But what differences imply the difference in notation [] and *. I mean in ALL possible usage context.
For example:
char c[] = "test";
if you provide this instruction in a function body it will allocate the string on a stack while
char* c = "test";
will point to a data (readonly) segment.
Can you list all the differences between these two notations in ALL usage contexts to form a clear general view.
According to the C99 standard:
An array type describes a contiguously allocated nonempty set of
objects with a particular member object type, called the element
type.
Array types are characterized by their element type and by
the number of elements in the array. An array type is said to be
derived from its element type, and if its element type is T, the array
type is sometimes called array of T. The construction of an array
type from an element type is called array type derivation.
A pointer type may be derived from a function type, an object type, or
an incomplete type, called the referenced type. A pointer type
describes an object whose value provides a reference to an entity of
the referenced type. A pointer type derived from the referenced type T
is sometimes referred to as a pointer to T. The construction of a pointer
type from a referenced type is called pointer type derivation.
According to the standard declarations…
char s[] = "abc", t[3] = "abc";
char s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
…are identical. The contents of the arrays are modifiable. On the other hand, the declaration…
const char *p = "abc";
…defines p with the type as pointer to constant char and initializes it to point to an object with type constant array of char (in C++) with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.
According to 6.3.2.1 Array subscripting dereferencing and array subscripting are identical:
The definition of the subscript operator [] is that E1[E2] is
identical to (*((E1)+(E2))).
The differences of arrays vs. pointers are:
pointer has no information of the memory size behind it (there is no portable way to get it)
an array of incomplete type cannot be constructed
a pointer type may be derived from a an incomplete type
a pointer can define a recursive structure (this one is the consequence of the previous two)
More helpful information on the subject can be found at http://www.cplusplus.com/forum/articles/9/
char c[] = "test";
This will create an array containing the string test so you can modify/change any character, say
c[2] = 'p';
but,
char * c = "test"
It is a string literal -- it's a const char.
So doing any modification to this string literal gives us segfault. So
c[2] = 'p';
is illegal now and gives us segfault.
char [] denotes the type "array of unknown bound of char", while char * denotes the type "pointer to char". As you've observed, when a definition of a variable of type "array of unknown bound of char" is initialised with a string literal, the type is converted to "array[N] of char" where N is the appropriate size. The same applies in general to initialisation from array aggregate:
int arr[] = { 0, 1, 2 };
arr is converted to type "array[3] of int".
In a user-defined type definition (struct, class or union), array-of-unknown-bound types are prohibited in C++, although in some versions of C they are allowed as the last member of a struct, where they can be used to access allocated memory past the end of the struct; this usage is called "flexible arrays".
Recursive type construction is another difference; one can construct pointers to and arrays of char * (e.g. char **, char (*)[10]) but this is illegal for arrays of unknown bound; one cannot write char []* or char [][10] (although char (*)[] and char [10][] are fine).
Finally, cv-qualification operates differently; given typedef char *ptr_to_char and typedef char array_of_unknown_bound_of_char[], cv-qualifiying the pointer version will behave as expected, while cv-qualifying the array version will migrate the cv-qualification to the element type: that is, const array_of_unknown_bound_of_char is equivalent to const char [] and not the fictional char (const) []. This means that in a function definition, where array-to-pointer decay operates on the arguments prior to constructing the prototype,
void foo (int const a[]) {
a = 0;
}
is legal; there is no way to make the array-of-unknown-bound parameter non-modifiable.
The whole lot becomes clear if you know that declaring a pointer variable does not create the type of variable, it points at. It creates a pointer variable.
So, in practice, if you need a string then you need to specify an array of characters and a pointer can be used later on.
Actually arrays are equivalent to constant pointers.
Also, char c[] allocates memory for the array, whose base address is c itself. No separate memory is allocated for storing that address.
Writing char *c allocates memory for the string whose base address is stored in c. Also, a separate memory location is used to store c.

when does a array act as a pointer in c?

i know that the array name could be used as a pointer(although it's a converted form), but my question is , Is there some other instance where array acts as a pointer.
Technically speaking, an array name never acts as a pointer. An
expression with array type (which could be an array name) will convert
to a pointer anytime an array type is not legal, but a pointer type is.
And the declaration of an array as a function parameter is converted
into a declaration of a pointer. (Which means that the name isn't an
array name, but a pointer name. Despite appearances.)
It is due to array-to-pointer standard conversion. Specifically, array decays into a pointer to the first element of the array.
Array decays into a pointer, I think, because arrays and pointers are used exactly in the same way: using an index, which you can increment and decrement, to traverse the elements, in both direction, forward and backward..
Here are the relevant sections of the C language standard (you asked for C, that's what you get):
6.3.2.1 Lvalues, arrays, and function designators
...
3 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 with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue. If the array object has register storage class, the
behavior is undefined.
...
6.5.2.1 Array subscripting
Constraints
1 One of the expressions shall have type ‘‘pointer to object type’’, the other expression shall
have integer type, and the result has type ‘‘type’’.
Semantics
2 A postfix expression followed by an expression in square brackets [] is a subscripted
designation of an element of an array object. The definition of the subscript operator []
is that E1[E2] is identical to (*((E1)+(E2))). Because of the conversion rules that
apply to the binary + operator, if E1 is an array object (equivalently, a pointer to the
initial element of an array object) and E2 is an integer, E1[E2] designates the E2-th
element of E1 (counting from zero).
...
6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression
The important thing to take away from this is that there is a difference between an object (in the C sense, something that takes up memory) and the expression we use to refer to that object. Arrays are always arrays, but the expression used to refer to that object will often be of a pointer type.
The identifier itself tells the base address of the memory block.
int arr[SIZE];
arr
+------+------+---- ----+------+
| | | . . . | |
+------+------+---- ----+------+
arr[0] arr[1] arr[2] arr[n-1] arr[n]
The `arr' holds the address of the base address of the block
int *arr = malloc (sizeof (int) * SIZE);
arr
+------+
|addr1 |------------+
+------+ |
addr_of_arr |
|
|
V
+------+------+---- ----+------+
| | | . . . | |
+------+------+---- ----+------+
addr1[0] addr[1] addr1[n-1] addr1[n]
Arrays in C are basically just pointers that reserve consecutive blocks of memory. So in essence arrays always act like pointers.

Is array name a constant pointer in C++?

I have a question about the array name a
int a[10]
How is the array name defined in C++? A constant pointer? It is defined like this or just we can look it like this? What operations can be applied on the name?
The C++ standard defines what an array is and its behaviour. Take a look in the index. It's not a pointer, const or otherwise, and it's not anything else, it's an array.
To see a difference:
int a[10];
int *const b = a;
std::cout << sizeof(a); // prints "40" on my machine.
std::cout << sizeof(b); // prints "4" on my machine.
Clearly a and b are not the same type, since they have different sizes.
In most contexts, an array name "decays" to a pointer to its own first element. You can think of this as an automatic conversion. The result is an rvalue, meaning that it's "just" a pointer value, and can't be assigned to, similar to when a function name decays to a function pointer. Doesn't mean it's "const" as such, but it's not assignable.
So an array "is" a pointer much like a function "is" a function pointer, or a long "is" an int. That is to say, it isn't really, but you can use it as one in most contexts thanks to the conversion.
An array name is not a constant pointer - however it acts like one in so many contexts (it converts to one on sight pretty much) that for most purposes it is.
From 6.3.2.1/3 "Other operands/Lvalues, arrays,and function designators":
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 with type "pointer to type" that points to the initial element of the array object and is not an lvalue.

c++: function arg char** is not the same as char*[]

I am using g++. I am using code that had a main(int,char**), renamed so I can call it. I looked at Should I use char** argv or char* argv[] in C?, where char** is said to be equivalent to char* []. This does not appear to be true in c++ function calls. For example:
void f1(char** p){;}
void f2(char* p[]){
f1(p);
//...`
}
fails with the compiler complaining "cannot convert char (*)[] to char**..." The references I look to say that arrays are converted to pointers for the call, but this does not seem to be the case as:
void f3(char* [] p);
char caa[16][16];
f3(caa);
also fails. I had assumed that as long as the levels of indirection were the same (e.g. char*** ptr and char[][][] carray ) the types were interchangeable.
Can someone provide a reference I can review that clarifies these issues?
Thanks.
This still holds true in C++. If your compiler complains as you describe for your first case, it is non-conformant.
To explain your second case, it is important to understand what actually happens. An expression of array type is implicitly convertible to a corresponding pointer type, i.e.: T[n] -> T*. However, if T itself is an array, this case isn't treated specially, and array-to-pointer decay does not propagate. So T*[n] decays to T**, but T[x][y] will only decay to T[y]*, and no further.
From implementation perspective this makes sense, because decaying further, if allowed, would give T**, which is pointer to pointer; whereas 2D C arrays aren't implemented as jagged arrays (i.e. array of pointers to arrays) - they form a single contiguous memory block. So, there's no T* "inside" the array to take an address of to give you a T**. For the allowed cases, a typical implementation simply takes the address of the array as a whole and converts it to type of pointer to single element (when underlying pointer representation is the same for all types, as is usually the case, this convertion is a no-op at run time).
The normative reference here is ISO C++03, 4.2[conv.array]/1:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to an rvalue of type “pointer to T.” The result is a pointer to the first element of the array.
void f2(char* p[]){
the compiler complaining "cannot convert char (*)[] to char**..."
Strange. char(*)[] is a pointer to array of chars, but in your code snippet the function has char *p[] argument, what means array of pointers to char! These types are indeed different (because array elements have different sizes), let alone your code snippet perfectly compiles. You really have misspelled something.
Sherlock Holmes mode: or is there a typedef involved? ;-)
void f1(char** p){;}
typedef char type[];
void f2(type * p){
f1(p);
}
This really doesn't compile and yields the error you referred to.