s.j
s.j

Reputation: 21

Pointer to a struct accessed using index like an array

#include<stdio.h>

struct test{ 
    int a;
    int b;
}m;

int main()
{
    m.a=5;m.b=7; 
    struct test *p;
    p = &m;
    printf("p[0] = %d\n",*(p+0));
    printf("p[1] = %d\n",*(p+1));

    return 0;

}

I get the following Ouput:

p[0] = 5 p[1] = 0

Can someone please explain this behavior? Is there a way to print all struct members using index?

Sorry about the typo.

(Updated)

As I could print 1st element using index 0 , though the type of pointer is of "struct test type" and 1st member is an integer , I could get the correct value. Hence, the question triggered about the cause of this behavior. And if all the members can be accessed using the index just like the 1st member was accessed.

Upvotes: 1

Views: 3161

Answers (5)

CWLiu
CWLiu

Reputation: 4043

First, you have a typo in your code. Please correct it from p = &a; to p = &m;, so that the error complained by the compiler shall be removed.

Second, I guess you expect the output to be p[0] = 5 and p[1] = 7. To achieve that, modify your code from

printf("p[0] = %d\n",*(p+0));
printf("p[1] = %d\n",*(p+1));

to

printf("p[0] = %d\n",p->a);
printf("p[1] = %d\n",p->b);

can work.

Upvotes: 1

Sourav Ghosh
Sourav Ghosh

Reputation: 134286

In your code,

printf("p[0] = %d\n",*(p+0));
printf("p[0] = %d\n",*(p+1));

invokes undefined behavior as

  1. you are passing wrong type of argument for %d format specifier.
  2. You're accessing out of bound memory by saying *(p+1)

So, the output cannot be explained or justified in any way.


Now, that said, let's analyze the code a bit.

First of all,

  p = &a;

is wrong, as there is no variable called a. There is a member variable a for the structure variable m, which can be accessed as m.a. So, you can somehow write

 p = (struct test*) &m.a;

Now, using the address of the first element of the structure as the structure address is valid as there is no padding at the beginning of the structure. But that does not mean, you can apply pointer arithmetic directly on the structure pointer p and get each member variable, mainly because

  • There can be padding between two elements
  • The pointer p is of type struct test (Though you can get around by casting)

Upvotes: 3

abhiarora
abhiarora

Reputation: 10430

I compiled your code with gcc and i got.

In function ‘main’:
error: ‘a’ undeclared (first use in this function)
   p = &a;
        ^
note: each undeclared identifier is reported only once for each function it appears in
 warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
       printf("p[0] = %d\n",*(p+0));
              ^
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
    printf("p[0] = %d\n",*(p+1));

Assuming you meant p=&m, here is my explanation

printf("p[0] = %d\n",*(p+0));
printf("p[0] = %d\n",*(p+1));

First analyse whether deferring pointer like you did in printf function is correct or not.

The *(p+0) will give you the access to the struct test variabe m. As, you have assigned the address of a variable of type struct test to the pointer p, deferring pointer *p or *(p+0) will give you the access to the variable m. But the address assigned to the pointer is of a single variable not of the array of type struct test, deferring (p+1) will give you UNDEFINED BEHAVIOR. For example, *(p+1) would have worked if (not in printf statement)

struct test m[20];
struct test *p;

(*(p+0)).a=2;
(*(p+1)).a=5;

Is there a way to print all struct members using index?

You can. But there is no overloading of operators in c. So, you can achieve this by -

printf("a=%d, b=%d", p->a, p->b);

If pointer p points to array of type struct test, then you can use index in printf as

printf("a=%d, b=%d of %dth element", p[i].a, p[i].b, i);

My suggestion for your future code experimentation will be first analyse warning and error given by your code. The warnings can help to rectify most of the bugs in your code. I always compile my c/c++ code with gcc/g++ compiler and use flags like -Wall, -Wshadow, -Wextra. You can google a warning if you don't understand it.

Upvotes: 2

Anish Sharma
Anish Sharma

Reputation: 505

You are assigning the address of a to p directly. a is a member of m and so cannot be accessed directly. And as of your code, you should use an integer pointer for your arithmetic.

you need to modify a part of your code

struct test *p;
p = &a;

to

 int *p;
 p = &m.a;

now the code should work as you desire.

Upvotes: 0

Get a proper compiler. Compiled with default settings on GCC 5, the compilation spits out:

foo.c: In function ‘main’:
foo.c:12:10: error: ‘a’ undeclared (first use in this function)
     p = &a;
          ^
foo.c:12:10: note: each undeclared identifier is reported only once for each function it appears in
foo.c:13:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
     printf("p[0] = %d\n",*(p+0));
            ^
foo.c:14:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘struct test’ [-Wformat=]
     printf("p[0] = %d\n",*(p+1));
            ^

Perhaps you meant p = &m;.


After that your code invokes undefined behaviour. %d expects that the corresponding argument be an int, yet you provide a struct test. Furthermore on the latter print, the pointer is pointing to uninitialized memory after the m, and garbage is printed. Even the fact that you had 5 printed in the first case cannot be relied on. The C standard does not explain that why or why not this happens, the C standard says "at this time it is ok for the compiler to generate code that prints 42342, crash the program, or do whatever else, and it is fine by this standar d."


In C compilers the warnings usually mean "standard violations" in which case undefined behaviour is probable. A newcomer to C programming language should always consider all compiler warnings especially with default settings as being fatal errors.

Upvotes: 1

Related Questions