Advertisement
regzarr

unions, structs and bit fields

Mar 12th, 2019
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.39 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6.  
  7. // Read coordinates X, Y for point @point_name, place them in @output
  8. #define INPUT_COORDS_POINT(point_name, output)  \
  9.         printf("Enter coordinate X for %s:\n", point_name); \
  10.         scanf("%lf",output.x); \
  11.         printf("Enter coordinate Y for %s:\n", point_name); \
  12.         scanf("%lf",output.y);
  13.  
  14. //#define OUTPUT_COORDS_POINT(polygon, point) \
  15. //        printf("(%f,%f)", polygon. point.x, polygon.point.y);
  16.  
  17. #define OUTPUT_COORDS_POINT(point) \
  18.         printf("(%f,%f)", point.x, point.y);
  19.  
  20. // For debugging and researching purposes
  21. void printBits(unsigned char n) {
  22.     unsigned bitLength = sizeof(unsigned char) * 8;
  23.     int count = 0;
  24.     for (int bitPos = bitLength - 1; bitPos >= 0; bitPos--) {
  25.         if (count == 4) putchar(' ');
  26.         if ((n & (1 << bitPos)) == 0) {
  27.             putchar('0');
  28.         } else {
  29.             putchar('1');
  30.         }
  31.         count++;
  32.     }
  33.     putchar('\n');
  34. }
  35.  
  36. enum geometric_type {
  37.     t_circle = 1,
  38.     t_triangle = 2,
  39.     t_rectangle = 3
  40. };
  41.  
  42. typedef struct _point {
  43.     double x, y;
  44. } point;
  45.  
  46. typedef struct _circle {
  47.     point center;
  48.     unsigned int radius;
  49. } circle;
  50.  
  51. typedef struct _triangle {
  52.     point A;
  53.     point B;
  54.     point C;
  55. } triangle;
  56.  
  57. typedef struct _rectangle {
  58.     point A;
  59.     point B;
  60.     point C;
  61.     point D;
  62. } rectangle;
  63.  
  64. // WARNING: this will always access the first three points in the rectangle (rec.A, rec.B and rec.C)
  65. // It is the caller's responsibility to make sure these are declared beforehand.
  66. bool isValidRectangleDefinition(rectangle rec) {
  67.     // we "move" B and C such that they can be considered vectors starting from the origin (0,0)
  68.     // graphical explanation below
  69.     point b, c;
  70.     b.x = rec.B.x - rec.A.x;  // (?):
  71.     b.y = rec.B.y - rec.A.y;  // is there an easier
  72.     c.x = rec.C.x - rec.B.x;  // or shorter way
  73.     c.y = rec.C.y - rec.B.y;  // of doing this?
  74.     if (1.0 * b.x * c.x + 1.0 * b.y * c.y == 0) { // the dot product is 0 meaning that the vectors are perpendicular
  75.         return true;
  76.     }
  77.     return false;
  78. }
  79.  
  80. /*
  81.      y ^                                                y ^
  82.        |                                                  |
  83.        |  A (1, 1)                   turns to             |
  84.        |                                                  |
  85.        |    +                                             |
  86.        |    |                                             |
  87.        |    |                                             |
  88. +---------------------------->                     +---------------->----------->
  89.        |    |                                             |
  90.        |    |                x                            |      C (2, 0)       x
  91.        |    v--------->                                   |
  92.        |                                                  |
  93.        |  B (1, -1)    C (3, -1)                          |
  94.        |                                                  v  B (0, -2)
  95.        |                                                  |
  96.        |                                                  |
  97.        +                                                  +
  98. */
  99.  
  100. typedef struct _geometric_object {
  101.     unsigned char shape : 2; // actually useless but I need to use bit fields somewhere
  102.     // makes the switch statement in the reading function unsafe too...
  103.     union {
  104.         circle c;
  105.         triangle t;
  106.         rectangle r;
  107.     };
  108. } geometric_object;
  109.  
  110. void readGeometricObject(geometric_object *obj) {
  111.     geometric_object input;
  112.     unsigned char c;
  113.     printf("What is the shape of the geometric object being defined?\n"
  114.            "1. Circle\n"
  115.            "2. Triangle\n"
  116.            "3. Rectangle\n"
  117.            "0. Abort\n");
  118.     scanf("%hhu", &c);
  119.     switch (c) {
  120.         case t_circle:
  121.             obj->shape = t_circle;
  122.             printf("Enter coordinate X for the center:\n");
  123.             scanf("%lf", &obj->c.center.x);
  124.             printf("Enter coordinate Y for the center:\n");
  125.             scanf("%lf", &obj->c.center.y);
  126.             printf("Enter the radius:\n");
  127.             scanf("%u", &obj->c.radius);
  128.             break;
  129.         case t_triangle:
  130.             obj->shape = t_triangle;
  131.             INPUT_COORDS_POINT("A", &obj->t.A)
  132.             INPUT_COORDS_POINT("B", &obj->t.B)
  133.             INPUT_COORDS_POINT("C", &obj->t.C) // these may or may not define a line (the points A,B,C)
  134.             break;
  135.         case t_rectangle:
  136.             obj->shape = t_rectangle;
  137.             INPUT_COORDS_POINT("A", &obj->r.A)
  138.             INPUT_COORDS_POINT("B", &obj->r.B)
  139.             bool valid;
  140.             do {
  141.                 INPUT_COORDS_POINT("C", &obj->r.C)
  142.                 valid = isValidRectangleDefinition(obj->r);
  143.                 if (!valid) {
  144.                     printf("A, B and C cannot form a rectangle as they are not making a right angle. Enter point C again:\n");
  145.                 }
  146.             } while (!valid);
  147.             obj->r.D.x = (obj->r.C.x - obj->r.B.x) + obj->r.A.x;
  148.             obj->r.D.y = (obj->r.C.y - obj->r.B.y) + obj->r.A.y;
  149.             break;
  150.         case 0:
  151.             printf("Aborting...\n");
  152.             break;
  153.         default:
  154.             printf("Invalid shape\n");
  155.     }
  156. }
  157.  
  158. void printGeometricObject(const geometric_object *obj) {
  159.     switch (obj->shape) {
  160.         case t_circle:
  161.             printf("Circle defined by center (%f,%f) with radius %u\n", obj->c.center.x, obj->c.center.y,
  162.                    obj->c.radius);
  163.             break;
  164.         case t_triangle:
  165.             printf("Triangle defined by points ");
  166.             /*for (char ch = 'A'; ch <= 'C' ; ++ch){  // how would I go around doing this?
  167.                 OUTPUT_COORDS_POINT(&obj.t, ch)
  168.             }*/
  169.             printf("A ");
  170.             OUTPUT_COORDS_POINT(obj->t.A)
  171.             printf(", B ");
  172.             OUTPUT_COORDS_POINT(obj->t.B)
  173.             printf(", C ");
  174.             OUTPUT_COORDS_POINT(obj->t.C)
  175.             printf(".\n");
  176.             break;
  177.         case t_rectangle:
  178.             printf("Rectangle defined by points ");
  179.             printf("A ");
  180.             OUTPUT_COORDS_POINT(obj->r.A)
  181.             printf(", B ");
  182.             OUTPUT_COORDS_POINT(obj->r.B)
  183.             printf(", C ");
  184.             OUTPUT_COORDS_POINT(obj->r.C)
  185.             printf(", D ");
  186.             OUTPUT_COORDS_POINT(obj->r.D)
  187.             printf(".\n");
  188.             break;
  189.         default:
  190.             printf("Object shape undefined.\n");
  191.     }
  192. }
  193.  
  194. // ----- HOME EXERCISES ----- //
  195. /*1. A simple classification of stars is as follows:
  196.  *
  197.  * (a) Main Sequence Stars characterized by: age category (an integer
  198.  * value between 1 and 4) and color (a character array of at most
  199.  * 12 characters)
  200.  * (b) Binary Stars rotating around a mass center characterized by:
  201.  * rotation radius for the first and the second star
  202.  * (c) Variable Light Stars characterized by: lowest luminosity, highest
  203.  * luminosity and light periodicity measured in Earth days
  204.  *
  205.  * All stars have a name of arbitrary length. Use composite variables
  206.  * and bit fields and write a program that reads data about a star and
  207.  * then prints it back on the screen.*/
  208.  
  209. typedef struct _main_sequence_star {
  210.     unsigned age; // integer between 1 and 4
  211.     char color[13];
  212. } msStar;
  213.  
  214. typedef struct _binary_star {
  215.     unsigned firstStarRotationRadius : 16;
  216.     unsigned secondStarRotationRadius : 16;
  217. } bStar;
  218.  
  219. typedef struct _variable_light_star {
  220.     // Stellar luminosity is characterized by the size of the star measured in
  221.     // solar radii and its effective temperature measured in Kelvin, but for the
  222.     // sake of simplicity I will only measure it in positive integer values
  223.     // representing Bolometric luminosity (in solar units). The most luminous
  224.     // star listed on Wikipedia is R136a1 measuring in at 8,710,000 su.
  225.     // Here's the wiki page for reference:
  226.     // https://en.wikipedia.org/wiki/List_of_most_luminous_stars
  227.     unsigned lowLuminosity : 24;
  228.     unsigned highLuminosity : 24; // values up to 16,777,215
  229.     unsigned periodicity : 16;
  230. } vlStar;
  231.  
  232. typedef struct _star {
  233.     char *name;
  234.     enum _class {
  235.         t_ms,
  236.         t_b,
  237.         t_vl
  238.     } class;
  239.     union {
  240.         msStar ms;
  241.         bStar b;
  242.         vlStar vl;
  243.     };
  244. } Star;
  245.  
  246. char *readString() {
  247. #define CHUNK 32
  248.     char *input = NULL;
  249.     char buf[CHUNK];
  250.     size_t inputLength = 0, bufLength = 0;
  251.     do {
  252.         if (fgets(buf, CHUNK, stdin)) {
  253.             bufLength = strlen(buf);
  254.             input = realloc(input, inputLength + bufLength);
  255.             strcpy(&input[inputLength], buf); // buf is guaranteed to have a null terminating character
  256.             inputLength += bufLength;
  257.         }
  258.     } while ((bufLength == CHUNK - 1) && buf[CHUNK - 2] != '\n');
  259.     return input;
  260. }
  261.  
  262. Star readStar() {
  263.     Star star;
  264.     printf("Name of the star:\n");
  265.     // reading the arbitrarily long string
  266.     star.name = readString();
  267.     printf("Type of star:\n"
  268.            "(a) Main Sequence Star\n"
  269.            "(b) Binary Star\n"
  270.            "(c) Variable Light Star\n");
  271.     char type;
  272.     scanf("%c", &type);
  273.     switch (type) {
  274.         case 'a':
  275.             star.class = t_ms;
  276.             printf("Age (integer between 1 and 4):\n");
  277.             scanf("%u", &star.ms.age);
  278.             while (star.ms.age < 1 || star.ms.age > 4) {
  279.                 printf("Age out of range. Enter an integer between 1 and 4:\n");
  280.                 scanf("%u", &star.ms.age);
  281.             }
  282.             printf("Color (maximum of 12 characters):\n");
  283.             fgets(star.name, 12, stdin);
  284.             break;
  285.         default:
  286.             printf("Undefined classification\n");
  287.     }
  288.     return star;
  289. }
  290.  
  291. int main() {
  292.     // Exercise 0 //
  293.     /*int listLength = 3;
  294.     geometric_object list[listLength];
  295.     *//*for (int i = 0; i < 3; ++i) {
  296.         readGeometricObject(&list[i]);
  297.     }
  298.     for (int i = 0; i < 3; ++i) {
  299.         printGeometricObject(&list[i]);
  300.     }*//*
  301.     readGeometricObject(&list[0]);
  302.     printGeometricObject(&list[0]);*/
  303.  
  304.     // Exercise 1 //
  305.     Star st = readStar();
  306.     return 0;
  307. }
  308.  
  309. /* QUESTIONS:
  310.  * ----- Exercise 0: Geometric shapes -----
  311.  * 1. ---DISMISSED--- The problem was solved by itself (somehow): I declared the function as a geometric_object type
  312.  * function as a workaround (with no parameters, planning on just simply returning the variable @input) but returned
  313.  * to my initial idea. Initial question:
  314.  * ### I cannot use "geometric_object" instead of "struct _geometric_object" as a function parameter (compiler will not
  315.  * recognize geometric_object as a type in this case). Why is that? ###
  316.  * 2. Why is memmove a better approach than memset in the case of overlapping memory blocks? Is there undefined
  317.  * behaviour involved?
  318.  * 3. See function isValidRectangleDefinition().
  319.  * 4. See function printGeometricObject().
  320.  * 5. How would I go about making a delete function which sets all the values in a geometric_object type variable
  321.  * to 0? I know the size of the union will be sizeof(rectangle) but what about the @shape?
  322.  *
  323.  * ----- Exercise 1: Stars -----
  324.  * 1. Should I free() the stars' names at the end of main even if they get freed after terminating the program?
  325.  * 2. True or not?
  326.  * "Size of char is always 1 byte, regardless of whether 1 byte means 8 bits or not"
  327.  * Should I ever call sizeof(char)?
  328.  */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement