CrownedEagle
CrownedEagle

Reputation: 125

Why ++str operation causes error if array is char *str[] but not in case of char *argv[] (one of the argument to the main function)?

I have written small piece of code to understand how to traverse through array of char pointers & 2D array of characters. I've used 1] and 2] while printing the o/p to just keep track of which block of code prints what, kindly ignore them.

The similar code for printing o/p is used for traversing through 3 different (types of) arrays:-

a) Array of Character Pointers: char *argv[]

b) Array of Character Pointers: char *str[]

c) 2D Array of Characters: char strarr[][7]

The basic operation I performed are as follows: If char *foo[] then

A) foo points 1st element (string) of foo (doubtful about this one)

B) *++foo points to 1st char of next element of foo

C) **++foo gives 1st char of next element of foo

D) ++*foo points to next char within element of foo

E) *++*foo gives next char within element of foo

The operations A, B, C & D are allowed only in case of char *argv[]. char *str[] allows only operations C & D; while 2D array char strarr[][7] doesn't allow all A-D.

I understand why operation C & D are allowed for char *str[] and not for char strarr[][7]: Since char *str[] is an array pointers and the increment of value its elements (i.e. value of address to string) is allowed while in case of char strarr[]2[7] is 2D array of element it is not possible to increment the address of its elements.

Correct me for any wrong assumptions.

But I am not able to understand why operation of **++str, *++str or ++str is not allowed whereas **++argv *++argv or ++argv is allowed?

Both argv and str are array of char pointers then why this different behavior? (str points to str[0] then why ++str causes error instead of pointing to str[1]?) Is char *argv[] is some special kind of array or operations on it performed in some other way/method?

When I write **++str, *++str or ++str the compiler gives the following error:

gcc -Wall -c "TestProg.c" (in directory: /home/crownedeagle/Downloads/CDAC C-CAT/C - K&R Solutions) TestProg.c: In function ‘main’: TestProg.c:61:33: error: lvalue required as increment operand printf("\n1]\n**++str = %c", **++str); ^

Here is the code:

//Pointer of Array and Array Pointer Experimentation

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<ctype.h>

int main(int argc, char *argv[])
{
    int i;
    if (argc == 7)
    {
        printf("\n");
        for (i = 0; i < argc; i++)
            printf("%s\t\t%p\n", argv[i], argv[i]);

        printf("\n0]\n**argv = %c", **argv);
        printf("\n*argv = %s", *argv);

        printf("\n1]\nargv = %p", argv);
        printf("\n*argv = %s", *argv);
        printf("\n**++argv = %c", **++argv);
        printf("\nargv = %p", argv);
        printf("\n*argv = %s", *argv);
        printf("\n**++argv = %c", **++argv);
        printf("\nargv = %p", argv);
        printf("\n*argv = %s", *argv);      

        printf("\n2]\nargv = %p", argv);
        printf("\n&(argv[0]) = %p", &(argv[0]));
        printf("\n*argv = %p", *argv);
        printf("\n&(**argv) = %p", &(**argv));

        printf("\n*++*argv = %c", *++*argv);
        printf("\n*argv = %s", *argv);

        printf("\nargv = %p", argv);
        printf("\n&(argv[0]) = %p", &(argv[0]));
        printf("\n*argv = %p", *argv);
        printf("\n&(**argv) = %p", &(**argv));

        printf("\nargv[0] = %s", argv[0]);

        printf("\n\n");

        for (i = 0; i < argc; i++)
            printf("%s\t\t%p\n", argv[i], argv[i]);
    }

    char *str[] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

    printf("\n");
    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", str[i], str[i]);

    printf("\n0]\n**str = %c", **str);
    printf("\n*str = %s", *str);

    //printf("\n1]\n**++str = %c", **++str);
    //printf("\n*str = %s", *str);

    printf("\n1]\nstr = %p", str);
    printf("\n&(str[0]) = %p", &(str[0]));
    printf("\n*str = %p", *str);
    printf("\n&(**str) = %p", &(**str));

    printf("\n*++*str = %c", *++*str);
    printf("\n*str = %s", *str);

    printf("\nstr = %p", str);
    printf("\n&(str[0]) = %p", &(str[0]));
    printf("\n*str = %p", *str);
    printf("\n&(**str) = %p", &(**str));

    printf("\nstr[0] = %s", str[0]);

    printf("\n\n");

    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", str[i], str[i]);

    char strarr[][7] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

    printf("\n");
    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", strarr[i], strarr[i]);

    printf("\n0]\n**strarr = %c", **strarr);
    printf("\n*strarr = %s", *strarr);

    //printf("\n1]\n**++strarr = %c", **++strarr);
    //printf("\n*strarr = %s", *strarr);

    printf("\n1]\nstrarr = %p", strarr);
    printf("\n&(strarr[0]) = %p", &(strarr[0]));
    printf("\n*strarr = %p", *strarr);
    printf("\n&(**strarr) = %p", &(**strarr));

    //printf("\n*++*strarr = %c", *++*strarr);
    printf("\n*strarr = %s", *strarr);

    printf("\nstrarr = %p", strarr);
    printf("\n&(strarr[0]) = %p", &(strarr[0]));
    printf("\n*strarr = %p", *strarr);
    printf("\n&(**strarr) = %p", &(**strarr));

    printf("\nstrarr[0] = %s", strarr[0]);

    printf("\n\n"); 

    for (i = 0; i < 5; i++)
            printf("%s\t\t%p\n", strarr[i], strarr[i]);

    return 0;   
}

