Puzzles G21 ... G20

Part G — Struct Problems

 

These puzzles involve structs and pointers.

A variable may be the actual memory of a struct or may point to a struct. Here are the two possibilities:

typedef struct
{
  int watts;
  int lumens;
} Bulb;

int main ()
{
  Bulb direct = {100, 1710};
  
  Bulb *reference;
  reference = (Bulb *)malloc( sizeof( Bulb ) );
  reference->watts = 40;
  reference->lumens = 800;
  . . .

The variable direct is the name of the actual memory of a struct. The variable reference holds a pointer to another struct.

pointer vs direct

The declaration

Bulb *reference;

merely sets up the variable reference without putting any value in it. No memory is allocated for a struct. At run-time, the program allocates memory for a struct:

reference = (Bulb *)malloc( sizeof( Bulb ) );

The sizeof() operator determines the number of bytes needed. At runtime, malloc() asks the operating system for that many bytes and returns the address of the first byte of the block. A type cast (Bulb *)tells the compiler how the address will be used.

So there are two ways to refer to a struct: directly and by reference (through a pointer). This can be confusing, and it gets even worse when structs contain structs.

 


Puzzle G21 — Point Declaration

Edit main() so that it contains the variable point which works correctly with the rest of the program.

/* declare the Point type */
typedef struct
{
  int x, y;
} Point;

/* function to print a Point */
void printPoint( Point *p )
{
  printf("(%d, %d)\n", p->x, p->y );
}

int main(int argc, char *argv[])
{
  /* declare and initialize the variable point */
  Point 

  /* print values */
  printPoint(   );
  
  system("pause");
  return 0;
}


Puzzle G22 — Another Point Declaration

This program is nearly the same as the previous one, except now dynamic memory is used for the struct. Edit main() so that it contains the variable point which works correctly with the rest of the program. Use malloc() to get dynamic memory. Don't forget to free it at the end of the program.

/* declare the Point type */
typedef struct
{
  int x, y;
} Point;

/* function to print a Point */
void printPoint( Point *p )
{
  printf("(%d, %d)\n", p->x, p->y );
}

int main(int argc, char *argv[])
{
  /* declare a Point and allocate memory */
  Point ?????

  /* don't change these statements */
  point->x = -23;
  point->y = 45;
 
  /* print values */
  printPoint(   );

  /* free memory */
  free( ???? );

  system("pause");
  return 0;
}


 

Here is the Triangle type, a Triangle variable tri, and a variable triptr that points to a Triangle:

typedef struct
{
  int x, y;
} Point;

typedef struct
{
  int red, green, blue;
} Color;

typedef struct
{
  Point p0, p1, p2;
  Color color;
} Triangle;

int main ()
{
  Triangle tri ;
  
  Triangle *triptr ;
  triptr = (Triangle *)malloc( sizeof(Triangle) );
}

At this point, neither triangle is initialized.

Two triangle structs

The identifier tri is the name for the memory of a Triangle. That memory can be assigned values by statements like:

  tri.p0.x = 45;
  tri.p0.y = 97; 

The variable triptr holds a pointer to the memory of a Triangle. That memory can be assigned values by statements like:

  triptr->p0.x = 45;
  triptr->p0.y = 97; 

 


Puzzle G23 — Triangle Initialization

Edit main() in the following so that it contains the variable tri which works correctly with the rest of the program.

/* Practice with various ways to declare things */

typedef struct
{
  int x, y;
} Point;

void printPoint( Point *p )
{
  printf("(%d, %d) ", p->x, p->y );
}

typedef struct
{
  int red, green, blue;
} Color;
 
void printColor( Color *c )
{
  printf("%3d red, %3d grn, %3d blu", c->red, c->green, c->blue );
}

typedef struct
{
  Point p0, p1, p2;
  Color color;
} Triangle;

void printTriangle( Triangle *t )
{
  printf("Points: ");
  printPoint( &t->p0 ); printPoint( &t->p1 ); printPoint( &t->p2 );
  printf("\nColor: ");
  printColor( &t->color );
  printf("\n");
}

int main ()
{
  /* Declare a variable here */
  ????
   
  /* Leave the following unchanged */
  tri.p0.x = 15;
  tri.p0.y = 15; 
  tri.p1.x = 85;
  tri.p1.y = 110; 
  tri.p2.x = 50;
  tri.p2.y = 50; 
  tri.color.red   = 123;
  tri.color.green = 50;
  tri.color.blue = 150;

  /* Insert the parameter in the function call */
  printTriangle( ??? )
  system("pause");
} 

Notice how the parameter t in printTriangle() is used. It is a pointer to a Triangle:

void printTriangle( Triangle *t )

Accessing a member point of the pointed-at Triangle is done through the pointer t:

t->p0

The function printPoint(Point *p) expects a pointer to a Point, so the address of the Point is supplied:

&( t->p0 )

Because of operator precedence, parentheses are not needed:

printPoint( &t->p0 );

The address-of operator & has lower precedence than the structure pointer member operator ->. Another way to do the same thing is:

printPoint( &( (*t).p0 ) );


Puzzle G24 — Another Triangle Initialization

Edit main() so that it contains the variable triptr which works correctly with the rest of the program. You will also need to allocate memory for the actual struct.

/* Practice with various ways to declare things */

typedef struct
{
  int x, y;
} Point;

void printPoint( Point *p )
{
  printf("(%d, %d) ", p->x, p->y );
}

typedef struct
{
  int red, green, blue;
} Color;
 
void printColor( Color *c )
{
  printf("%3d red, %3d grn, %3d blu", c->red, c->green, c->blue );
}

typedef struct
{
  Point p0, p1, p2;
  Color color;
} Triangle;

void printTriangle( Triangle *t )
{
  printf("Points: ");
  printPoint( &t->p0 ); printPoint( &t->p1 ); printPoint( &t->p2 );
  printf("\nColor: ");
  printColor( &t->color );
  printf("\n");
}

int main ()
{
  /* Declare a variable here */
  ?????
  
  /* Allocate memory here */
  ????
  
  /* Leave the following unchanged */
  triptr->p0.x = 15;
  triptr->p0.y = 15; 
  triptr->p1.x = 85;
  triptr->p1.y = 110; 
  triptr->p2.x = 50;
  triptr->p2.y = 50; 
  triptr->color.red   = 123;
  triptr->color.green = 50;
  triptr->color.blue = 150;

  /* Insert the parameter in the function call */
  printTriangle(????);
  
  /* free memory */
  ?????
  
  system("pause");
} 

In production-quality code, it would be best to use an initialization function for Triangle structs and to have a function that changes their values.


 

In the previous two puzzles, Triangle structs directly contained other structs. Another possibility is to have the Triangle struct contain pointers to the other struct types. Here is the picture:

Modified Triange Struct

Here are some typedef definitions for this:

typedef struct
{
  int x, y;
} Point;

typedef struct
{
  int red, green, blue;
} Color;

typedef struct
{
  Point *p0, *p1, *p2;
  Color *color;
} TriangleMod;

Here is code that constructs such a TriangleMod struct:

int main()
{
  TriangleMod *trimod;
  
  trimod = (TriangleMod *)malloc( sizeof( TriangleMod ) );
  trimod->p0 = (Point *)malloc( sizeof( Point ) );
  trimod->p1 = (Point *)malloc( sizeof( Point ) );
  trimod->p2 = (Point *)malloc( sizeof( Point ) );
  trimod->color = (Point *)malloc( sizeof( Color ) );
  ...
}

No values have been initialized in the above. This is done by statements like:

  trimod->p0->x = 45;
  triptr->p0->y = 97; 

Puzzle G25 — Initialization of Modified Triangle

Edit main() of the following code so that the struct is initialized correctly (pick the values you want) and printed out. At the end of the program, free dynamically allocated memory.

typedef struct
{
  int x, y;
} Point;

void printPoint( Point *p )
{
  printf("(%d, %d) ", p->x, p->y );
}

typedef struct
{
  int red, green, blue;
} Color;

void printColor( Color *c )
{
  printf("%3d red, %3d grn, %3d blu", c->red, c->green, c->blue );
}

typedef struct
{
  Point *p0, *p1, *p2;
  Color *color;
} TriangleMod;

void printTriangleMod( TriangleMod *t )
{
  printf("Points: ");
  printPoint( t->p0 ); printPoint( t->p1 ); printPoint( t->p2 );
  printf("\tColor: ");
  printColor( t->color );
  printf("\n");
}

int main()
{
  TriangleMod *trimod;

  trimod = (TriangleMod *)malloc( sizeof( TriangleMod ) );
  trimod->p0 = (Point *)malloc( sizeof( Point ) );
  trimod->p1 = (Point *)malloc( sizeof( Point ) );
  trimod->p2 = (Point *)malloc( sizeof( Point ) );
  trimod->color = (Color *)malloc( sizeof( Color ) );

  /* Initialize trimod here */

  /* Print out trimod here */
  printTriangleMod( trimod );
  
  /* Free memory here */

  system( "pause" );
}

The triangle print function has been modified to use the pointers in the TriangleMod struct.

Dynamically allocated memory should be returned when it is no longer in use. Think carefully about how to free memory at the end of the program.


Puzzle G26 — TriangleMod Constructor

A constructor for a TriangleMod struct allocates memory for the main struct and the structs it points to (of type Point and Color). Non-pointer members are initialized to zero. Write a newTriangleMod() function in the following:

typedef struct
{
  int x, y;
} Point;

void printPoint( Point *p )
{
  printf("(%d, %d) ", p->x, p->y );
}

Point *newPoint()
{
  Point *p = (Point *)malloc( sizeof( Point ) );
  p->x=0;
  p->y=0;
  return p;
}

void setPoint( Point *p, int x, int y )
{
  p->x = x; p->y = y;
}

typedef struct
{
  int red, green, blue;
} Color;

Color *newColor()
{
  Color *c = (Color *)malloc( sizeof( Color ) );
  c->red=0;
  c->green=0;
  c->blue=0;
  return c;
}

/* function to set a Color */
void setColor( Color *c, int r, int g, int b )
{
  if ( r<0 || r>255 ) r = 0;
  if ( g<0 || g>255 ) g = 0;
  if ( b<0 || b>255 ) b = 0;

  c->red   = r;
  c->green = g;
  c->blue  = b;
}

void printColor( Color *c )
{
  printf("%3d red, %3d grn, %3d blu", c->red, c->green, c->blue );
}

/* Write this function */
/* Use newColor() and newPoint()  (above) */
TriangleMod *newTriangleMod()
{
}

int main()
{
  TriangleMod *trimod = newTriangleMod();
  
  /* Initialize trimod here */

  /* Print out trimod here */
  printTriangleMod( trimod );
  
  /* Free memory here */

  system( "pause" );
}

The next puzzle has you write a destructor for TriangleMod. You can write it and include it in this program if you want.


Puzzle G27 — TriangleMod destructor

Because it is crucial to free memory in the correct order, that order should be encapsulated in a function. Add the following function to the previous program and use it at the end to free memory

void freeTriangleMod( TriangleMod *t )


Puzzle G28 — Setting functions

Write some "set" functions for the triangle type and use them to initialize the triangle.

/* set point "num" of tri to (x, y) */
void setTriangleModPoint( TriangleMod *tri, int num, int x, int y)
{
}

/* set the color of tri to (r, g, b) */
void setTriangleModColor( TriangleMod *tri, int r, int g, int b)
{
}

int main()
{
  TriangleMod *trimod = newTriangleMod();

  /* Initialize trimod here */
  setTriangleModPoint( trimod, 0, 45, 97 );
  setTriangleModPoint( trimod, 1, 75, 80 );
  setTriangleModPoint( trimod, 2,  0,  0 );
  setTriangleModColor( trimod, 120, 240, 50);

  /* Print out trimod */
  printTriangleMod( trimod );

  /* Free memory */
  freeTriangleMod( trimod );
  
  system( "pause" );
}


Puzzle G29 — Array of Triangles

Create an array of triangle pointers. Initialize the array by setting each cell to NULL. Then create several triangles and put their address in some of the array cells. Print out the array, showing which cells contain null and printing triangle data for other cells. Here is a picture of the array with three cells filled with pointers to initialized triangles:

Triangle Array

Here is code that starts building the above structure. Your job is to finish the program.

int main()
{
  const int length = 8;
  
  TriangleMod *triarray[length];
  
  /* Initialize the array here */
  ????????

  /* Create several array elements here */
  ????? = newTriangleMod();
  setTriangleModPoint( ??????, 0, 245, 148 );
  setTriangleModPoint( ??????, 1, -97,  32 );
  setTriangleModPoint( ??????, 2,  12, -34 );
  setTriangleModColor( ??????, 200, 160, 100);
  . . .

  /* Print out the array here. Print "null" for empty cells. */
  ???????

  /* Free allocated memory here */
  
  
  system( "pause" );
}

Don't try to free memory that has not been allocated.


Puzzle G30 — Triangle Collection Type

Define a struct type triCollection that contains two members: a pointer to an array of triangles and an int that gives the number of elements. Write a constructor and a destructor for the type. Initialize several array elements and print out the collection.

Actually, this is quite a bit of work for one puzzle. It would be OK to skip this one.

Triangle Collection


— Return to the main contents page