0

I have a structure that I've set up, and a pointer to the structure, that is basically an array. I want to create a function that modifies specific values within the structure but can't seem to figure out how to pass in the structure pointer as a parameter.

struct deviations {
    int switch;
    int x;
    int y;
};

struct deviations *pdevs = malloc(24 * sizeof(int));

for(int i = 0; i < 8; i++) {
    (pdevs + i)->switchez = 1;
    (pdevs + i)->x = 0;
    (pdevs + i)->y = 0;
}

int top[3] = {0, 1, 2};
int bottom[3] = {5, 6, 7};
int left[3] = {0, 3 ,5};
int right[3] = {2, 4, 7};

for(int i = 0; i < 3; i++) {
   (pdevs + top[i])->y = -1; 
}

I have multiple (8) for loops like above and in each of them the basic structure is the same, except the array ("top"), lvalue ('y') and rvalue ('-1') change in each. I can't figure out how to declare a function with the structure/pointer to structure properly.

I currently have it around 26 lines of (8 for loops repeating) code and am pretty sure I can compress it down to a tidy little function if I can figure out how to pass in the pointer to the structure. Any help would be much appreciated!

This snippet is part of a larger function/program that determines whether or not to check the surrounding items (3 up top, 3 at bottom, one on each side). I have set up a structure with an on/off switch based on the position of the base item, and an x/y offset. I am trying to shift each individual cell by a certain amount +1/-1/ or 0 in the x or y position. And I am trying to flip the switch on or off depending on certain conditions about the x or y of the original cell. Malloc is probably unnecessary, but am unsure whether or not this array of structs will be used again later, if not, I will remove the call to malloc.

Thanks!

Ali Z
  • 47
  • 6
  • 1
    You should use `sizeof(struct deviations)` in the `malloc()` call. – Barmar Oct 25 '18 at 02:34
  • the sizeof declaration you suggested is definitely the way to go, thanks! – Ali Z Oct 25 '18 at 02:37
  • Oops... Clicked wrong key and edited another comment. You should use `pdevs[top[i]]->y` instead. And also I suggest you use a macro. – Hoblovski Oct 25 '18 at 02:37
  • It'd be good if you hadn't omitted the code that actually demonstrates what you're trying to do. Instead you tried to describe code in words, which is just confusing. – paddy Oct 25 '18 at 02:37
  • And it would be easier to understand if you wrote `pdevs[top[i]].y = -1` – Barmar Oct 25 '18 at 02:37
  • Also, if you had to set _multiple_ items in the `struct`, you could do (e.g.): `for (int i = 0; i < 3; ++i) { struct deviations *pdev = &pdevs[top[i]]; pdev->y = -1; pdev->x = -1; pdev->switch = 0; }` – Craig Estey Oct 25 '18 at 02:42
  • @paddy edited and added everything except the repeat for loops that I'm looking for direction on. Will keep that in mind moving forward. thanks – Ali Z Oct 25 '18 at 02:43
  • except in `for` loop i don't see closing braces `}` anywhere – asio_guy Oct 25 '18 at 02:44
  • Well, again you omitted code so we can't determine the _intent_ of your program. It _looks_ like you're trying to set up a static-sized array of neighbors and their X/Y offset, _e.g._ top-left == (-1,-1), right == (1,0) etc... Why you need loops or dynamic allocation for this is puzzling. – paddy Oct 25 '18 at 02:45
  • @u__ It's on the same line as the assignment -- just poor formatting. – Barmar Oct 25 '18 at 02:46
  • couldn't resist - I went ahead and formatted the `code` a bit – asio_guy Oct 25 '18 at 02:50
  • @paddy included more context. not sure if that's enough of what you're looking for. – Ali Z Oct 25 '18 at 02:57
  • thanx @u__ still getting used to this! – Ali Z Oct 25 '18 at 03:14
  • Note that `struct deviations *pdevs = malloc(24 * sizeof(int));` is not the correct way to allocate an array of 8 structures. You need `struct deviations *pdevs = malloc(8 * sizeof(struct deviations));` i.e. the size of the struct is NOT always 3 times the size of the size of int. There is sometimes padding involved. – Rishikesh Raje Oct 25 '18 at 04:03

2 Answers2

1

So you want a generic function that can take an array of 3 indexes, the structure member to fill in, and the value.