The output of code is:

crownedeagle@EagleNest:~/C - K&R Solutions$ ./TestProg abcdef hijklm opqrst vwxyza 123456 789012

    ./TestProg    0x7ffd61c027c7
    abcdef        0x7ffd61c027d2
    hijklm        0x7ffd61c027d9
    opqrst        0x7ffd61c027e0
    vwxyza        0x7ffd61c027e7
    123456        0x7ffd61c027ee
    789012        0x7ffd61c027f5

    0]
    **argv = .
    *argv = ./TestProg
    1]
    argv = 0x7ffd61c01c98
    *argv = ./TestProg
    **++argv = a
    argv = 0x7ffd61c01ca0
    *argv = abcdef
    **++argv = h
    argv = 0x7ffd61c01ca8
    *argv = hijklm
    2]
    argv = 0x7ffd61c01ca8
    &(argv[0]) = 0x7ffd61c01ca8
    *argv = 0x7ffd61c027d9
    &(**argv) = 0x7ffd61c027d9
    *++*argv = i
    *argv = ijklm
    argv = 0x7ffd61c01ca8
    &(argv[0]) = 0x7ffd61c01ca8
    *argv = 0x7ffd61c027da
    &(**argv) = 0x7ffd61c027da
    argv[0] = ijklm

    ijklm         0x7ffd61c027da
    opqrst        0x7ffd61c027e0
    vwxyza        0x7ffd61c027e7
    123456        0x7ffd61c027ee
    789012        0x7ffd61c027f5
    (null)        (nil)
    XDG_VTNR=7    0x7ffd61c027fc

    ABCDEF        0x400dfa
    HIJKLM        0x400e01
    OPQRST        0x400e08
    VWXYZA        0x400e0f
    123456        0x400e16

    0]
    **str = A
    *str = ABCDEF
    1]
    str = 0x7ffd61c01b80
    &(str[0]) = 0x7ffd61c01b80
    *str = 0x400dfa
    &(**str) = 0x400dfa
    *++*str = B
    *str = BCDEF
    str = 0x7ffd61c01b80
    &(str[0]) = 0x7ffd61c01b80
    *str = 0x400dfb
    &(**str) = 0x400dfb
    str[0] = BCDEF

    BCDEF         0x400dfb
    HIJKLM        0x400e01
    OPQRST        0x400e08
    VWXYZA        0x400e0f
    123456        0x400e16

    ABCDEF        0x7ffd61c01b50
    HIJKLM        0x7ffd61c01b57
    OPQRST        0x7ffd61c01b5e
    VWXYZA        0x7ffd61c01b65
    123456        0x7ffd61c01b6c

    0]
    **strarr = A
    *strarr = ABCDEF
    1]
    strarr = 0x7ffd61c01b50
    &(strarr[0]) = 0x7ffd61c01b50
    *strarr = 0x7ffd61c01b50
    &(**strarr) = 0x7ffd61c01b50
    *strarr = ABCDEF
    strarr = 0x7ffd61c01b50
    &(strarr[0]) = 0x7ffd61c01b50
    *strarr = 0x7ffd61c01b50
    &(**strarr) = 0x7ffd61c01b50
    strarr[0] = ABCDEF

    ABCDEF        0x7ffd61c01b50
    HIJKLM        0x7ffd61c01b57
    OPQRST        0x7ffd61c01b5e
    VWXYZA        0x7ffd61c01b65
    123456        0x7ffd61c01b6c

Upvotes: 0

Views: 161

Answers (2)

user3629249
user3629249

Reputation: 16540

the order of execution of urinary operators is from right to left so:

* & + - ! ~ ++expr --expr

means the ++ is executed first then **.

regarding:

     printf("\n1]\n**++str = %c", **++str);

so, ++str results in the str[1] pointer

de-reference it once via '*' results in the string pointed to by str[1]

The second de-reference via '*' results in garbage as the string where: str[1] points is not a pointer

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

In this function declaration

int main(int argc, char *argv[])

the compiler adjusts the parameter having the array of unknown size type to pointer to the element type. That is this declaration is equivalent to

int main(int argc, char **argv )

So within the function you are dealing with a pointer and you may apply increment or assignment operators.

For example these function declarations

void f( int a[100] );
void f( int a[10] );
void f( int a[] );

declare the same one function and all the declarations are adjusted by the compiler to the declaration

void f( int *a );

From the C Standard (6.7.6.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.

In this declaration

char *str[] = {"ABCDEF", "HIJKLM", "OPQRST", "VWXYZA", "123456"};

there is declared an array of the type char * [5]. Arrays are non-modifiable lvalues. So you may not apply to arrays increment or assignment operators.

Upvotes: 3

Related Questions