cpointersstructuredouble-pointer

How to Access a array in the structure after assigning the structure variable to a pointer without arrow operator


#include <stdio.h>

struct dog
{
    int name[10];
    char breed[10];
    int age;
    char color[10];
};

int main()
{
struct dog frodo;
struct dog **ptr=&frodo.name;

for(int i=0;i<10;i++)
frodo.name[i]=i;

for(int i=0;i<10;i++)
printf(" frodo.name[%d]%d\n",i,frodo.name[i]);

for(int i=0;i<10;i++)
printf(" ptr =%d\n",ptr[i]);
}

I tried using double pointer but the index is not matching when value is being printed.

O/P: frodo.name[0]0 frodo.name[1]1

ptr =0 ptr =2


Solution

  • Your question indicates that you are new to C and still learning fundamentals, so in order to help you I'll go through your code and explain what it does, and then provide that code fixed to do what I think you are trying to do. I will try to be precise and thorough at the risk of sounding pedantic.

    Consider this declaration:

    int name[10];
    

    This defines name as a field in struct dog which declares name to be the type of "an array of 10 ints". Note that an array can be assigned to a pointer to its "inner" type (int), in which assignment it is said to "decay" into a "pointer to int". So int * pint = name; is valid code which show this facility in C. None-the-less, the type of name is "array of 10 ints". This if you take it's address (&name) you don't get a "pointer to int; you get a "pointer to an array of 10 ints".

    #include <stdio.h>
    
    struct dog
    {
        int name[10];
        char breed[10];
        int age;
        char color[10];
    };
    

    So you declare a new "aggregate type", struct dog, whose objects will contain a field called name whose type is an "array of 10 ints", followed by a field called breed whose type is an "array of 10 chars", followed by a field age whose type is int, then a field color with type "array of 10 chars".

    int main()
    {
    struct dog frodo;
    

    Define an object frodo of type struct dog, which then contains all of the fields of a struct dog. It is allocated memory on the stack, which will be cleaned up and removed when main returns.

    struct dog **ptr=&frodo.name;
    

    Here is the first sign of misunderstanding. If you were to declare a variable ptr_to_dog like this: struct dog * ptr_to_dog, you would declare it as a pointer ("address of") an object whose type is struct dog, or "pointer to struct dog", for short. frodo is such an object, so setting pointer to this address of frodo is valid: ptr_to_dog = &frodo;. &frodo is an expression which takes the address of the frodo object, so the type of this expression "pointer to struct dog", which matches the type of ptr_to_dog, so the assignment is correct.

    Your declaration struct dog **ptr creates an object ptr whose type is "pointer to a pointer to a struct dog. If you take the address of ptr_to_dog, you get an expression whose type is "pointer to a pointer to struct dog. This is the same type as the ptr you declared, so if you were to make the assignment ptr = &ptr_to_dog, that is valid.

    Now let's look at the right side of the assignment, &frodo.name. Note that . is said to "bind tighter" than the &, so this is the same as &(frodo.name). The expression frodo.name gets the value of the field name in the foo object, which is of type struct dog. So the expression &frodo.name gives a pointer to that field, so its type is "pointer to the field name in the frodo object. The type of name is "array of 10 ints", so &frodo.name is "pointer to an array of 10 ints". So the declaration you gave could be described as "get the pointer to the array of 10 ints name and assign it to the "pointer to the pointer to the struct dog foo" ptr. The types are not compatible. However, all pointers can be reduced to a kind of unnamed type "pointer to memory", so the compiler can convert the "pointer to 10 ints" &frodo.name to the "pointer to the pointer to frodo" ptr. This is almost never usefull, so most compiler will emit a warning about this.

    Now you could do this struct dog * ptr_to_dog = &frodo, which assigns the address of frodo to the "pointer to a struct dog" ptr_to_dog, so here the types match and the assignment is proper. Note that a "pointer to struct dog" does not mean "pointer to a single struct dog"; so pointer could point to memory that hold an indefinite series of struct dogs in succession, ie an array. So you can do ptr_to_dog[3], which means "get the fourth struct dog from the series of struct dogs beginning at the address ptr_to_dog. If ptr_to_dog contains only one struct dog, what you get from that will be meaningless, but it is a valid expression.

    for(int i=0;i<10;i++)
    frodo.name[i]=i;
    
    for(int i=0;i<10;i++)
    printf(" frodo.name[%d]%d\n",i,frodo.name[i]);
    
    for(int i=0;i<10;i++)
    printf(" ptr =%d\n",ptr[i]);
    }
    

    Remember that the type of ptr is "pointer to a pointer to a struct dog, but given your assignment, ptr does not point to a pointer to a struct dog; it points to an "array of 10 ints" in the field name of the struct dog object frodo. So the value of ptr here is meaningless; its value is some section of the memory of the name array interpreted as a "pointer to a pointer to struct dog". From this I take it that you wanted ptr to point to the "array of 10 ints" called name in the struct dog object frodo. To get this, the declaration should have been

    int * ptr = frodo.name;
    

    Remember that an array type (name) can be assigned to a pointer to its inner type (int), in which the array expression (frodo.name) will "decay" into that type of pointer. This this says "get the array of 10 ints name inside the struct dog frodo, decay it to a pointer to the beginning of the series of ints in name and assign that pointer to the pointer to ints called ptr". A proper assignment.

    Note that @tstanisl's answer is wrong in one place; it declares ptr to be a "pointer to char". But frodo.name consists of ints not chars, so his assignment is invalid. The expression &frodo.name[0] says "get the first int in the array of 10 ints frodo.name and take its address, yielding a "pointer to the first int in frodo.name". But the address of the first int here is also the address of the series of ints in frodo.name. So the address &frodo.name and frodo.name when it is "decayed" to a pointer-to-int have the same value and type.

    Here is your code, fixed with the above in mind:

    #include <stdio.h>
    
    struct dog
    {
        int name[10];
        char breed[10];
        int age;
        char color[10];
    };
    
    int main()
    {
    struct dog frodo;
    int *ptr= frodo.name;
    
    for(int i=0;i<10;i++)
    frodo.name[i]=i;
    
    for(int i=0;i<10;i++)
    printf(" frodo.name[%d]%d\n",i,frodo.name[i]);
    
    for(int i=0;i<10;i++)
    printf(" ptr =%d\n",ptr[i]);
    }