2

Please read the comments in the program below :

#include<stdio.h>
void test(char c[])
{
    c=c+2; //why does this work ?
    c--;
    printf("%c",*c);
}
int main()
{
    char ch[5]={'p','o','u','r'};
    //ch = ch+2;  //this is definitely not allowed on array names as they are not pointers
    test(ch);

    return 0;
}

OUTPUT
o
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Naveen
  • 7,944
  • 12
  • 78
  • 165
  • 2
    `c` is a pointer, `ch` is not. – Nikos C. May 25 '19 at 14:15
  • Not exactly a duplicate, but I recommend checking out: [Why do arrays in C decay to pointers?](https://stackoverflow.com/questions/33291624/why-do-arrays-in-c-decay-to-pointers) – 3limin4t0r May 25 '19 at 14:27

4 Answers4

0

You should keep in mind that the name of the array "decays" to a pointer to its first element. This means that test(ch); is equivalent to test(&ch[0]);.

Also, void test(char c[]) is nothing but void test(char* c), a pointer to a character. Pointers can be incremented or decremented which is why c = c + 2 and c-- compiles just fine.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
0

When an array is passed as function argument (among other cases), it decays to a pointer to the first element, and the function parameter which receives it is local to the function scope.

Quoting C11, chapter §6.3.2.1

Except when it is the operand of the sizeof operator, the _Alignof 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. [...]

So, in your case, inside void test(char c[]) function call, c is just another pointer, which points to the first element of the array. Normal pointer arithmetic can be performed on that pointer.

In other words,

 void test(char c[]) { //....

is same as

 void test(char *c) { //....

So, you case is something similar to

int main(void)  //correcting the definition
{
    char ch[5]={'p','o','u','r'};
    //ch = ch+2;  //this is definitely not allowed on array names as they are not pointers

    char *c = &ch[0];   // this is what happens when you pass the array as function argument.
    c = c + 2;   // see, this is possible.

    test(ch);

    return 0;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

Array designators are immutable lvalues. That is you may not change an array designator such a way that ir would define another array.

Consider array designators as named memory extents.

As for your example then this function declaration

void test(char c[]);

is adjusted by the compiler the following way

void test(char *c);

that is a parameter having an array type is adjusted by the compiler to pointer. Thus for example these function declarations

void test(char c[100]);
void test(char c[10]);
void test(char c[1]);
void test(char c[]);

are equivalent and declare this one function

void test(char *c);

You nay include all these declarations in your program though they will be redundant.

For example

#include <stdio.h>

void test(char c[100]);
void test(char c[10]);
void test(char c[1]);
void test(char c[]);
void test( char *c)
{
    c=c+2; 
    c--;
    printf("%c",*c);
}

int main( void )
{
    char ch[5]={'p','o','u','r'};
    test(ch);
}

To make it evident consider the following program

#include <stdio.h>

void test( char c[] )
{
    printf( "sizeof( c ) = %zu\n", sizeof( c ) );
}

int main( void )
{
    char ch[5]={'p','o','u','r'};
    test( ch );
    printf( "sizeof( ch ) = %zu\n", sizeof( ch ) );
}

Its output is

sizeof( c ) = 8
sizeof( ch ) = 5

That is within the function sizeof( c ) is equal to the size of a pointer (in used system it is equal to 8). While in main sizeof( ch ) is the size of the array.

When you pass an array to such a function then the array designator is implicitly converted to pointer to its first element. So these calls

test( ch );
test( &ch[0] );

are equivalent.

This means that within the function you deal with a pointer and you can change the value of the pointer using the pointer arithmetic.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • The terminology in this answer is muddled. The C standard uses “designator” only for function designators and for the things that designate which parts of an aggregate to initialize (in `struct foo x = { .bar = 3 };`, `.bar` is a designator). Lvalues are said to designate objects, but lvalues may be computed, not immutable. E.g., if `x` is a pointer to an array, `*x` is an array (and `sizeof *x` would give the size of that array), but `*x` can take on different values at different times. And arrays do not need to be named; an array can be created via `malloc`. – Eric Postpischil May 25 '19 at 14:43
  • @EricPostpischil English is not my native language so it is difficult to me to select a more appropriate word. – Vlad from Moscow May 25 '19 at 14:45
-1

In declarations of function parameters, an array declaration is automatically adjusted to be a pointer declaration, per C 2018 6.7.6.3 7:

A declaration of a parameter as “array of type” shall be adjusted to “qualified pointer to type”,…

Thus void test(char c[]) is effectively void test(char *c).

In main, ch is an array, because it was declared with char ch[5]…, which is a normal declaration that is not adjusted. In test, c is a pointer.

When main calls test with test(ch), the argument ch is an expression. In an expression, an array is automatically converted to a pointer in most cases because C 2018 6.3.2 3 says:

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…

Thus, when an array is passed to a function with a parameter declared as an array, the array is converted to a pointer and is passed for a parameter that was adjusted to be a pointer.

Note that only an outer array is adjusted. If the function parameter declaration is int x[3][4], it is adjusted to be int (*x)[4], a pointer to an array of 4 int. Only the array that is the parameter (the array of 3 arrays of 4 int above) is adjusted; other types within its composition are not adjusted.

Aside

The C standard is not entirely clear about the effects of the adjustment. Using Apple LLVM 10.0.1 with clang-1001.0.46.4, the following program prints “Hello, world.”:

#include <stdio.h>

static void foo(int a[printf("Hello, world.\n")]) {}

int main(void) { foo(0); }

This shows the array declaration was not completely adjusted to be a pointer declaration, as the expression specifying the array size was retained but would not be present in a pointer declaration.

Community
  • 1
  • 1
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • If it's any help, GCC 9.1.0 also compiles the code and prints `Hello, World.` when run. With minor massaging to test `a` before printing `a[0]`, it compiles under very stringent options, even with `-pedantic`. – Jonathan Leffler May 25 '19 at 20:16