Union as a Structure Variable in C

199 views Asked by At

I have the following structures:

complex_attribute
generic_attribute

I defined a union of these two, like so:

union union_attribute{
    struct complex_attribute *complex;
    struct generic_attribute *generic;
};

And then i defined another structure which keeps track of the union and a code associated with it:

struct tagged_attribute{
    int code;
    union union_attribute *attribute;
};

Then, i defined another structure called Disk, which contains an array of pointers to tagger_attribute objects:

struct disk {
    struct tagged_attribute *attribute_ptr[100];
}

Now I am trying to access the code of the tagged attribute like this:

printf("%i", disk_ptr->attribute_ptr[counter]->code); 

But I am getting a segmentation fault. Is my way of accessing the structure variable "code" incorrect?

Here is all of the relevant code from where I am trying to access "code":

struct disk* construct_disk(char* name, char* serial, char* vendor, char* model, int RPM, char *raid_type, int num_args, ...){
    struct disk *disk_ptr;
    disk_ptr = malloc (sizeof (struct disk));

    va_list ap;
    va_start(ap, num_args);
    int counter;
    int incrementer;
    //subattributes is a global variable
    incrementer = subattributes[counter];

    for(counter = 0; counter < num_attributes; counter++, incrementer = subattributes[counter]){
        printf("Counter = %i\n", counter);
        printf("incrementer = %i\n", incrementer);
        if (1){
            printf("Populating generic attribute");
            printf("%i", disk_ptr->attribute_ptr[counter]->code);
            //disk_ptr->attribute_ptr[counter]->code = GENERIC_ATTRIBUTE_TYPE;
            //disk_ptr->attribute_ptr[counter]->attribute->generic = construct_generic_attribute(va_arg(ap, int));
        }else{
            printf("Populating complex attribute");
            //struct generic_attribute* input_to_complex_attribute[incrementer];
            //int stepper;
            //for(stepper = 0; stepper<incrementer; stepper++){
            //  input_to_complex_attribute[stepper] = construct_generic_attribute(va_arg(ap, int));
            //}
            //disk_ptr->attribute_ptr[counter]->code = COMPLEX_ATTRIBUTE_TYPE;
            //disk_ptr->attribute_ptr[counter]->attribute->complex = construct_complex_attribute(5, incrementer, input_to_complex_attribute);
        }
    }

    va_end(ap);
    return disk_ptr;
}
3

There are 3 answers

0
Iskar Jarak On BEST ANSWER

You aren't accessing code at all (which you should be using to check which union member is valid, of course).

You're accessing the counterth element of the attribute_ptr array, which is a pointer to a tagged_attribute and trying to dereference it (with ->). Possibly without allocating that pointer (or any of the others in that array) first, nor initialising the memory after allocation (you haven't shown anything about that... failure to allocate correctly is a likely cause of your segfault.)

Of course, this assumes disk_ptr has been allocated and initialised correctly... which you haven't shown and may not have.

As already mentioned, show all relevant code if you want a more specific answer to your question. Further, compile with warnings enabled and learn to use tools such as gdb (GNU debugger) and valgrind (for memory issues) to debug your code.

EDIT: Now that you've added code, you have allocated disk_ptr but you never allocate anything in attribute_ptr, so it's just 100 pointers pointing to arbitrary places in memory.

0
missimer On

In C if a pointer is not pointing to valid memory you will have undefined behavior. One of the common things that happens is a segmentation fault as the pointer has random chunk or was initialized to zero and when you try to access the memory it is pointing to the hardware detects that you are accessing an invalid memory page. Every time you use -> you are dereferencing the pointer and run the risk of a seg fault. You should use a debugger to find the incorrect value. An alternative is to print the values before you dereference them:

printf("disk_ptr = %p\n", disk_ptr);
printf("disk_ptr->attribute_ptr[counter] = %p\n", disk_ptr->attribute_ptr[counter]);

You should place this code before the print that you shows. If disk_ptr is an invalid value the second print will fail. The first print will always succeed but you should see if it is NULL or not. If you do not see the second print that means the disk_ptr is an invalid pointer. This because in the second print disk_ptr is dereferenced via the -> operator and if it points to chunk it could (let me emphasize could) cause a seg fault (it could also overwrite some other data which might cause a seg fault later). If the second print works but the print you shows does not then disk_ptr->attribute_ptr[counter] could be the invalid pointer. Let me emphasize again because it is important. If a pointer is not pointing to a correct memory location you have undefined behavior. Dereferencing that pointer could cause a seg fault right there or could modify memory in some way such that a seg fault occurs later.

0
too honest for this site On

You are dereferencing disk_ptr->attribute_ptr[1], but that array of pointers is not initialized (the pointers point nowhere).

You have to malloc the struct tagged_attribute entries for each pointer first.