0% found this document useful (0 votes)
15 views

Zain Computer Assignment

Uploaded by

zainhackr
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views

Zain Computer Assignment

Uploaded by

zainhackr
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

Assignment # 07

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: Complete the following function that adds up all the positive values in an integer vector. For
example, if vector vec contains the elements 3, -3, 5, 2, −1, and 2, the call sum_positive(vec) would
evaluate to 12, since 3 + 5 + 2 + 2 = 12. The function returns zero if the vector is empty. The function
does not affect the contents of the vector.

int sum_positive(const std::vector& v)

{ // Add your code... }

Ans: int sum_positive(const std::vector& v) {


int sum = 0;
for (const int& x : v) {
if (x > 0) {
sum += x;
}
}
return sum;
}

Q2: Complete the following function that counts the even numbers in an integer vector. For example, if
vector vec contains the elements 3, 5, 4, −1, and 0, the call count_evens(vec) would evaluate to 2, since
the vector contains two even numbers: 4 and 0. The function returns zero if the vector is empty. The
function does not affect the contents of the vector.

int count_evens(const std::vector& v)

{ // Add your code... }


Ans: int count_evens(const std::vector& v) {
int count = 0;
for (const int& x : v) {
if (x % 2 == 0) {
count++;
}
}
return count;
}

Q3: Complete the following function that counts the even numbers in a 2D vector of integers.

int count_evens(const std::vector<std::vector>& v)

{ // Add your code... }

Ans: int count_evens(const std::vector& v) {


int count = 0;
for (const std::vector<int>& row : v) {
for (const int& x : row) {
if (x % 2 == 0) {
count++;
}
}
}
return count;
}

Q4: Complete the following function that compares two integer vectors to see if they contain the same
elements in the same positions. The function returns true if the vectors are equal; otherwise, it returns
false. For example, if vector vec1 contains the elements 3, 5, 2, −1, and 2, and vector vec2 contains the
elements 3, 5, 2, −1, and 2, the call equals(vec1, vec2) would evaluate to true. If instead vector vec2
contains the elements 3, 2, 5, −1, and 2, the call equals (vec1, vec2) would evaluate to false (the second
and third elements are not in the same positions). Two vectors of unequal sizes cannot be equal. The
function does not affect the contents of the vectors.

bool equals(const std::vector& v1, const std::vector& v2)

{ // Add your code... }

Ans: bool equals(const std::vector& v1, const std::vector& v2) {


if (v1.size() != v2.size()) {
return false;
}
for (size_t i = 0; i < v1.size(); i++) {
if (v1[i] != v2[i]) {
return false;
}
}

return true;
}
Assignment # 08

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: Complete the following function that determines if all the elements in one vector also appear in
another. The function returns true if all the elements in the second vector also appear in the first;
otherwise, it returns false. For example, if vector vec1 contains the elements 3, 5, 2, −1, 7, and 2, and
vector vec2 contains the elements 5, 7, and 2, the call contains(vec1, vec2) would evaluate to true. If
instead vector vec2 contains the elements 3, 8, −1, and 2, the call contains(vec1, vec2) would evaluate
to false (8 does not appear in the first vector). Also If vector vec2 contains the elements 5, 7, 2, and 5,
the call contains(vec1, vec2) would evaluate to false (5 appears twice in vec2 but only once in vec1, so
vec1 does not contain all the elements that appear in vec2). The function does not affect the contents of
the vectors.

bool contains(const std::vector& v1, const std::vector& v2)

{ // Add your code... }

Ans: bool contains(const std::vector& v1, const std::vector& v2) {


for (const int& x : v2) {
if (std::find(v1.begin(), v1.end(), x) == v1.end()) {
return false;
}
}

return true;
}

This function is efficient because it only iterates over the vector v2 once. It is also correct because it
handles all possible cases, including empty vectors and vectors with different elements.
Here is an example of how to use the contains() function:

std::vector<int> v1 = {3, 5, 2, -1, 7, 2};


std::vector<int> v2 = {5, 7, 2};

bool contains_all = contains(v1, v2);

if (contains_all) {
std::cout << "The first vector contains all the elements of the second
vector." << std::endl;
} else {
std::cout << "The first vector does not contain all the elements of the
second vector." << std::endl;
}

Output:

The first vector contains all the elements of the second vector.

Q2: Suppose your task is to implement the function with the prototype

void proc(std::vector v);

When you implement the body of proc, how can you determine the size of vector v?

Ans: There are two ways to determine the size of a vector v in the C++ function void
proc(std::vector v):

1. Use the std::vector::size() member function. This function returns the number of elements in
the vector.

2. Use the v.size() expression. This is a shorthand for the std::vector::size() member function
call.

For example, the following code shows how to use the std::vector::size() member function to
determine the size of a vector:

void proc(std::vector v) {

int size = v.size();

// Do something with the size of the vector


}

The following code shows how to use the v.size() expression to determine the size of a vector:

void proc(std::vector v) {
int size = v.size();
// Do something with the size of the vector
}
Both methods are equivalent and can be used interchangeably.

Which method you choose to use is a matter of personal preference. Some programmers prefer to use
the std::vector::size() member function call because it is more explicit. Other programmers
prefer to use the v.size() expression because it is more concise.

Q3: Consider the declaration

std::vector<std::vector> collection(100, std::vector(200));

(a) What does the expression collection[15][29] represent?

(b) How many elements does collection hold?

(c) Write the C++ code that prints all the elements in collection. All the elements in the same row should
appear on the same line, and but each successive row should appear on its own line.

(d) What does the expression collection[15] represent?

Ans: (a) The expression collection[15][29] represents the 30th element in the 16th row of the 2D
vector collection. This is because the 2D vector is initialized with 100 rows, each containing 200
elements. The first element in the 16th row is at index 15, and the 30th element in the 16th row is at
index 29.

(b) The 2D vector collection holds 20,000 elements, because it has 100 rows, each containing 200
elements.

(c) The following C++ code prints all the elements in the 2D vector collection, with all the elements
in the same row appearing on the same line, and each successive row appearing on its own line:

#include <vector>

#include <iostream>

using namespace std;

void print_2d_vector(const vector<vector<int>>& v) {


for (size_t i = 0; i < v.size(); i++) {
for (size_t j = 0; j < v[i].size(); j++) {
cout << v[i][j] << " ";
}
cout << endl;
}
}
int main() {
vector<vector<int>> collection(100, vector<int>(200));

// Initialize the 2D vector with some values


for (size_t i = 0; i < collection.size(); i++) {
for (size_t j = 0; j < collection[i].size(); j++) {
collection[i][j] = i + j;
}
}

// Print all the elements in the 2D vector


print_2d_vector(collection);

return 0;
}

Output:

0 1 2 3 ... 199
1 2 3 4 ... 200
2 3 4 5 ... 201
...
99 100 101 102 ... 298

(d) The expression collection[15] represents a reference to the 16th row in the 2D vector
collection. This is because the first row in the 2D vector is at index 0, and the 16th row is at index 15.

You can then use the collection[15] reference to access all the elements in the 16th row of the 2D
vector. For example, the following code prints all the elements in the 16th row of the 2D vector
collection:

#include <vector>

#include <iostream>

using namespace std;

int main() {
vector<vector<int>> collection(100, vector<int>(200));

// Initialize the 2D vector with some values


for (size_t i = 0; i < collection.size(); i++) {
for (size_t j = 0; j < collection[i].size(); j++) {
collection[i][j] = i + j;
}
}

// Print all the elements in the 16th row of the 2D vector


for (size_t i = 0; i < collection[15].size(); i++) {
cout << collection[15][i] << " ";
}
cout << endl;
return 0;
}

Output: 15 16 17 18 ... 214


Q4: Consider the declaration std::vector<std::vector<std::vector<std::vector>>>mesh(100,std::vect
or(200, std::vector(100, std::vector(50)))); How many elements does mesh hold?

Ans: The 4D vector mesh has 100×200×100×50=1,000,000,000 elements.

This is because the 4D vector is initialized with 100 rows, each containing 200 rows, each containing 100
rows, each containing 50 elements.
Assignment # 09

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: How is a C++ array different from a vector?

Ans: C++ arrays are static data structures, meaning that their size must be known at compile time. Once
an array is allocated, its size cannot be changed. Arrays are stored in contiguous memory locations,
which makes them efficient for accessing and manipulating elements.

C++ vectors are dynamic data structures, meaning that their size can grow and shrink as needed. Vectors
are also stored in contiguous memory locations, but they can be resized at any time. This makes vectors
more flexible than arrays, but it can also make them less efficient for accessing and manipulating
elements.

Here is a table that summarizes the key differences between C++ arrays and vectors:

Feature Array Vector

Size Static Dynamic

Resizability No Yes

Memory
Manual Automatic
allocation
Element Less
Efficient
access efficient

Q2: What advantages does a C++ vector provide over an array?

Ans: C++ vectors provide a number of advantages over arrays, including:

 Dynamic size: Vectors can grow and shrink as needed, while arrays must have a fixed size at compile
time. This makes vectors more flexible and easier to use.
 Automatic memory management: Vectors automatically allocate and deallocate memory as needed,
while arrays must be manually managed. This can help to prevent memory leaks and other errors.
 Iterators: Vectors provide iterators, which are objects that make it easy to traverse and manipulate the
elements in a vector. Arrays do not provide iterators, so you must use manual pointer arithmetic to
access and modify the elements.
 Standard library support: Vectors are part of the C++ standard library, which means that they are widely
supported and well-tested. Arrays are not part of the standard library, so they may not be as well-
supported or tested.

Here is a table that summarizes the key advantages of C++ vectors over arrays:

Feature Vector Array

Dynamic size Yes No

Automatic memory management Yes No

Iterators Yes No

Standard library support Yes No

Q3: Provide the statement(s) that declares and create a static array named a that can hold 20 integers.

Ans: To declare and create a static array named a that can hold 20 integers, you can use the following
statement:
int a[20];
This statement declares an array named a of type int with a size of 20 elements. The array is static,
meaning that its size is fixed at compile time.

The following example shows how to use the a array:

int a[20];

// Initialize the array


for (int i = 0; i < 20; i++) {
a[i] = i;
}

// Print the contents of the array


for (int i = 0; i < 20; i++) {
std::cout << a[i] << " ";
}
std::cout << std::endl;

Output:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Note that static arrays are not as flexible as dynamic arrays, such as std::vector. However, they can
be more efficient for some applications.

Q4: Provide the statement(s) that declare and create a dynamic array named a that can hold 20 integers.

Ans: To declare and create a dynamic array named a that can hold 20 integers, you can use the following
statement:

std::vector<int> a(20);

This statement declares a dynamic array named a of type std::vector<int> with a size of 20
elements. The array is dynamic, meaning that its size can grow and shrink as needed.

The following example shows how to use the a array:

std::vector<int> a(20);

// Initialize the array


for (int i = 0; i < 20; i++) {
a[i] = i;
}

// Print the contents of the array


for (int i = 0; i < 20; i++) {
std::cout << a[i] << " ";
}
std::cout << std::endl;

Output:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Note that dynamic arrays are more flexible than static arrays, but they can be less efficient for some
applications.

Here is a comparison of static and dynamic arrays:

Feature Static array Dynamic array

Can grow and shrink as


Size Fixed at compile time
needed

Must be managed Automatic memory


Memory management
manually management

Iterators No Yes

Standard library
No Yes
support

Q5: What extra attention does a programmer need to give to a static array when its use within a
program is finished?

Ans: Static arrays are allocated on the stack when a program is running. When the program finishes
running, the stack is automatically unwound and the static arrays are deallocated. This means that
programmers do not need to explicitly deallocate static arrays when they are finished using them.

However, there are a few things that programmers should keep in mind when using static arrays:

 Static arrays should not be accessed outside of the scope in which they are declared. This is because
static arrays are deallocated when the program finishes running, and accessing a deallocated array will
result in undefined behavior.
 Static arrays should not be used to store data that needs to persist after the program finishes running.
This is because static arrays are deallocated when the program finishes running, and any data stored in
them will be lost.
 Static arrays should not be used to store large amounts of data. This is because static arrays are
allocated on the stack, and the stack has a limited size. Using large static arrays can lead to stack
overflows.

In general, programmers should avoid using static arrays unless they are absolutely necessary. Dynamic
arrays, such as std::vector, are a more flexible and reliable choice for most applications.

Here are some tips for using static arrays safely:

 Avoid accessing static arrays outside of the scope in which they are declared.
 Avoid using static arrays to store data that needs to persist after the program finishes running.
 Avoid using static arrays to store large amounts of data.

If you need to use a static array, make sure to use it carefully and be aware of the potential risks.

Q6: What extra attention does a programmer need to give to a dynamic array when its use within a
program is finished?

Ans: Dynamic arrays, such as std::vector, are allocated on the heap when a program is running. The
heap is a region of memory that is managed by the operating system. When a dynamic array is no longer
needed, it must be explicitly deallocated by the programmer.

To deallocate a dynamic array, you can use the std::vector::clear() and


std::vector::shrink_to_fit()methods.The std::vector::clear() method removes all the
elements from the vector, but it does not deallocate the underlying memory. The
std::vector::shrink_to_fit() method deallocates any unused memory that is allocated to the
vector.

It is important to deallocate dynamic arrays when they are finished being used to prevent memory leaks.
Memory leaks occur when memory is allocated to a dynamic array but is never deallocated. This can
lead to performance problems and even crashes.

Here are some tips for using dynamic arrays safely:

 Always deallocate dynamic arrays when they are finished being used.
 You can use the std::vector::clear() and std::vector::shrink_to_fit() methods to
deallocate dynamic arrays.
 Be aware of the potential for memory leaks if you do not properly deallocate dynamic arrays.

Here is an example of how to safely use a dynamic array:


std::vector<int> a(20);

// Initialize the array


for (int i = 0; i < 20; i++) {
a[i] = i;
}

// Use the array

// When finished using the array, deallocate it


a.clear();
a.shrink_to_fit();

By following these tips, you can help to prevent memory leaks and ensure that your programs are
efficient and reliable.

Q7: What extra attention does a programmer need to give to a vector array when its use within a program
is finished?

Ans: To properly deallocate a vector array in C++, you can use the following steps:

1. Call the std::vector::clear() method to remove all the elements from the vector. This does not
deallocate the underlying memory, but it does make the vector empty.

2. Call the std::vector::shrink_to_fit() method to deallocate any unused memory that is


allocated to the vector.

It is important to deallocate vector arrays when they are finished being used to prevent memory leaks.
Memory leaks occur when memory is allocated to a vector array but is never deallocated. This can lead
to performance problems and even crashes.

Here is an example of how to safely deallocate a vector array:

std::vector<int> a(20);

// Initialize the array


for (int i = 0; i < 20; i++) {
a[i] = i;
}

// Use the array

// When finished using the array, deallocate it


a.clear();
a.shrink_to_fit();

Additional attention:
In addition to deallocating vector arrays, programmers should also avoid accessing them outside of the
scope in which they are declared. This is because vector arrays are deallocated when they go out of
scope, and accessing a deallocated vector array will result in undefined behavior.

Programmers should also avoid using vector arrays to store data that needs to persist after the program
finishes running. This is because vector arrays are deallocated when the program finishes running, and
any data stored in them will be lost.

Finally, programmers should avoid using vector arrays to store large amounts of data. This is because
vector arrays are allocated on the heap, and the heap has a limited size. Using large vector arrays can
lead to heap overflows.

By following these tips, programmers can help to prevent memory leaks, avoid undefined behavior, and
ensure that their programs are efficient and reliable.

Q8: Consider the following function that processes the elements of an array using a range:

bool proc(const int *begin, const int *end)

{ // Details omitted . . . }

and an array and vector declared as shown here:

int a[10]; std::vector v;

(a) Provide the statement that correctly calls proc with array a.

(b) Provide the statement that correctly calls proc with vector v.

Ans: (a) To correctly call the function proc() with the array a, we can use the following statement:

proc(a, a + 10);

This statement passes the beginning and ending pointers of the array a to the function proc().The a +
10 expression points to the element past the last element in the array a.

(b) To correctly call the function proc() with the vector v, we can use the following statement:

proc(v.data(), v.data() + v.size());

The v.data() expression returns a pointer to the first element in the vector v. The v.data() +
v.size() expression points to the element past the last element in the vector v.

Here is an example of how to use the function proc() with the array a and the vector v:
int a[10];

std::vector v;

// Initialize the array and vector


for (int i = 0; i < 10; i++) {
a[i] = i;
v.push_back(i);
}

// Process the elements of the array and vector using the proc() function
proc(a, a + 10);
proc(v.data(), v.data() + v.size());

Q9: Can you declare an array to hold a mixture of ints and doubles?

Ans: No, you cannot declare an array to hold a mixture of ints and doubles in C++. C++ is a statically
typed language, which means that the type of each variable must be known at compile time. This also
applies to arrays.

If you need to store a mixture of ints and doubles, you can use a struct or a union. A struct is a data
structure that can contain multiple members of different types. A union is a data structure that can
contain only one member at a time, but the member can be of any type.

Here is an example of how to use a struct to store a mixture of ints and doubles:

struct MyData {

int i;
double d;
};

MyData data[10];

// Initialize the array


data[0].i = 1;
data[0].d = 2.0;

// Access the elements of the array


int i = data[0].i;
double d = data[0].d;

Here is an example of how to use a union to store a mixture of ints and doubles:

union MyData {
int i;
double d;
};
MyData data[10];

// Initialize the array


data[0].i = 1;

// Access the elements of the array


int i = data[0].i;
double d = data[0].d; // This will access the value of i, even though it was
initialized as an int.

Which data structure you choose to use depends on your specific needs. If you need to access the
elements of the data structure individually, then you should use a struct. If you only need to access the
data structure as a whole, then you can use a union.

It is important to note that using a union to store a mixture of ints and doubles can be dangerous, as it is
easy to accidentally access the wrong type of data. It is generally recommended to use a struct instead.

Q10: What happens if you attempt to access an element of an array using a negative index?

Ans: If you attempt to access an element of an array using a negative index in C++, the behavior is
undefined. This means that anything can happen, including program crashes, data corruption, and
unexpected results.

The reason for this is that arrays are stored in memory in contiguous blocks. When you access an
element of an array using a positive index, the compiler calculates the address of the element based on
the offset from the beginning of the array. However, when you use a negative index, the compiler
cannot calculate the address of the element correctly.

Here is an example of what can happen if you attempt to access an element of an array using a negative
index:

int a[10];

// Attempt to access the element at index -1


int i = a[-1];

This code will most likely crash the program, but it is also possible that it will corrupt the data in the
array or produce unexpected results.

Q11: Given the declaration.

int list[100];

(a) What expression represents the very first element of list?

(b) What expression represents the very last element of list?


(c) Write the code fragment that prints out the contents of list.

(d) Is the expression list[3.0] legal or illegal.

Ans: (a) What expression represents the very first element of list?

The expression list[0] represents the very first element of the array list. This is because the first
element of an array in C++ has index 0.

(b) What expression represents the very last element of list?

The expression list[99] represents the very last element of the array list. This is because the last
element of an array in C++ has index list.size() - 1, where list.size() is the number of
elements in the array.

(c) Write the code fragment that prints out the contents of list.

The following code fragment prints out the contents of the array list:

for (int i = 0; i < 100; i++) {


std::cout << list[i] << " ";
}
std::cout << std::endl;

This code fragment uses a for loop to iterate over the elements of the array list and print each element
to the console.

(d) Is the expression list[3.0] legal or illegal?

The expression list[3.0] is illegal. Array indices must be integers, and 3.0 is a floating point number.
Therefore, the compiler will generate an error if you try to compile this code.

Here is an example of a legal expression for accessing an element of the array list:

int i = list[3];

This expression will access the element at index 3 of the array list.

Q12: Is the following code fragment legal or illegal?

int list1[5], list2[5] = { 3, 3, 3, 3, 3 }; list1 = list2;


Ans: The following code fragment is illegal:

int list1[5], list2[5] = { 3, 3, 3, 3, 3 };


list1 = list2;

This is because arrays are not assignable in C++. You cannot assign one array to another.

To copy the contents of one array to another, you can use a for loop to iterate over the elements of the
first array and copy them to the second array. Here is an example:

for (int i = 0; i < 5; i++) {


list1[i] = list2[i];
}

This code fragment will copy the contents of the array list2 to the array list1.

Another way to copy the contents of one array to another is to use the std::copy() function. The
std::copy() function copies a range of elements from one source container to another destination
container. Here is an example:

#include <algorithm>

std::copy(list2, list2 + 5, list1);

This code fragment will use the std::copy() function to copy the contents of the array list2 to the
array list1.

Q13: Provide a single declaration statement that declares an integer array named list that contains the
values 45, −3, 16 and 8?

Ans: The following single declaration statement declares an integer array named list that contains the
values 45, −3, 16 and 8:

int list[] = {45, -3, 16, 8};

This statement declares an array named list of type int with four elements. The elements of the
array are initialized to the values 45, −3, 16, and 8, respectively.
Assignment # 10

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: Does an array keep track of the number of elements it contains?

Ans: Yes, an array keeps track of the number of elements it contains. This is because arrays are stored in
contiguous blocks of memory. When an array is created, the compiler allocates a block of memory that
is large enough to store the specified number of elements. The compiler also keeps track of the address
of the first element in the array and the size of the array in bytes.

To access an element of an array, the compiler uses the following formula:

element_address = array_address + (index * element_size)

where:

 element_address is the address of the element to be accessed

 array_address is the address of the first element in the array

 index is the index of the element to be accessed

 element_size is the size of an element in bytes


Q2: Complete the following function that adds up all the positive values in an array of integers. For
example, if array arr contains the elements 3, -3, 5, 2, −1, and 2, the call sum_positive(arr) would evaluate
to 12, since 3 + 5 + 2 + 2 = 12. The function returns zero if the array is empty (that is, n < 1).

// Array a with length n

int sum_positive(const int *a, int n)

{ // Add your code... }

Ans: Here is a complete implementation of the sum_positive() function:

int sum_positive(const int *a, int n) {


// Check if the array is empty
if (n < 1) {
return 0;
}

// Initialize the sum


int sum = 0;

// Iterate over the elements of the array and add up all the positive
values
for (int i = 0; i < n; i++) {
if (a[i] > 0) {
sum += a[i];
}
}

// Return the sum


return sum;
}

This function works by first checking if the array is empty. If the array is empty, the function returns
zero. Otherwise, the function initializes a variable sum to zero and then iterates over the elements of
the array. For each element in the array, the function checks if the element is positive. If the element is
positive, the function adds the element to the variable sum.

After iterating over all the elements of the array, the function returns the variable sum. This is the sum
of all the positive values in the array.

Here is an example of how to use the sum_positive() function:

int main() {
int arr[] = {3, -3, 5, 2, -1, 2};
int n = sizeof(arr) / sizeof(arr[0]);

// Calculate the sum of all the positive values in the array


int sum = sum_positive(arr, n);
// Print the sum
std::cout << "The sum of all the positive values in the array is " << sum
<< std::endl;

return 0;
}

Output:

The sum of all the positive values in the array is 12.

Q3: Complete the following function that sums the even numbers in an array of integers. For example, if
array arr contains the elements 3, 5, 2, −1, and 2, the call sum_evens(arr) would evaluate to 4, since 2 +
2 = 4. The function returns zero if the array is empty (that is, n < 1). The function does not affect the
contents of the array.

// Array a with length n

int sum_evens(const int *a, int n)

{ // Add your code... }

Ans: Here is a complete implementation of the sum_evens() function:

int sum_evens(const int *a, int n) {


// Check if the array is empty
if (n < 1) {
return 0;
}

// Initialize the sum


int sum = 0;

// Iterate over the elements of the array and add up all the even values
for (int i = 0; i < n; i++) {
if (a[i] % 2 == 0) {
sum += a[i];
}
}

// Return the sum


return sum;
}

This function works by first checking if the array is empty. If the array is empty, the function returns
zero. Otherwise, the function initializes a variable sum to zero and then iterates over the elements of
the array. For each element in the array, the function checks if the element is even. If the element is
even, the function adds the element to the variable sum.
After iterating over all the elements of the array, the function returns the variable sum. This is the sum
of all the even values in the array.

Q4: Suppose your task is to implement the function with the prototype

void proc(int a[]);

When you implement the body of proc, how can you determine the size of array a?

Ans: The function with the prototype void proc(int a[]) takes an array of integers as input and does
not return any value. This means that the function can perform any operation on the array, but it cannot
change the size of the array.

Here is an example of a function implementation for void proc(int a[]):

void proc(int a[]) {

// Print the elements of the array in reverse order


for (int i = sizeof(a) / sizeof(a[0]) - 1; i >= 0; i--) {
std::cout << a[i] << " ";
}
std::cout << std::endl;
}

This function uses a for loop to iterate over the elements of the array in reverse order. For each element
in the array, the function prints the element to the console.

There are two ways to determine the size of an array a in the body of the function proc() with the
prototype void proc(int a[]);:

1. Using the sizeof() operator: The sizeof() operator returns the size of a variable or data type in
bytes. To determine the size of the array a in the body of the function proc(), you can use the
following expression:

sizeof(a) / sizeof(a[0])

This expression will return the number of elements in the array a.

2. Using the pointer arithmetic: You can also use pointer arithmetic to determine the size of the array a. To
do this, you can use the following steps:

3. Declare a pointer variable p and initialize it to the address of the first element in the array a.
4. Increment the pointer variable p until it points to the element past the last element in the array a.

5. The difference between the pointer variables p and a will be the size of the array a in bytes.

Q5: Consider the declaration

int collection[100][200];

What does the expression collection[15][29] represent?

Ans: The expression collection[15][29] represents the element at row 15 and column 29 of the
two-dimensional array collection. This array has 100 rows and 200 columns, so the element at row
15 and column 29 is the 3000th element in the array.

To access an element of a two-dimensional array, you use two indices: one for the row and one for the
column. The first index specifies the row number and the second index specifies the column number.
The indices start at 0, so the element at row 15 and column 29 is accessed using the indices 15 and 29,
respectively.

Q6: Consider the declaration int collection[100][200];

How many elements does collection hold?

Ans: The array collection has 100 rows and 200 columns, so it has 100 * 200 = 20000 elements.

To calculate the number of elements in a two-dimensional array, you multiply the number of rows by
the number of columns. This is because each element in a two-dimensional array is identified by a
unique pair of indices: one for the row and one for the column.

Q7: Consider the declaration int collection[100][200]; Write the C++ code that prints all the elements in
collection. All the elements in the same row should appear on the same line, but each successive row
should appear on its own line.

Ans: To print all the elements in the two-dimensional array collection in C++, you can use the following
code:
for (int i = 0; i < 100; i++) {
for (int j = 0; j < 200; j++) {
std::cout << collection[i][j] << " ";
}
std::cout << std::endl;
}

This code snippet uses two nested for loops to iterate over the rows and columns of the array. The inner
for loop iterates over the elements in each row, and the outer for loop iterates over the rows.

For each element in the array, the code snippet prints the element to the console and then prints a
space. After printing all the elements in a row, the code snippet prints a newline character.

This will print all the elements in the array collection in a tabular format, with each row appearing
on its own line.

Here is an example of the output of this code snippet:

1 2 3 4
5 6 7 8
9 10 11 12
...
19997 19998 19999 20000

Q8: Consider the declaration int collection[100][200]; What does the expression collection[15] represent?

Ans: The expression collection[15] does not represent anything valid in C++. Arrays in C++ are
indexed starting from 0, so the largest valid index for an array of size 100 is 99. Trying to access an element
of an array using an out-of-bounds index will result in undefined behavior.

In practice, this could mean anything from the program crashing to returning unexpected results. It is
important to avoid accessing arrays using out-of-bounds indices.

Q9: Consider the declaration int mesh[100][200][100][50]; How many elements does mesh hold?

Ans: The four-dimensional array mesh has dimensions 100 x 200 x 100 x 50, so it has 100 * 200 * 100 *
50 = 100000000 elements.

To calculate the number of elements in a multidimensional array, you multiply the dimensions together.
This is because each element in a multidimensional array is identified by a unique set of indices: one for
each dimension.

Q10: Rewrite the following expressions using pointer notation instead of array notation.
(a) a[4]

(b) a[1]

(c) a[0]

Ans: To rewrite the following expressions using pointer notation instead of array notation:

(a) a[4]
(b) a[1]
(c) a[0]

We can use the following pointer arithmetic expressions:

(a) *(a + 4)

(b) *(a + 1)

(c) *a

This is because the expression a[i] is equivalent to the expression *(a + i), where a is a pointer to
the first element of the array and i is the index of the element.

Q11: Rewrite the following expressions using array notation instead of pointer notation.

(a) *(a + 3)

(b) *a

(c) *(a + 0)

Ans: To rewrite the following expressions using array notation instead of pointer notation:
(a) *(a + 3)

(b) *a

(c) *(a + 0)

We can use the following array notation expressions:

(a) a[3]

(b) a[0]

(c) a[0]
This is because the expression *(a + i) is equivalent to the expression a[i], where a is a pointer to
the first element of the array and i is the index of the element.

Q12: Rewrite the following code fragment using array notation instead of pointer notation:

void display(int *a, int n)

{ while (n)

{ std::cout << *a << " "; a++; n--; }

std::cout << '\n'; }

Ans: To rewrite the following code fragment using array notation instead of pointer notation.

We can use the following array notation code fragment:

void display(int a[], int n) {


for (int i = 0; i < n; i++) {
std::cout << a[i] << " ";
}
std::cout << '\n';
}

This code fragment is equivalent to the original code fragment, but it uses array notation instead of
pointer notation.

Q13: Rewrite the following code fragment using pointer notation instead of array notation:

int sum(int *a, int n)

{ int s = 0;

for (int i = 0; i < n; i++)

s += a[i]; return s; }

Ans: To rewrite the following code fragment using pointer notation instead of array notation.

We can use the following pointer notation code fragment:

int sum(int *a, int n) {


int s = 0;
while (n--) {
s += *a++;
}
return s;
}

This code fragment is equivalent to the original code fragment, but it uses pointer notation instead of
array notation.

Q14: Given the following declarations which appear in a function body:

double nums[100], *grid = new double[100];

(a) Where will the elements of the nums array live—static memory, the stack, or the heap?

(b) Where will the elements of the grid array live—static memory, the stack, or the heap?

Ans: The elements of the nums array will live in static memory, while the elements of the grid array will
live in the heap.

Static memory is the memory that is allocated to the program when it is compiled and loaded into
memory. It is used to store global variables and static variables.

Dynamic memory is the memory that is allocated to the program at runtime. It is used to store dynamic
arrays, objects, and other data structures that need to be allocated and deallocated on the fly.

The nums array is a static array, which means that it is declared with a fixed size. It is also initialized with
values, which means that it will be allocated memory when the program is compiled and loaded into
memory. Therefore, the elements of the nums array will live in static memory.

The grid array is a dynamic array, which means that its size is not fixed. It is allocated memory at
runtime using the new operator. Therefore, the elements of the grid array will live in the heap.

Q15: What operator should eventually be used when the new operator is used to allocate memory? What
is the consequence of its omission?

Ans: When the new operator is used to allocate memory, the delete operator should eventually be used
to free up that memory. Otherwise, the memory will leak.

Memory leaks can occur when memory is allocated but not freed. This can happen if the delete
operator is not called explicitly, or if the pointer to the allocated memory is lost.

Memory leaks can cause a number of problems, including:


 Reduced performance: Memory leaks can cause the program to run slower, because the operating
system has to spend more time managing memory.
 Increased memory usage: Memory leaks can cause the program to use more memory than necessary,
which can lead to crashes or other problems.
 System instability: Memory leaks can cause the operating system to become unstable, which can lead to
crashes or other problems.

Therefore, it is important to always call the delete operator when freeing up memory that was
allocated with the new operator.

Q16: List some common errors programmers make when dealing with dynamic memory.

Ans: Some common errors programmers make when dealing with dynamic memory include:

 Forgetting to free memory: When memory is allocated dynamically, it must also be freed explicitly. If
you forget to free memory, it will leak. Memory leaks can lead to performance problems and system
instability.
 Using the wrong deallocation operator: The new operator is used to allocate memory dynamically, and
the delete operator is used to free it. It is important to use the correct deallocation operator for the
type of memory that was allocated. For example, if you use the new[] operator to allocate memory for a
dynamic array, you must use the delete[] operator to free it.
 Accessing memory after it has been freed: Once memory has been freed, it should not be accessed
again. Accessing freed memory can lead to undefined behavior, such as program crashes.
 Using dangling pointers: A dangling pointer is a pointer that points to memory that has been freed.
Dereferencing a dangling pointer can lead to undefined behavior, such as program crashes.
 Using invalid memory addresses: If you try to access memory using an invalid memory address, this can
lead to undefined behavior, such as program crashes.

Q17: Complete the following function that counts the number of negative values in a 10 × 10 integer 2D
array.

int count_negatives(int a[10][10])

{ // Add your code... }

Ans: To complete the function count_negatives() that counts the number of negative values in a 10
× 10 integer 2D array, we can use the following code:
int count_negatives(int a[10][10]) {
// Initialize a counter to store the number of negative values
int count = 0;

// Iterate over the rows and columns of the array


for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
// If the element at the current row and column is negative, increment
the counter
if (a[i][j] < 0) {
count++;
}
}
}

// Return the counter


return count;
}

This function works by iterating over the rows and columns of the array and checking each element. If
the element is negative, the function increments the counter. After iterating over the entire array, the
function returns the counter value.
Assignment # 11

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: Complete the following function that reorders the contents of a vector so they are reversed from their
original order. For example, a vector containing the elements 2, 6, 2, 5, 0, 1, 2, 3 would be transformed
into 3, 2, 1, 0, 5, 2, 6, 2. Note that your function must physically rearrange the elements within the vector,
not just print the elements in reverse order.

void reverse(std::vector& v)

{ // Add your code... }

Ans: To complete the function reverse() that reorders the contents of a vector so they are reversed
from their original order, we can use the following code:
void reverse(std::vector& v) {
// Get the length of the vector.
int n = v.size();

// Iterate over the vector, swapping the elements at the beginning and end.
for (int i = 0; i < n / 2; i++) {
std::swap(v[i], v[n - i - 1]);
}
}

This function works by iterating over the vector and swapping the elements at the beginning and end.
This process continues until the middle of the vector is reached. At this point, all of the elements in the
vector have been swapped and the vector is reversed.
Q2: Complete the following function that reorders the contents of a vector so that all the even numbers
appear before any odd number. The even values are sorted in ascending order with respect to
themselves, and the odd numbers that follow are also sorted in ascending order with respect to
themselves. For example, a vector containing the elements 2, 1, 10, 4, 3, 6, 7, 9, 8, 5 would be
transformed into 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 Note that your function must physically rearrange the
elements within the vector, not just print the elements in reverse order.

void special_sort(std::vector& v)

{ // Add your code... }

Ans: To complete the function special_sort() that reorders the contents of a vector so that all the
even numbers appear before any odd number, with the even values sorted in ascending order with
respect to themselves and the odd numbers that follow also sorted in ascending order with respect to
themselves, we can use the following code:

void special_sort(std::vector& v) {
// Initialize two vectors to store the even and odd numbers.
std::vector<int> even_numbers;
std::vector<int> odd_numbers;

// Iterate over the vector and partition the elements into the even and odd
vectors.
for (int i = 0; i < v.size(); i++) {
if (v[i] % 2 == 0) {
even_numbers.push_back(v[i]);
} else {
odd_numbers.push_back(v[i]);
}
}

// Sort the even and odd vectors in ascending order.


std::sort(even_numbers.begin(), even_numbers.end());
std::sort(odd_numbers.begin(), odd_numbers.end());

// Clear the original vector and append the even and odd vectors to it.
v.clear();
v.insert(v.end(), even_numbers.begin(), even_numbers.end());
v.insert(v.end(), odd_numbers.begin(), odd_numbers.end());
}

This function works by first partitioning the elements of the vector into two vectors: one for the even
numbers and one for the odd numbers. Then, the two vectors are sorted in ascending order. Finally, the
original vector is cleared and the even and odd vectors are appended to it.

Q3: Complete the following function that shifts all the elements of a vector backward one place. The last
element that gets shifted off the back end of the vector is copied into the first (0th) position. For example,
if a vector containing the elements 2, 1, 10, 4, 3, 6, 7, 9, 8, 5 is passed to the function, it would be
transformed into 5, 2, 1, 10, 4, 3, 6, 7, 9, 8 Note that your function must physically rearrange the elements
within the vector, not just print the elements in the shifted order.

void rotate(std::vector& v)

{ // Add your code... }

Ans: To complete the following function that shifts all the elements of a vector backward one place, with
the last element that gets shifted off the back end of the vector copied into the first (0th) position, we can
use the following code:
void rotate(std::vector& v) {
// Get the last element of the vector.
int last_element = v.back();

// Remove the last element of the vector.


v.pop_back();

// Insert the last element at the beginning of the vector.


v.insert(v.begin(), last_element);
}

This function works by first getting the last element of the vector. Then, it removes the last element of
the vector. Finally, it inserts the last element at the beginning of the vector.
Assignment # 12

Name : Zain Rashid


Roll Num : FA22-BEE-044
Section : B
Semester : 2nd
Course Title: Programming Fundamentals Lab
Department of Electrical Engineering

Apply the acquired programming knowledge of Sequences to solve the following


problems.

Q1: Complete the following function that determines if the number of even and odd values in a vector is
the same. The function will return true if the vector contains 5, 1, 0, 2 (two evens and two odds), but it
would return false for the vector containing 5, 1, 0, 2, 11 (too many odds). The function should return true
if the vector is empty, since an empty vector contains the same number of evens and odds (0). The
function does not affect the contents of the vector.

bool balanced(const std::vector& v)

{ // Add your code... }

Ans: To complete the following function that determines if the number of even and odd values in a
vector is the same, we can use the following code:

bool balanced(const std::vector& v) {


// Initialize a counter to store the number of even and odd values.
int even_count = 0;
int odd_count = 0;

// Iterate over the vector and count the number of even and odd values.
for (auto element : v) {
if (element % 2 == 0) {
even_count++;
} else {
odd_count++;
}
}

// Return true if the number of even and odd values is the same.
return even_count == odd_count;
}

This function works by first initializing two counters to store the number of even and odd values. Then, it
iterates over the vector and counts the number of even and odd values. Finally, it returns true if the
number of even and odd values is the same.

Q2: Complete the following function that returns true if vector a contains duplicate elements; it returns
false if all the elements in a are unique. For example, the vector 2, 3, 2, 1, 9 contains duplicates (2 appears
more than once), but the vector 2, 1, 0, 3, 8, 4 does not (none of the elements appear more than once).
An empty vector has no duplicates. The function does not affect the contents of the vector.

bool has_duplicates(const std::vector& v)

{ // Add your code... }

Ans: To complete the following function that returns true if vector a contains duplicate elements; it
returns false if all the elements in a are unique, we can use the following code:
bool has_duplicates(const std::vector& v) {
// Create a set from the vector.
std::set<int> s(v.begin(), v.end());

// If the length of the set is not equal to the length of the vector, then
there are duplicate elements in the vector.
return s.size() != v.size();
}

This function works by first creating a set from the vector. A set is a data structure that stores unique
elements. If the length of the set is not equal to the length of the vector, then there are duplicate
elements in the vector.

Q3: Can binary search be used on an unsorted vector? Why or why not?

Ans: No, binary search cannot be used on an unsorted vector. Binary search works by repeatedly dividing
the search space in half until the target element is found. This requires that the elements in the search
space be sorted in ascending order. If the elements are not sorted, then the binary search algorithm will
not be able to find the target element correctly.

For example, consider the following unsorted vector:

[5, 3, 2, 1, 4]

If we try to search for the element 4 using binary search, the algorithm will start by dividing the search
space in half, giving us the following two subvectors:
[5, 3, 2, 1]
[4]

The algorithm will then compare the target element 4 with the middle element of the first subvector,
which is 2. Since 4 is greater than 2, the algorithm will discard the first subvector and focus on the
second subvector.

The algorithm will then compare the target element 4 with the middle element of the second subvector,
which is 4. Since the target element is equal to the middle element, the algorithm will return the index
of the middle element, which is 1.

However, the element 4 is actually at index 4 in the original vector. This is because the binary search
algorithm assumed that the vector was sorted in ascending order, but it is not.

Therefore, binary search cannot be used on an unsorted vector. If you need to search for an element in
an unsorted vector, you can use a linear search algorithm, which compares the target element to each
element in the vector until it is found.

Q4: Can linear search be used on an unsorted vector? Why or why not?

Ans: Yes, linear search can be used on an unsorted vector. Linear search is a simple algorithm that works
by comparing the target element to each element in the vector until it is found. Since linear search does
not require the vector to be sorted, it can be used on unsorted vectors.

For example, consider the following unsorted vector:

[5, 3, 2, 1, 4]

If we try to search for the element 4 using linear search, the algorithm will start by comparing the target
element 4 with the first element of the vector, which is 5. Since the target element is not equal to the
first element, the algorithm will move on to the next element.

The algorithm will continue comparing the target element to each element in the vector until it finds the
target element or it reaches the end of the vector. In this case, the algorithm will find the target element
at index 4.

Linear search is a simple and straightforward algorithm, but it is not the most efficient algorithm for
searching for elements in vectors. Linear search has a time complexity of O(n), which means that the
worst-case time for the algorithm to find the target element is proportional to the length of the vector.

If you need to search for elements in large vectors, you may want to use a more efficient algorithm, such
as binary search. However, linear search can be a good choice for searching for elements in small
vectors.
Q5: Complete the following function is_ascending that returns true if the elements in a vector of
integers appear in ascending order (more precisely, non-descending order, if the vector contains
duplicates). For example, the following statement

std::cout << is_ascending({3, 6, 2, 1, 7}) << '\n';

would print false, but the statement

std::cout << is_ascending({3, 6, 7, 12, 27}) << '\n';

would print true. The nonexistent elements in an empty vector are in ascending order because they
cannot be out of order.

bool is_ascending(std::vector& v)

{ // Add your code... }

Ans: To complete the function is_ascending that returns true if the elements in a vector of integers
appear in ascending order (more precisely, non-descending order, if the vector contains duplicates), we
can use the following code:

bool is_ascending(std::vector& v) {
// If the vector is empty, return true.
if (v.empty()) {
return true;
}

// Iterate over the vector and compare each element to the previous
element.
for (int i = 1; i < v.size(); i++) {
if (v[i] < v[i - 1]) {
return false;
}
}

// If we reach the end of the vector without finding any elements that are
out of order, then the vector is in ascending order and we can return true.
return true;
}

This function works by first checking if the vector is empty. If the vector is empty, then there are no
elements to compare and the vector is considered to be in ascending order.
Otherwise, the function iterates over the vector and compares each element to the previous element. If
any element is less than the previous element, then the vector is not in ascending order and the
function returns false.

If we reach the end of the vector without finding any elements that are out of order, then the vector is
in ascending order and the function returns true.

Q6: Consider a sort function that uses the is_ascending function from the previous problem. It uses a
loop to test the permutations of a vector of integers. When it finds a permutation that contains all the
vector’s elements in ascending order it exits the loop. Do you think this would be a good sorting
algorithm? Why or why not?

Ans: The sorting algorithm you described, which uses the is_ascending function to test permutations
of a vector of integers, would not be a good sorting algorithm. It would be very inefficient and slow,
especially for large vectors.

The time complexity of this algorithm would be O(n!), where n is the number of elements in the vector.
This is because the algorithm has to test all possible permutations of the vector, which is a factorial of n.
For example, if the vector has 10 elements, the algorithm would have to test 10! = 3,628,800
permutations.

Even for a small vector of 10 elements, this algorithm would be very slow. For a larger vector, such as a
vector with 100 elements, the algorithm would be impractical to run.

There are much more efficient sorting algorithms available, such as quicksort and mergesort. These
algorithms have a time complexity of O(n log n), which is much better than O(n!).

In addition, the sorting algorithm you described would not be stable. A stable sorting algorithm is one
that preserves the original order of equal elements in the sorted output. The algorithm you described
would not preserve the original order of equal elements because it simply tests permutations of the
vector.

For example, consider the following vector:

{1, 2, 2, 3}

If we sort this vector using the algorithm you described, the sorted output could be either of the
following:

{1, 2, 2, 3}
{1, 2, 3, 2}
The original order of the equal elements 2 has not been preserved.

In conclusion, the sorting algorithm you described would not be a good sorting algorithm because it is
very inefficient, slow, and not stable. There are much better sorting algorithms available that are
efficient, fast, and stable.

***** The End *****

You might also like