Q:

Adding const keyword to an array passed as a parameter to function

Is there any way that I can add const keyword to an array passed as a parameter to function:
void foo(char arr_arg[])

If I place const before char (void foo(const char arr_arg[])) or after char(void foo(char const arr_arg[])), that would mean than it's char which is constant, not the arr_arg.
I have just read that under the hood an array sent as a parameter to function is represented as a pointer, so void foo(char arr_arg[]) is the same as void foo(char* ptr_arg).
Taking it into account, I may rewrite the function as void foo(char * const ptr_arg) for it to be exactly what I want to achieve.
But I want to know if there is a way to add const keyword in this declaration void foo(char arr_arg[]) for it to be the same as void foo(char * const ptr_arg) (and not void foo(char const * ptr_arg) or void foo(const char * ptr_arg))?
I just want to understand if there is a syntax to make arr_arg constant with array notation [].

A:

In C you have to put const between the [], however strange that might look to an unprepared person
void foo(char arr_arg[const]);

This is "new" C99-specific syntax. In C89/90 or C++ there no way to do it with "array" syntax, so you have to switch to the equivalent "pointer" syntax, as suggested in David's answer.

A:

The first thing is that in your particular signature, the argument is transformed by the compiler into a pointer, so what you have is:
void foo( char * arg );

Now, there are two entities that can be made const in that signature: the pointer and the pointed type. To make the pointed type can be made const in two different yet equivalent ways [*]:
void foo( const char * arg );
void foo( char const * arg );

The pointer could be made const with the syntax:
void foo( char * const arg );

But note that in a function signature, in the same way that char arg[] is transformed into a pointer char *arg, the top level qualifier is discarded. So from the point of view of the declaration, these two are equivalent:
void foo( char * const arg );
void foo( char *       arg );

In the definition, the top level const can be use to instruct the compiler that the argument pointer (by value) should not be changed within the function, and it will detect if you attempt to reset the pointer to a different location. But, if only the pointer is const, then the compiler will gladly let you modify the pointed memory. If you don't want the function to change the contents of the array, then you should opt for one of the first two signatures.
[*] I tend to prefer the char const * format, as it provides a consistent way of reading types: from right to left it reads: a non-const pointer to a const char. Additionally it is simpler to reason about typedef-ed types (by performing direct substitution in the expression). Given typedef char* char_p;, const char_p and char_p const are both equivalent to char * const and different from const char *. By consistently using const on the right you can just blindly substitute the typedef and read the type without having to reason.

