1

I have written below program.

#include<windows.h>
#include <stdio.h>
#include<tchar.h>

#define MAX_ARG 5 
#define MAX_COMMAND_LINE 10 

int _tmain(int argc, LPTSTR argv[]){

BOOL exitFlag = FALSE;
TCHAR command[MAX_COMMAND_LINE], *pc;
DWORD i, localArgc;
TCHAR argstr[MAX_ARG][MAX_COMMAND_LINE] = {"abcdef", "Dravid", "sachin", "ganguli" };

char name[10] = "Happy";

// Why argstr == argstr[0]
printf("%p   %p \n", name,  name[0] );      // name != name[0]  
printf("%p  %p = %p\n", argstr, argstr[0], *argstr);


// Why there is no difference if it increase left or right variable value? 
TCHAR *place = malloc(10 * sizeof(TCHAR *));
place = argstr[0];
printf("%c  %c \n", *++place, *place ); // Incremented the left parameter
printf("%c  %c \n", *place, *++place ); // Incremented the right parameter

return 0;
}

1) Why argstr == argstr[0] ?

2) In printf, from which side(right/left) the calculation happens?

samanta
  • 35
  • 1
  • 8
  • Very similar question: http://stackoverflow.com/questions/2528318/how-come-an-arrays-address-is-equal-to-its-value-in-c – M.M Sep 03 '16 at 14:15

4 Answers4

2

Taking non-standard TCHAR out of the question for the sake of clarity, if argstr is declared as

char argstr[MAX_ARG][MAX_COMMAND_LINE] = {"abcdef", "Dravid", "sachin", "ganguli" };

then its type can be expressed in English as "array of MAX_ARG arrays of MAX_COMMAND_LINE char". On the other hand, the type of argstr[0] is "array of MAX_COMMAND_LINE char". These two objects do not even have compatible types, so they cannot be equal.

The code you present in fact does not test their equality, as far as I can see. That is, it nowhere attempts to evaluate argstr == argstr[0]. If it did, and if the compiler were at all worth using, then it would at least warn about the type mismatch between the operands. It might, however, still accept the code, and at runtime the comparison might evaluate to true. Why is that?

In the first place, you need to appreciate that in almost all C contexts, an expression that evaluates to an array decays to a pointer to the first element of the array. In particular, because argstr and argstr[0] both designate arrays, the expression argstr == argstr[0] is equivalent to &argstr[0] == &argstr[0][0].

Furthermore, C requires the first element of an array to have the same address as the array itself -- that is, an array cannot contain any padding before its first element. Therefore, the address of argstr[0][0] is the same as the address of argstr[0]. That's why if the compiler accepts argstr == argstr[0] despite the mismatched types, it might well evaluate to true.

What you actually appear to test is how printf() prints the two pointers. You again have a type problem here, because printf()'s %p field descriptor requires the corresponding argument to have type void *, and your actual corresponding arguments have different (pointer) types. Formally, your code has undefined behavior for that reason, but on the many implementations where all object pointers have the same representation, it is likely to produce the same result as this correct version:

printf("%p  %p = %p\n", (void *) argstr, (void *) argstr[0], (void *) *argstr);

And that is highly likely, albeit not guaranteed, to format each pointer identically, because, again, they all represent the same address.

Community
  • 1
  • 1
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
1

1) Why argstr == argstr[0] ?

argstr is a multi-dimensional array. argstr[0] is still an array hence an address, and since argstr data starts by argstr[0], the addresses in memory are the same.

2) In printf, from which side(right/left) the calculation happens?

You don't want to know. What you are doing is really dangerous and not portable. Just don't.

PS: in:

printf("%p   %p \n", name,  name[0] );

%p does not apply to name[0] which is a char, not a pointer. printf converts the value of the character to an invalid value of a pointer. Not really interesting :)

On the other hand, that below would yield the same value:

printf("%p   %p \n", name,  &name[0] );
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Thanks. But am still confused! Suppose argstr = 0x1111. Then argstr[0] = argstr + (sizeof(void *) * 0) = argstr. This I know. But am thining *argstr => The content inside(0x1111). Right? So how can The content and address can be same.!! I can't draw any picture here, otherwise I would have drew my doubt perfectly. am sorry. – samanta Sep 01 '16 at 16:20
  • 1
    argstr is not an array of pointers. It is a matrix. The first "row" has the same address as the address of the matrix. – Jean-François Fabre Sep 01 '16 at 17:25
