3

foo is a struct with 5 scalar variables (A, B, C, D, F) and one array (E). What is confusing me is what f[0], f[1], and f[2] are in this context and what is happening here.

int     
bar(struct foo *f)
{
    f[1].C = f[0].B > f[2].C;
    f[0].E[-1] = f[0].D;
    f[0].A = f[1].C;
}

Are f[0], f[1], and f[2] individual structures with member variables? Can someone please explain? Thanks.

sampathsris
  • 21,564
  • 12
  • 71
  • 98
  • 1
    Segmentation fault? :) – someuser Jul 10 '14 at 03:37
  • Yes. `f` is a pointer to the first element of an array of `struct foo`. When addressed with an array subscript (like `[1]`, for example), the compiler computes the address of the element and dereferences it (`*(f + 1)` in the example). – rslemos Jul 10 '14 at 03:37
  • @someuser, not necessarily. – rslemos Jul 10 '14 at 03:38
  • Note that this sort of access is not good because you are never told how big the array of struct foos are, as someuser pointed out, this very easily can lead to a segfault. – James H Jul 10 '14 at 03:39
  • 1
    I never tried, in more than 15 years programming in C, to dereference a negative element in an array. Weird. – rslemos Jul 10 '14 at 03:39
  • 1
    Haha I just noticed that negative index rslemos. That funny thing is I'm pretty sure the compiler would be okay with it. I've never tried it either, now I have this urge to go give it a shot for kicks. – James H Jul 10 '14 at 03:40
  • So then, if I am understanding correctly, f[1].C would refer to the member variable C of the second structure in that array of struct foo? This is part of a function in a chapter review for a book I'm reading, not code I am using for anything. – user3822785 Jul 10 '14 at 03:41
  • Yes, user3822785, that would be correct. – James H Jul 10 '14 at 03:47
  • @JamesH exactly what I did. The compiler does exacly what we expect (`*(array - 1)`). In case of automatic variables you must guess where on the stack the compiler will allocate them. In case of structs, members are more predictable so you can access data in *previous* member that way. Weird still. – rslemos Jul 10 '14 at 03:52
  • Yes that makes sense since it is really just doing pointer math. And as you pointed out, completely useless in this scenario (and potentially hazardous in other scenarios) – James H Jul 10 '14 at 03:54
  • this is not fortran, so all offsets are positive (>=0). – user3629249 Jul 12 '14 at 02:01
  • the passed parameter is a pointer to a struct foo. The increment is always the size of the underlying type (in this case sizeof(struct foo) so f[0] is the current struct foo, f[1] is the next struct foo, etc. in C, all offsets are positive, so [-1] would be a very large offset forward. – user3629249 Jul 12 '14 at 02:05

4 Answers4

2

Are f[0], f[1], and f[2] individual structures with member variables?

Yes. f is a pointer to an array of struct foo instances f[0] is the first such member of that array, f[1] is the second member, etc. You might call it like this:

struct foo fArray[3];
// ... Initialize fArray[0], fArray[1], fArray[2] etc. ...
bar(fArray);
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
2

What you are doing is, you are passing a reference (pointer) to an array of struct foo to the function bar.

You must somewhere have a code that is similar to following:

struct foo  myFoos[10]; // an array with 10 elements of struct foo
struct foo *mallocedFoos;
// here goes some code to initialize the elements of the array
bar(&myFoos[0]);          // pass a reference to (address of/pointer to) the array

// or something like this is happening
mallocedFoos = malloc(sizeof(struct foo) * 10);
// here goes some code to initialize allocated memory
bar(mallocedFoos);        // pass the 'struct foo *' to the function

To understand the concept better, see this example.

sampathsris
  • 21,564
  • 12
  • 71
  • 98
2

Yes, in this context, f[0], f[1], etc., are elements of an array of type struct foo.

The more interesting thing to me is this line:

f[0].E[-1] = f[0].D;

I didn't realize negative indexes were allowed, but this question explains that array indexing is just pointer math, so it's an obfuscated way of saying:

f[0].D = f[0].D;

Which is basically useless as far as I know.

Also interesting:

f[0].C = f[0].B > f[2].C;

This would set f[0].C to a boolean, which is not usually compared with a > operator, so it's possible that different C members are used for different functions.

I feel that your confusion is warranted, given the strange nature of this function.

Community
  • 1
  • 1
Austin Mullins
  • 7,307
  • 2
  • 33
  • 48
  • Thanks (and to everyone else that answered). The function is part of a chapter review question about assembly notation and I actually don't think it is necessary to fully understand the function to answer the question correctly, but I wanted to make sure I understood what was happening here. Appreciate the answers everyone! – user3822785 Jul 10 '14 at 03:49
  • You're welcome, and welcome to SO! One of the best first posts I've seen. – Austin Mullins Jul 10 '14 at 03:55
  • 2
    `E[-1]` is not permitted if `E` is an array, because this attempts to access outside the bounds of `E`, causing undefined behaviour. (Recent versions of gcc -O3 might kill the entire function upon seeing this). – M.M Jul 10 '14 at 05:24
  • Just tried it with gcc 4.8.1 on Ubuntu 13.10 using `-O3`, and it worked. – Austin Mullins Jul 10 '14 at 05:36
  • I think the key is that the array is part of a struct, and not the first part, so there's a known memory allocation behind it. I don't know. I've never read standards except when they're posted on SO. – Austin Mullins Jul 10 '14 at 05:39
1

In this case f is an array of structures Similar to
struct node = { int A; //A to D and F are scalar variables int B; int C; int D; int E[10]; //E is an array of integers int F; } struct node f[10]; //f is an array of structs

For more details you can also refer How do you make an array of structs in C?

Community
  • 1
  • 1
Santosh A
  • 5,173
  • 27
  • 37