The array and value are simple. To handle a structure member generically, you can use the offsetof() macro.

void fill_structs(struct deviations *pdevs, size_t offset, int indexes[3], int value) {
    for (int i = 0; i < 3; i++) {
        *((int *)((char *)&pdevs[indexes[i]] + offset)) = value;
    }
}

Then you call it like:

fill_structs(pdevs, offsetof(struct deviations, y), top, -1);

offsetof() returns the offset in bytes of a structure member from the base of the structure. So in the function you have to convert the address of the array element to char * so you can add the offset to it, then convert it to int * so you can dereference it and assign to the int member there.

BTW, you should get out of the habit of using things like

(pdevs + i) -> x

If you're using a pointer as the base of an array, use array syntax:

pdevs[i].x

It's much easier to tell that i is an array index this way.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • agreed, pdevs[i] is the way I should've been using it, not sure what compelled me to go with the other way. I am unfamiliar with macros, will do some research and see if I can wrap my head around that and also this: *((int *)((char *)&pdevs[indexes[i]] + offset)) = value; New to C, so trying to make sense of the declarations in this. – Ali Z Oct 25 '18 at 03:00
  • It's always a good idea to use `typedefs` while working with `structs` e.g. `typedef struct _deviations deviations`. Then you can use it like any other types e.g. `int, char. size_t, etc` without having to mention `struct` every time – Sisir Oct 25 '18 at 03:24
  • @Sisir LOL, earlier today I was answering a question that used a typedef, and someone else said that it's NOT a good idea, and referred me to a Linux kernel style guide. – Barmar Oct 25 '18 at 03:26
  • It's not good to declare `typedef struct _deviations* deviations` but it is absolutely fine to declare `typedef struct _deviations deviations`. In fact if you don't do this every time you want to use the type you will have to write the obvious keyword `struct`. However I agree that this concept is subject to individual perception and your current project guidelines. – Sisir Oct 25 '18 at 03:38
  • Some nice discussions on this particular topic is in the below links https://softwareengineering.stackexchange.com/questions/147545/when-to-use-typedef https://stackoverflow.com/questions/516237/when-should-i-use-typedef-in-c – Sisir Oct 25 '18 at 03:39
  • 1
    @Sisir I know about the "don't typedef pointers" advice and agree. That was the first time anyone told me "don't typedef at all", and I agree with you. But I don't make a point of advising one way or the other in my answers, I just go with whatever the OP did. – Barmar Oct 25 '18 at 03:42
1

This answer serves purely to challenge your thinking about your current approach.

Personally, unless there's some special logic involved, I would just ditch the loops completely and initialize your struct like this.

const struct deviations devs[8] = {
    { 1, -1, -1 },  // top-left
    { 1,  0, -1 },  // top
    { 1,  1, -1 },  // top-right
    { 1, -1,  0 },  // left
    { 1,  1,  0 },  // right
    { 1, -1,  1 },  // bottom-left
    { 1,  0,  1 },  // bottom
    { 1,  1,  1 }   // bottom-right
};

If you then decide that you really need to allocate that dynamically then you could just copy it:

struct deviations *pdevs = malloc(sizeof(devs));
if (pdevs) memcpy(pdevs, devs, sizeof(devs));

But if you really wanted to generate this stuff in a loop, why not something like this?

int ii = 0;
for(int y = -1; y <= 1; ++y) {
    for(int x = -1; x <= 1; ++x) {
        if (x == 0 && y == 0) continue;
        pdevs[ii].switch = 1;
        pdevs[ii].x = x;
        pdevs[ii].y = y;
        ++ii;
    }
}
paddy
  • 60,864
  • 6
  • 61
  • 103
  • Honestly, a static set of arrays is probably the easier/smarter way to go about it, I actually had that written down on the last page of my notes and then went down the rabbit hole the past few hours over and complicated things to the billionth degree. Thanks for the clarity, think it's time for a walk. – Ali Z Oct 25 '18 at 03:10
  • No worries. By the way, I was pushing you to add extra detail to your question because I suspected it suffered from the [XY problem](https://meta.stackexchange.com/a/66378/200806). – paddy Oct 25 '18 at 03:16
  • You were right, this is definitely accurate...oops. – Ali Z Oct 25 '18 at 03:20