Self-test 10:
Struct and Pointer
-
We have a struct called Point as follows. Define a struct Rect for rectangles that are parallel to the axes in a Cartesian coordinate system. Represent a rectangle by its lower left and upper right endpoints using the Point type.
struct Point { double x; double y; };Solutionstruct Rect { Point lowerLeft; /* lower right endpoint of rectangle */ Point upperRight; /* upper right endpoint of rectangle */ };
-
Write a function that returns true if a point falls within a rectangle, false otherwise. Use the Point and Rectangle types in Q1.
Solutionbool point_in_rectangle(const Point& p, const Rect& r) { // Applying logical 'and' to connect these conditions return ( (p.x <= r.upperRight.x && p.x >= r.lowerLeft.x) && (p.y <= r.upperRight.y && p.y >= r.lowerLeft.y) ); }
-
Complete the following function using the structures and functions in Q1 and Q2, so that it returns true if the first rectangle is completely contained inside the second rectangle, and false otherwise.
bool rectangle_in_rectangle(const Rect& r1, const Rect& r2) { // CODE HERE }Solutionbool rectangle_in_rectangle(const Rect& r1, const Rect& r2) { return point_in_rectangle(r1.lowerLeft, r2) && point_in_rectangle(r1.upperRight,r2); }
-
What is the output of the following program?
#include <iostream> using namespace std; struct Point { int x; int y; }; void foo(int *x) { if (*x > 0) { cout << *x << endl; *x = *x - 1; foo(x); } } int main(void) { Point my = {4,5}; foo(&(my.y)); cout << my.x << " " << my.y << endl; return 0; }Solution5 4 3 2 1 4 0When we call foo for the first time, the address of my.y passed to the function. variable x in the function foo will contain the address of my.y, so changing the value of *x actually changes the value of my.y. The function foo is called recursively, each time decrementing the value of my.y until its value becomes 0. However, during the recursive calls, my.x is not modified at all.
-
With the two struct defined as below, which one of the following initializations of a struct is incorrect?
struct Student_Detail { int year; char *name; }; struct Student_Data { int id; struct Student_Detail detail; };A. Student_Data a; a.detail.name = "Johnson Lee"; B. Student_Data b; b = { 10, 2009, "Johnson Lee" }; C. Student_Data c[10]; c[0].id = 100; c[0].detail.year = 20; c[0].detail.name = "Johnson Lee"; c[1] = c[0]; D. Student_Data c = { 2009, 20, "Johnson Lee" };SolutionB is not correct. A struct variable can be initialized when it is defined using the brace initializer notation; so D is correct. But if it is not initialized during its definition it can't be done in that way.
-
What's the problem with the following code?
#include <iostream> using namespace std; int main(void) { int x = 2; int *px; *px = &x; cout << *px << endl; return 0; }Solution#include <iostream> using namespace std; int main(void) { int x = 2; int *px; *px = &x; // Compilation error. Correct: px = &x; cout << *px << endl; return 0; }Reason: the type of x is an integer. So &x has the type of int*, and the type of *px is an integer.
-
What's the problem with the following code?
#include <iostream> using namespace std; int main(void) { int x = 2, y = 10; int *px, py; px = &x; py = &y; cout << *px << endl; cout << *py << endl; return 0; }Solution#include <iostream> using namespace std; int main(void) { int x = 2, y = 10; int *px, py; px = &x; py = &y; // Compilation error. cout << *px << endl; cout << *py << endl; return 0; }Reason: py is an int type, but &y is an int* type. Compilation error is resulted. You can change the line int *px, py; to int *px, *py; to solve the problem
-
What's the problem with the following code?
char a[20][5]; char** p = a; p[3][6] = 9;
SolutionThe statement
char** p = a;will give a compilation error.This is a common confusion when a 1-dimension array identifier and a 2-dimensional array identifier are interpreted as a pointer in C++.
In the following code
char s[10]; char* q = s;s can be interpreted as a char pointer with the type of char* and thus q=s is fine.However, for 2-dimensional array such as
char a[20][5];
a is a pointer to a 1-dimensional char array with 5 elements! That is, the type a is NOT char** but char (*)[5]. Recall that when you pass a 2-dimensional array to a function, you need to specify its second dimension. That is the reason.Finally, to correct the error, we need to define p as char (*p)[5]. That is,
char (*p)[5] = a;
-
What are the outputs of the following code?
int a[5] = {1, 2, 3, 4, 5}; long x1 = reinterpret_cast<long>(a); long x2 = reinterpret_cast<long>(a+1); long y1 = reinterpret_cast<long>(&a); long y2 = reinterpret_cast<long>(&a+1); cout << x2-x1 << endl; cout << y2-y1 << endl;Solution4 20
In C++, a can be interpreted as a pointer to a[0], and (a+1) a pointer to a[1]. That is, a gives the address of a[0] and (a+1) gives the address of a[1] in the memory. Since the size of int is 4 bytes, therefore the numerical difference between (a+1) and a is 4.
However, &a means the address of the int a[5] array, and thus (&a+1) is interpreted as a pointer to an imaginary 1-dimensional int array put below the int a[5] array. Thus, the difference between (&a+1) and &a is the size of the whole int array with 5 integers, and is 4*5=20.
-
What's the problem with the following code?
char* s = "ABC"; cout << s << endl; s[0] = 'B'; cout < s << endl;
SolutionThis will be compiled successfully but with a warning such as the one below:
warning: conversion from string literal to 'char *' is deprecated [-Wdeprecated-writable-strings] char* s="ABC";And if you run the program, it will crash. The reason is that the pointer s points to a constant C string which is protected by the operating system and cannot be modified. When you try to modify this constant C string, the program will fail.
-
What's the problem with the following code?
void allocate_memory(char *p) { p = new char[50]; strcpy(p, "hello world"); } int main(void) { char *str = NULL; allocate_memory(str); cout << str; delete [] str; str = NULL; return 0; }SolutionThis will be compiled successfully but the program will crash. When you call allocate_memory() you pass the str by value and its value is copied to p in allocate_memory(). Nothing really happens with the pointer str when the function allocate_memory is run. Thus, on return from allocate_memory(), str is still equal to NULL, and the program will crash when you delete a dynamic array which is actually a NULL pointer. The correct code should use pass-by-reference.
void allocate_memory(char*& p) { p = new char[50]; strcpy(p, "hello world"); }
-
If the address of x is 1500 and the address of y is 400, what is the value of z after the following statements?
int x = 21; int* y = &x; int z = *y;
SolutionThe value of z is 21.
-
What is wrong with the following program?
#include <iostream> using namespace std; int main(void) { int i = 4, j = 2; int *p, *q; p = &i; q = &p; cout << *p << endl; cout << *q << endl; return 0; }Solution#include <iostream> using namespace std; int main(void) { int i = 4, j = 2; int *p, *q; p = &i; q = &p; // Compilation error. Correct : q = p; cout << *p << endl; cout << *q << endl; return 0; }Reason: q is of int* type, but &p is of int** type. Compilation error is resulted.
-
What are the outputs of the following program?
#include <iostream> using namespace std; int main(void) { int i = 4,j = 2; int *p; int r[5] = {0, 3, 6, 9, 12}; p = r; i = (*p)++; j = *(p++); cout << "i=" << i << endl; cout << "j=" << j << endl; return 0; }Solutioni=0 j=1
Reason: p is equivalent to &r[0], hence *p is r[0]. The statement i = (*p)++; will put the original value of r[0], i.e. 0, to i, and then increase r[0] to 1. Then the statement "j = *(p++);" will first put the value of *p, i.e. 1, to j, and then increase the pointer p by 1 meaning p would then point to r[1].
-
Given the following array declaration:
int a[3][4];
Which of the following expression(s) is/are NOT equivalent to a[i][j]?
a) *(&a[0][0]+4*i+j) b) *(a[i]+j) c) *(a[i][0]+j) d) *((*(a+i)) + j)
SolutionThe expression (c) is not. a[i][0] is the of int type. Instead the address should be used, i.e. &a[i][0]. The correct expression is:
*(&a[i][0]+j)
-
What is the problem with the following program?
#include <iostream> using namespace std; struct Point { double x; double y; }; struct Shape { Point* pts; int numOfPts; }; int main(void) { Point temp[4] = {{0.0, 0.0}, {10.0, 5.0}, {10.0, 20.0}, {0.0, 20.0}}; Shape rect; rect.numOfPts = 4; rect.pts = &temp; }Solution#include <iostream> using namespace std; struct Point { double x; double y; }; struct Shape { Point* pts; int numOfPts; }; int main(void) { Point temp[4] = {{0.0, 0.0}, {10.0, 5.0}, {10.0, 20.0}, {0.0, 20.0}}; Shape rect; rect.numOfPts = 4; rect.pts = &temp; // correct: rect.pts = temp; }Reason: rect.pts is of type Point*, while &temp is of type Point**. Hence, temp which is the address of the Point array should be assigned to rect.pts.
-
Given the two structures in Question 16, namely, Point and Shape, and the following two functions:
void fn(Shape *shape) { Point tmp; for (int i = 0; i < (shape->numOfPts)/2; i++) { tmp = (*shape).pts[i]; *((*shape).pts + i) = *(shape->pts + shape->numOfPts - i - 1); shape->pts[shape->numOfPts - i - 1] = tmp; } } void printShape(Shape shape) { for (int i = 0; i < shape.numOfPts; i++) cout << shape.pts[i].x << "," << shape.pts[i].y << endl; }What are the outputs of the following main function?
int main(void) { Point temp[4] = {{0.0, 0.0}, {10.0, 5.0}, {10.0, 20.0}, {0.0, 20.0}}; Shape rect; rect.numOfPts = 4; rect.pts = temp; // Incorrect: rect.pts = &temp; cout << "Before: " << endl; printShape(rect); fn(&rect); cout << "After: " << endl; printShape(rect); }SolutionBefore: 0,0 10,5 10,20 0,20 After: 0,20 10,20 10,5 0,0