0

I have to create 2 structs namely rectangle and oval, where the rectangle structure contains its length and breadth and the oval structure contains the lengths of its semi-minor and semi-major axes. Then I have to create a union Shape which has the above two structs as its members. I then have to create a common function 'area' which calculates the area of the union(Either the rectangle or the oval on the basis of the arguments passed to the function). I currently handled the above using a menu-driven approach and using switch cases (code attached after the question).

I want to create a smart function which takes the union as a parameter and calculates the area depending on what structure is stored in the union.

CODE

typedef struct rect{
    int l,b;
}r;
typedef struct oval{
    int x,y;
}o;
union shape{
    r r1;
    o o1;
}sh;
void area(int a);
void main()
{
    int ch;
    int a;
    printf(" 1.Area of rect\n 2.Area of oval\n 3.EXIT");
    while(1){
        printf("\nEnter your choice: ");
        scanf("%d",&ch);
        switch(ch)
        {
            case 1:a=0;
                area(a);
                break;
            case 2:a=1;
                area(a);
                break;
            default:printf("BYE\n");
                return;
        }
    }
}
void area(int a)
{
    if(a==0){
        printf("Enter Length and Breadth: ");
        scanf("%d %d",&sh.r1.l,&sh.r1.b);
        int ar=sh.r1.l*sh.r1.b;
        printf("%d",ar);
    }
    else if(a==1){
        printf("Enter x and y of Oval: ");
        scanf("%d %d",&sh.o1.x,&sh.o1.y);
        float ar=sh.o1.x*sh.o1.y;
        printf("%.2f",ar*3.14);
    }
}

Thanks in advance!

  • You need a `struct` that has a `type` member, and the `union`. The `type` is used to indicate which field of the `union` is valid. – user3386109 Nov 16 '19 at 06:58
  • @user3386109 Can you provide an example using the `type` member? – coderboy Nov 16 '19 at 07:37
  • Have a look at [this question](https://stackoverflow.com/questions/252552/). The first answer has an example of what I'm talking about (in the larger code snippet). And [this question](https://stackoverflow.com/questions/4940064) has a variation on the theme. – user3386109 Nov 16 '19 at 08:03
  • @user3386109 Good links. But may I recommend to change from "first answer" to "most upvoted answer"? Sorting of answers is configurable by each user individually you know. – Yunnosch Nov 16 '19 at 08:06
  • If using C++17 or later, and definitely not using C++ standards before C++17, you might want to consider `std::variant`. – Peter Nov 16 '19 at 08:24
  • @user3386109 I disagree, if I select "oldest" sorting, I get a different "first", one with 29 upvotes, followed by 4 and 242. – Yunnosch Nov 16 '19 at 08:36
  • 1
    If you want to stay in pure C, another approach is to have a pointer to an `area` function in your `shape` struct. When you create an oval, just make this pointer to point to an `ovalArea` function ; when you create a rectangle make it to point to an `rectArea` ; and so on with other geometry. And when you need an area for `sh *a`, just call `a->area(a)`. – Joël Hecht Nov 16 '19 at 08:40

2 Answers2

1

As an alternative to the risky (not typesafe), and assuming that the feature is a MUST requirement, consider using the Type-Generic _Generic macro, which will allow you to dispatch a single call, based on type.

I have to admit that in 10+ years of C development, I've never had a situation that justified the usage of this construct - using a language that has proper support for polymorphism (c++, Java) is always preferable.

#define area(shape) _Generic((shape), struct oval: oval_area, struct rect: rect_area)

typedef struct rect{
    int l,b;
}r;
typedef struct oval{
    int x,y;
}o;

int rect_area(struct rect v) {
        return v.l *  v.b ;
}

int oval_area(struct oval v) {
        return v.x * v.y * 2 ;
}

void main(void)
{
        struct rect r ;
        struct oval o ;

        area(r) ;
        area(o) ;
}
dash-o
  • 13,723
  • 1
  • 10
  • 37
0

The safest solution has been described by user3386109 via links to other posts.
I very much recommend to use that approach.

However, there is another alternative, based on keeping track of which type is represented in which union implicitly. (The concept I have already described here How to verify if a void pointer (void *) is one of two data types? ).

A union basically tells the compiler, that it might be this type or that and explicitly that the compiler for this variable/type does NOT know better than the programmer (which otherwise usually is the case). So if the programmer instructs the compiler to access this union member or that, then the compiler will trust that it matches what was last written.

In this situation the programmer must know better than the compiler.
I.e. this is the opposite of what easily is misunderstood about unions by programmers, instead of "I do not need to know which type is in there." it means "I have to know at each and every point what is in there, because I need to tell the compiler."

Now the concept to use another part of the variable to keep track of what is stored (described by user3386109 ), makes that duty quite bearable.
But if you do not follow that approach, then the knowledge can and must still be somewhere else.
You could for example store all ovals in one array and all rectanlges in another. Syntactically both are the same, but you would only ever do oval things with the array of ovals and only ever rectanlge things with the array of rectangles.
I chose this example for being very simple to understand, but I admit it does not make a lot of practical sense, because then there is no benefit in having a union type for both.
It does however illustrate the possibility that the type info is somewhere, but implicit and that that form of storing it, can be more efficient concerning execution time and memory consumption.

A slightly more complex datastructure, which contains your shape struct, can make more sense. For example, a struct for baloons would contain the geometry information in a shape and there would never be a question whether it means an oval (rotation-ellipsoid) or a rectangle (square-faced box), neither would something describing parts of walls in a room which need papering ever be in any doubt.

Yunnosch
  • 26,130
  • 9
  • 42
  • 54