Looking for met2502f25-a.sg test answers and solutions? Browse our comprehensive collection of verified answers for met2502f25-a.sg at distance3.sg.digipen.edu.
Get instant access to accurate answers and detailed explanations for your course questions. Our community-driven platform helps students succeed!
Just as in C, the type qualifier const is used in C++ to declare and initialize a read-only variable whose value cannot be changed during program execution. Therefore, the following code fragment will be flagged as a compile-time error:
int const value {10};
std::cout << "value: " << value << "\n";
value = 20; // error: assigning a new value to a const variable
std::cout << "value: " << value << "\n";
In both languages, the rule is that a const variable must be initialized during its definition. This makes sense since if a const variable's value cannot be changed during its lifetime, it can only be given a value when its lifetime begins. Therefore, the following code will be flagged as a compile-time error:
int const value; // error: const variable is not initialized during its definition
value = 20;
A constant expression is an expression whose value can be evaluated at compile-time and whose value cannot be changed during program execution. A literal value such as and is a constant expression. It may seem strange but a const variable need not be a constant expression. As an example:
void foo(int n) {
double pi = 3.14285714; // 3.14285714 is a constant expression
const int size = n; // not a constant expression
// other code here ...
}
literal is a constant expression while read-only variable size is not a constant expression since its value is only known at run-time.
Additionally in C++, a const variable initialized from a constant expression is also a constant expression. As an example:
void foo(int n) {
const double pi = 3.14285714; // constant expression
const int size = n; // not a constant expression
// other code here ...
}
read-only variable pi is a constant expression since it is initialized by a literal.
The following C++ code fragment
int const degree{4};
int poly[degree] {11,12,13,14};
establishes two levels of constancy for variable degree:
degree cannot be changed during program execution [just as in C], anddegree is a constant expression and can therefore be used to specify the size of a static array [unlike in C].Compare the following C program's behavior:
#include <stdio.h>
int main(void) {
int const value = 4;
int array[value] = {1, 2, 3, 4};
printf("%d\n", array[1]);
return 0;
}
with the behavior of this C++ program
#include <iostream>
int main() {
int const value {4};
int array[value] {1, 2, 3, 4};
std::cout << array[1] << "\n";
}
to deduce that a const variable initialized from a constant expression [such as const variable value] is also a constant expression only in C++ code but not in C code.
Clearly, a constant expression has several advantages:
Whether a given variable or expression is a constant expression depends on the types and initializers:
int square(int n) {
return n*n;
}
int main() {
int const max_files{20}; // max_files is a constant expression
int const limit {max_files}; // limit is a constant expression
int size{27}; // size is not a constant expression
int const sq_size{square(2)}; // sq_size is not a constant expression
// because the value of the initializer is not known until run-time
int array[square(2)]{1,2,3,4}; // illegal because square(2) is not a constant expression
std::cout << array[2] << "\n";
}
Since C+11, the standard has introduced a new keyword that allows programmers to specify that the value of a variable [such as size] or an expression [such square(2)] must be evaluated at compile-time. This keyword when used as a specifier for function square will enable the const variable sq_size to be a constant expression and thus allow the compiler to define the array array with size .
Read Section of the textbook to learn what this C++ keyword is and then write the exact keyword as your answer.
Recall from HLP1 that internal variables are variables that are defined in function blocks while external variables are variables that are defined outside of any function. By default, internal variables have internal linkage while external variables have external linkage. Internal linkage of a variable implies the compiler doesn't export the variable's name to the linker, while external linkage of a variable implies the compiler will export the variable's name to the linker. Thus, in contrast to internal variables, external variables defined in one source file are accessible to functions defined in other source files. Programmers can force external variables to have internal linkage by adding storage specifier keyword static to the definition of the external variable, as in:
static int global_variable;In C11, by default, read-only external variables [defined as read-only using type qualifier keyword const] have external linkage. Determine whether such read-only external variables have internal linkage or external linkage in C++ by examining the following C++ code in a source file:
#include <cstdio>
const int foo = 1;
int main() {
std::printf("%d\n", foo);
}
and the following code in a second source file:
const int foo = 4;Which of the following choices best reflects the output of compilation [only] of each of two source files and the linkage of the corresponding two object files?
A dynamic array is an array with dynamic storage duration. In C++, a dynamic array is created on the free store using an array new expression. If T is a type and n is a non-negative integral value, expression new T[n] allocates an array of n objects of type T and returns a pointer [which has type T*] to the initial element of the array. If T is a fundamental or built-in type the array elements are left uninitialized. If T is a user-defined type, then each element of the dynamic array is initialized by running its default constructor. As an example,
int *pi {new int[10]};will allocate memory for an array of int elements and cause pi to point to the first element. Since int is a fundamental type, the new expression doesn't initialize the dynamic array elements. The number of elements doesn’t need to be constant: the size of the array can be determined at runtime, meaning the value between brackets could be a variable rather than a literal.
To deallocate a dynamic array, use the array delete expression. Unlike the array new expression, the array delete expression doesn’t require a length:
delete [] pi;Like the delete expression, the array delete expression returns void.
Beginner C++ programmers make the common mistake of writing the following incorrect statement to allocate a matrix of rows and columns:
int *p2i {new int[5][6]}; // errorThe most efficient solution is to rely on the row-major order followed by C++ [and also by C] to conceptualize a two-dimensional array within the one-dimensional array of bytes comprising physical memory. For example, a two-dimensional array with rows and columns is conceptualized as a row-major ordered one-dimensional array of elements:
int *p2i {new int[5 * 6]};An element located at the intersection of row and column of the two-dimensional array is accessed by mapping the offset of this two-dimensional element within the one-dimensional array pointed to by p2i:
// offset of two-dimensional element at intersection of row y and column x
int offset = y*6 + x;
Now, read the following code fragment and determine the value written to standard output stream.
int const rows{3}, columns{4};
int *p2i { new int[rows*columns]{7,10,17,12,3,14,-5,16,18,19,11,8} };
int r{1}, c{3};
std::cout << *(p2i+r*columns+c);
C++ supports dynamic allocation of objects on the free store [or heap] using a new expression that begins with keyword new followed by the type of the object with dynamic storage duration. New expressions create objects of the given type on the free store and return a pointer to the newly minted object. If T is the type of an object, new T is an expression that allocates an uninitialized object of type T on the free store and yields a pointer to this [unnamed] newly allocated object. As an example,
int *p = new int;will allocate an unnamed and uninitialized object of type int, and cause p to point to that object. It is possible to give a specific value to use when initializing the object by executing the function-style expression new T(args) or the more modern uniform initialization expression new T{args}. As an example,
int *p = new int {42};will allocate an unnamed object of type int on the free store, initialize the unnamed object to , and cause p to point to that object.
C++ supports deallocation of a dynamic object using a delete expression, which is composed of keyword delete followed by a pointer to an object that was previously allocated by a new expression. A delete expression always returns void. To deallocate the object pointed to by p, you would use the following delete expression:
delete p;The value contained in memory where the deleted object resided is undefined, meaning the compiler can produce code that leaves anything there. In practice, compilers will try to be as efficient as possible, so typically the object’s memory will remain untouched until the program reuses it for other purposes.
Although new expressions and delete expressions seem to have the same functionality as C standard library functions malloc and free, respectively, they've multiple differences:
malloc just allocates the appropriate memory for storing the object. Fundamental data types have no constructors, so they will be default initialized meaning that the object is uninitialized and its value is undefined.malloc returns a pointer of type void*, so typecasting is required. For example if Ais an user-defined type, we define an object on the free store like this:
A *pa {new A};whereas the value returned by function
malloc must be typecast to type A*:
A *pb = static_cast<A*>(malloc(sizeof(A)));malloc signals failure [for example, when the program is out of heap memory] by returning a null pointer where as the new expression throws an exception that requires the programmer to use C++ exception handling mechanisms to avoid program termination.free does nothing more than return the previously allocated memory back to the heap, the delete expression will first call the destructor function of the object's type followed by returning the memory back to the heap.It should now be clear that C standard library functions malloc, calloc, realloc, and free must not be used in C++ programs except in exceptional cases. Such an exceptional scenario arises when a C++ program interfaces with an API that was implemented in C. Suppose the C++ program makes a call to an API function that returns a pointer pointing to dynamically allocated memory. [which presumably was allocated by the execution of function malloc]. To avoid memory leaks, the dynamically allocated memory must be returned to the free store. In this scenario, the only recourse available to the C++ program is to return the previously allocated dynamic memory back to the free store using C standard library function free.
If the following program doesn't compile, write . If the program has undefined behavior, write . If the program prints unspecified values to standard output, write . Otherwise, write the exact values written to the standard output stream.
#include <iostream>
#include <stdlib.h>
struct Vector {
int x, y, z;
Vector() : x{0}, y{0}, z{0} {} // default constructor
};
int main() {
Vector *pV {static_cast<Vector*>(malloc(sizeof(Vector)))};
std::cout << pV->x << pV->y << pV->z;
free(pV);
}
nullptr is a keyword introduced in C++11 and is meant to replace the use of both and C standard library macro NULL. Although integer literal is a valid value to assign to pointers, it is hard for human readers and automated debuggers to detect uses of in the context of initialization or assignment to pointers. The use of macro NULL is not type safe because the macro typecasts integer literal to either void* or int depending on the particular compiler.
In contrast to macro NULL or integer literal , keyword nullptr provides a type safe value representing an empty pointer.
Given the following definition
int *pi {nullptr};choose the best possible answer from the listed choices.
In C, we can have only a single name to specify an object. For example, the definition
int n;associates name n with a block of memory of size bytes. In C++, the concept of references allows us to associate multiple names to an object. For example, the first line of the following code fragment
int i{10};
int *pi{&i};
int &ri{i};
ri = 21;
std::cout << i << ' ' << ri << ' ' << *pi << '\n';
associates name i to an int object. Such a named object is called a variable. The second line defines a pointer variable pi and initializes it with the address of variable i. We can directly refer to the object using name i or indirectly refer to the object using expression *pi. The third definition introduces name ri as a reference to variable i. C++ uses the term reference to mean that name ri is an alias to name i: anywhere you can use name i, you can now use alias ri. That is, the object associated with named i has a second name ri associated with it. Therefore, the code fragment will write thrice to the standard output stream.
Although it seems that references are similar to pointers, they differ in several essential ways:
nullptr to a pointer variable].Although every reference must be initialized to refer to something, it is still possible to have a dangling reference. Dangling references arise when a reference is initialized to alias a dynamically allocated object which is then subsequently deleted. Consider the following code fragment:
int *pi = static_cast<int*>(malloc(sizeof(int)));
*pi = 10;
int &ri {*pi}; // ri is now an alias to unnamed object pointed to by pi
ri += 1; // update to 11 the value of object pointed to by pi
free(pi); // the object that pi is pointing to is no longer in existence!!!
// note that the physical memory still exists but not
// the dynamic object that was earlier given storage there
// therefore, ri is now a dangling reference
ri += 2; // undefined behavior
Which of the following code fragments do NOT compile?
The following code fragment defines a namespace named Lab in a C++ source file:
namespace Lab {
int id;
struct Vector {
int x,y,z;
};
} // notice the lack of a ; character after the closing curly brace!!!
The above code fragment resembles a C/C++ structure definition with both using curly braces to delimit scope and both declaring members, but they are quite different. Keyword struct is used to define an user-defined type that can be instantiated as an object stored in memory. On the other hand, keyword namespace is used to organize names [types, functions, variables] into logical groups to prevent name collisions. For example, namespace Lab adds scope Lab to the names id and Vector declared in that namespace. That is, the names declared in namespace Lab are distinct from similar names declared in both the global scope or in some other namespace such as namespace Lecture:
namespace Lecture {
int id; // this name will not clash with the name id declared in namespace Lab
struct Vector { // ditto
int x,y,z;
};
} // end namespace Lecture
Outside the namespace scope, members can be accessed by specifying a fully qualified name consisting of the namespace's name followed by the scope resolution operator :: and then followed by the member's name. Therefore, type Vector in namespace Lab will be accessed outside the namespace like this: Lab::Vector.
All names at namespace scope are visible to one another without qualification.
What is the output when function foo is invoked?
namespace A {
char c = 'a';
}
char c = 'b';
void foo() {
std::cout << A::c << c;
}
A structure in C is a user defined data type that can be used to group multiple values under one name. These individual values are called data members and they have different names and possibly different types.
A structure in C++ is a more complex data type that provides facilities to easily implement the concepts of data abstraction and encapsulation [that will be explained in future lectures]. In addition to data members, C++ structures can also contain type declarations and functions. Member functions of a C++ structure can be used by programmers to initialize, to retrieve, and modify the state of the data members of a variable of that structure type. For example, we can define a type Student like this:
#include <string>
struct Student {
std::string name; // string is C++ standard library type declared in <string> that represents a
// variable-length sequence of characters. This class allows us to handle C-style strings
// similar to values of type int
int id;
double gpa;
Student(std::string const& a_name, int an_id, double a_gpa) : name{a_name}, id{an_id}, gpa{a_gpa} { }
void GPA(double new_gpa) { gpa = new_gpa; } // 1st overloaded member function GPA called modifier member function
double GPA() const { return gpa; } // 2nd overloaded member function GPA called accessor member function
};
A member function with the same name as the structure type is called a constructor. The purpose of a constructor is to initialize the data members of an object.
The first overloaded member function GPA is called a modifier because it changes the value of data member gpa. The second overloaded member function GPA is called an accessor because it retrieves the current value of data member gpa.
What is the exact output written to standard output by the following code fragment?
Student s {"Bart", 98, 2.1};
std::cout << s.name << ' ' << s.id << ' ' << s.GPA();
C++ structures behave differently than C structures. The first difference is that C++ structures enable data abstraction and encapsulation [to be covered in subsequent weeks] by allowing both data [called data members] and functions [called member functions] to be defined inside the structure block.
There is an additional minor difference to know about structure types in C++ in comparison to C. Suppose, we've defined the following structure:
struct Vector {
int x, y, z;
};
Recall that in C, the type defined above is struct Vector and a variable of such a type would be defined like this:
struct Vector vec;In C++, you can define variables of similar type with or without keyword struct:
struct Vector vec1; // variable of type struct Vector
Vector vec2; // ditto
In practice, this is a superficial difference that leads to a little less typing of C++ code in comparison to C. Now, compile the following code using a C compiler and then a C++ compiler.
#include <stdio.h>
struct Vector {
int x, y, z;
};
int main(void) {
Vector v = {10, 20, 30};
printf("(%d, %d, %d)\n", v.x, v.y, v.z);
return 0;
}
Which of the following best reflects the output of these compilations?