Reputation: 95
I've been learning C for about 2 months, still a novice:(
I know there are other similar questions on this site. I've read them, but still couldn't really understand, so here I am. Below is my code:
//naming my structure as ball
typedef struct ball_room {
int enter;
int exit;
} ball;
//I've omitted some irrelevant details for brevity
int i, n, max;
scanf("%d", &n);
ball person[n];
.../*assign values to ball.enter and ball.exit with user input*/
max = 1;
for (i = 0; i < n; i++)
if (ball_room(person, person[i].enter, n) > max)
max = ball_room(person, person[i].enter, n);
printf("%d\n", max);
return 0;
}
and below is my function receiving the array:
//This function returns the number of people in the ballroom
//when b[j](person[j] in "main") enters
int ball_room(ball *b, int i, int n)
{
int people = 0, j;
for (j = 0; j < n; j++)
if (b[j].enter <= i && b[j].exit > i)
people++;
return people;
}
my question is that why is it b[j].enter
instead of b[j]->enter
, which my compiler wouldn't accept?
In my limited experience, when manipulating structure itself (the object), I use .
to go inside the structure, and when it's a pointer (the address), I use ->
(hope this is correct.)
And in this case, I pass the array to function using ball *b
, which represent the address of person[0]
, so I can access the whole array. But shouldn't ball *b
be in the form of a pointer and therefore I should use ->
to access its content? It's just an address that I pass to the function.
This is my first time doing something with an array of structures, please help me get this clear, thank you!
Upvotes: 1
Views: 2582
Reputation: 25536
For explanation of the current issue, see Eric's answer; in some of the answers given so far there is dangerous wording applied, so just to make clear: When do we have an array and when a pointer???
Consider the following:
int a[7];
As long as we can refer to a
directly, we still have an array and can use any operations that are valid on, e. g. getting size:
size_t n = sizeof(a); // size in bytes, not ints, i. e. 7*sizeof(int)
You can pass arrays to functions or even do pointer arithmetics on:
f(a);
a + 1;
In both cases, the array "decays" to a pointer, though, and the result is a pointer as well. Be aware that you can assign new values to a pointer, but not to an array itself (you can assign new values to the array's elements, directly or via pointer), so you cannot do things like ++a
either.
When an array decays to a pointer, it gets a pointer to its first element:
int* ptr = a;
int* ptr = &*a; // only pointers can be dereferenced -> a decays!
int* ptr = &a[0]; // short for &*(a + 0)...
All result in exactly the same; however, the following is invalid:
int* ptr = &a;
Taking the address of an entire array actually is possible, but the resulting pointer is not of type "pointer to element" nor of type "pointer to pointer to element" (int**
in the example), but of type "pointer to array of specific size". Syntax for is ugly, though, but the following would be legal again:
int(*aptr)[7] = &a;
You need to read: if I dereference ptr
, I get int[7]
...
Once decayed, there is only a pointer to the array left (more precisely: to one of the array elements, directly after decaying, to the first; array and first element always share the same address, so, although of different type, both pointers ptr
and aptr
from above hold exactly the same value). Pointers can be moved around within the array, but they do not hold as much information as the array itself, especially, the array size gets lost. This is why one needs to pass the array's length together with the pointer to functions (if needed; another variant is a sentinel value denoting the array end such as the terminating null character in strings or the null pointer following the string arguments in main
's arguments list):
int a[7];
f(a, sizeof(a)/sizeof(*a)); // division: sizeof is in bytes, dividing by size
// of first element gives number of elements
Possibly with f as:
void f(int b[], size_t n)
// ^^^^^^^ in function parameter lists, just alternative syntax for int* b !!!
// however, we can show more explicitly that we expect a pointer
// to an array this way...
{
size_t m = sizeof(b); // as b is a POINTER, gives the constant (but hardware specific!)
// size of a pointer (on typical modern 64-bit hardware 8 bytes),
// no matter what size of the array being pointed to is!!!
while(n)
{
*b++ = n--;
// ^^ advances pointer, NOT array!
}
}
Hope this helps to avoid confusion.
Upvotes: 2
Reputation: 1233
In C, the array name is a pointer to array’s first element, hence your function declaration has name ball *b
and works when you pass a ball[]
instance.
Try dynamically allocating the memory by using malloc()
and passing that pointer to your function.
Upvotes: 0
Reputation: 224311
Given ball *b
, b[j]
is an element from the elements that b
points to. Thus b[j]
is not a pointer; it is a struct. Since it is a struct, you use .
to refer to members in it.
The definition of b[j]
in the C standard is that it is *((b)+(j))
. So it takes the pointer b
, moves j
elements beyond it, and then applies *
.
Since *
is already applied in b[j]
, you do not need ->
, just .
.
Upvotes: 6
Reputation: 871
you use .
instead of ->
because of this declaration of parameters:
int ball_room(ball *b, int i, int n)
b
is expected to be pointer to data with type ball
, so you can access it in various ways:
b[5].somefield = 15
- you use dot here, because if b
is of type ball *
, it means that b
is pointer OR it is array of objects with type b
, if it's array of objects with type b
(which is your case) you use .
to access fields of object(b+5)->somefield = 15
- it will do exactly same thing as code above, but you will access data in pointer
wayUpvotes: 5
Reputation: 12362
In C/C++ an array devolves into the address of it's first member. So when you pass the array to ball_room
what actually gets passed is &ball[0]
.
Now inside ball_room
the reverse happens. b
is a pointer to ball. But here you use it as an array b[j]
. So it un-devolves back into an array of structs. So what b[j]
gives you is the struct and not a pointer to a struct. Consequently you access it using .
instead of ->
.
You can also use (b + j)->somefield
. Or for even more fun how about writing j[b].somefield
. The later being a really confusing left-over from the eraly compiler days when a[b]
truly got turned into *(a + b)
internally.
Upvotes: 2