1

First, based on your declaration, argstr is laid out in memory as follows:

        +---+
argstr: |'a'| argstr[0][0]
        +---+ 
        |'b'| argstr[0][1]
        +---+
        |'c'| argstr[0][2]
        +---+
         ...
        +---+
        |'f'| argstr[0][5]
        +---+
        | 0 | argstr[0][6]
        +---+
         ...
        +---+
        | ? | argstr[0][9]
        +---+
        |'D'| argstr[1][0]
        +---+
        |'r'| argstr[1][1]
        +---+
         ...
        +---+
        | ? | argstr[1][9]
        +---+
        |'s'| argstr[2][0]
        +---+
         ...
        +---+
        | ? | argstr[4][9]
        +---+

All 50 array elements are laid out sequentially in row-major order (that is, all of the elements of the first row, followed by all elements of the second row, etc.). Note that no storage has been set aside for any pointers anywhere. This means that the address of the first element of the first subarray (&argstr[0][0]) is the same as the address of the first element of the array (&argstr[0]) which is the same as the address of the array (&argstr).

Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.

In your printf call, the expression argstr has type "5-element array of 10-element array of TCHAR". Since it's not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to 10-element array of TCHAR", or TCHAR (*)[10], and the value of the expression is the address of the first element (&argstr[0]).

In the same call, the expression argstr[0] has type "10-element array of TCHAR". Since it's not the operand of the sizeof or unary & operators, it is converted to an expression of type "pointer to TCHAR", or TCHAR *, and the value of the expression is the address of the first element (&argstr[0][0]).

What the hell? Why does the type of an array expression change into a pointer?

The array subscript operator [] is defined in terms of pointer arithmetic: the expression a[i] is defined as *(a + i). Given an address a, offset i elements (not bytes) from that address and dereference the result. This is a carryover from the B programming language from which C was derived. In B, a separate pointer was created as part of an array definition; that pointer would be bound to the array name and point to the first element of the array, so in B &argstr and &argstr[0] would indeed be different.

Ritchie got rid of that array pointer when he designed C, but he wanted to keep B's array semantics, so he created the array conversion rule above. In an expression like argstr[i][j], the subexpression argstr is first converted to a pointer value, which is subscripted with [i]; that gives us another array expression, which is converted to a new pointer expression, which is subscripted with [j].

Summing up, given the declaration TCHAR argstr[5][10], all of the following are true:

    Expression        Type              Decays to        Value
    ----------        ----              ---------        -----
        argstr        TCHAR [5][10]     TCHAR (*)[10]    Address of argstr[0]
       &argstr        TCHAR (*)[5][10]  n/a              Address of argstr
       *argstr        TCHAR [10]        TCHAR *          Value of argstr[0]
     argstr[i]        TCHAR [10]        TCHAR *          Address of argstr[i][0]
    &argstr[i]        TCHAR (*)[10]     n/a              Address of argstr[i]
    *argstr[i]        TCHAR             n/a              Value of argstr[i][0]
  argstr[i][j]        TCHAR             n/a              Value of argstr[i][j]
 &argstr[i][j]        TCHAR *           n/a              Address of argstr[i][j]

argstr, &argstr, *argstr, argstr[0], &argstr[0], and &argstr[0][0] all yield the same value (the address of the first element of the array), but the types of the expressions are different.

John Bode
  • 119,563
  • 19
  • 122
  • 198
-2

Because arrays are implemented in C by memory allocation using pointers internally. Say a 2D int array int a[5][4];. A pointer is used to indicate the first address of the allocated memory block for array a.It is accessible through a or a[0],so argstr and argstr[0] points to same block.so argstr == argstr[0]. As lowest addressable memory unit is byte, so a or a[0] points to first byte of the whole allocated block which is (1byte * sizeof(datatype)) in practice because 4 byte to represent an integer. Say the address of a is = 1000000, so a holds 1000000. In a, 5*5*sizeof(int) is the size of allocated memory block where:

  • a[0][0] or a points to first block in first row, size is 4 byte(sizeof(int))
  • a[0][1] or *(a[0]+1) or *(a+1) points to second block in first row , size is 4 byte(sizeof(int))
  • a[1][0] or *(a + 1*5 + 0) points to first block in second row , size is 4 byte
  • and so on... ... ...

As you will notice, array is allocated sequentially, so to find a row we need to multiply the total row numbers with current row number to get a[1][0].

Tavij
  • 98
  • 7