Skip to content

Commit 3e675fe

Browse files
authored
feat: add exercise for pointer concept (#825)
1 parent 3a4fe7e commit 3e675fe

File tree

15 files changed

+18473
-0
lines changed

15 files changed

+18473
-0
lines changed

config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,18 @@
196196
"references",
197197
"headers"
198198
]
199+
},
200+
{
201+
"slug": "speedywagon",
202+
"name": "Speedywagon Foundation",
203+
"uuid": "ed2148a5-674c-4660-a050-b11ab240b876",
204+
"concepts": [
205+
"pointers"
206+
],
207+
"prerequisites": [
208+
"classes",
209+
"references"
210+
]
199211
}
200212
],
201213
"practice": [
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Hints
2+
3+
## General
4+
5+
- Pay close attention to pointer syntax.
6+
You will be using `*` (dereference operator) and `->` (member access through pointer).
7+
- Make sure to check for null pointers (`nullptr`) where necessary to avoid accessing invalid memory.
8+
- You can run the tests even if your code isn't complete; a rough structure is enough to see test results.
9+
- All functions used by the tests must be declared in the header file.
10+
- If your program crashes or behaves unexpectedly, it's often due to null pointer dereferencing.
11+
Double-check that you handle `nullptr` properly.
12+
- When using pointer arithmetic, ensure that you stay within the bounds of the sensor array.
13+
Going beyond the array's capacity can lead to memory issues.
14+
15+
## 1. Check Sensor Connection (`connection_check`)
16+
17+
- The task is mainly about verifying whether a pointer is null or not.
18+
- Use the comparison operator `!=` to check if a pointer is valid.
19+
- If you're unsure whether you're checking the pointer correctly, think about what `nullptr` represents (the absence of a valid memory address).
20+
21+
22+
## 2. Count Activity of Sensors (`activity_counter`)
23+
24+
- You need to iterate over the array of sensors.
25+
An array in C++ can be treated as a pointer to its first element.
26+
- Use pointer arithmetic (`sensor_array + i`) to access the sensor at index `i`.
27+
- The `->` operator is used to access a member of the struct through a pointer.
28+
29+
### Example
30+
31+
```cpp
32+
int sum = (sensor_array + i)->activity; // Access activity using pointer arithmetic
33+
```
34+
35+
## 3. Alarm Control (`alarm_control`)
36+
37+
- First, check if the pointer is null before accessing the sensor.
38+
- Use the `->` operator to access the `activity` member of the `pillar_men_sensor` struct.
39+
- Think carefully about what should happen if the sensor's activity level is `0`.
40+
Should the alarm trigger?
41+
42+
## 4. Checking the data for anomalies with the `uv_alarm` function
43+
44+
- Use the `&` operator to pass a pointer to the sensor's data array into the `uv_light_heuristic` function.
45+
- Ensure you correctly check for a null pointer before accessing the sensor's data.
46+
- Compare the result of `uv_light_heuristic` with the sensor's `activity` value to determine if the alarm should trigger.
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Instructions
2+
3+
Welcome, Engineer!
4+
You are one of the last veterans of the Speedywagon Foundation, a secret organization that, for decades, has been battling ancient threats like the Pillar Men.
5+
In the course of this effort, you've spent years maintaining the Foundation's technological systems, built using a mix of cutting-edge tech and aging libraries.
6+
7+
However, in recent times, the sensors that track Pillar Men activities are malfunctioning.
8+
The Foundation's systems are old, and the code interacts with a legacy C++ library that cannot be updated.
9+
Your task is to implement four core functions that monitor Pillar Men sensor activity using an old-fashioned pointer-based library.
10+
11+
The Foundation's operations rely on you.
12+
13+
## 0. The Sensor Environment (`pillar_men_sensor`)
14+
15+
As sensor readings can be huge, we supply a mockup _struct_ that is used in the actual library.
16+
The code has already been implemented in the header file for you.
17+
18+
```cpp
19+
struct pillar_men_sensor {
20+
int activity{};
21+
std::string location{};
22+
std::vector<int> data{};
23+
};
24+
```
25+
26+
## 1. Check Sensor Connection (`connection_check`)
27+
28+
Your first task is to ensure that the Pillar Men sensor is connected properly.
29+
We can't have false alarms triggered by disconnected sensors.
30+
You will write a function `connection_check`, which tests if the sensor's pointer is valid by checking for `nullptr`.
31+
32+
### Task
33+
34+
- Define a function that accepts a pointer a a `pillar_men_sensor` _struct_.
35+
- The function should return `true` if the sensor pointer is not null, and `false` otherwise.
36+
37+
### Example
38+
39+
```cpp
40+
pillar_men_sensor* sensor{nullptr};
41+
bool isConnected = connection_check(sensor);
42+
// isConnected => false
43+
```
44+
45+
## 2. Count Activity of Sensors (`activity_counter`)
46+
47+
Pillar Men are lurking in the shadows, and we need to know if sensors have detected any activity.
48+
You will write the `activity_counter` function, which takes in an array of sensors and a capacity indicating the number of sensors in the array.
49+
50+
### Task
51+
52+
- Define a function that accepts a pointer to the first element of an array and the arrays capacity.
53+
- Use pointer arithmetic to loop through the sensor array and accumulate the activity readings.
54+
- Return the accumulated activity.
55+
56+
### Example
57+
58+
```cpp
59+
pillar_men_sensor sensor_array[3] = {{0}, {101}, {22}};
60+
int totalActivity = activity_counter(sensor_array, 3);
61+
// totalActivity => 123
62+
```
63+
64+
## 3. Alarm Control (`alarm_control`)
65+
66+
Not every sensor should trigger an alarm unless there’s real danger.
67+
The `alarm_control` function ensures that a sensor only triggers an alarm if its activity level is greater than 0.
68+
This function should also check for null sensors to prevent system crashes.
69+
70+
### Task
71+
72+
- Define a function that accepts the pointer to a `pillar_men_sensor`.
73+
- The function should first check for a `nullptr` sensor. If the sensor is `nullptr`, return `false`.
74+
- If the sensor is valid and its activity is greater than 0, return `true`; otherwise, return `false`.
75+
76+
### Example
77+
78+
```cpp
79+
pillar_men_sensor db{9008, "songokunoie", {7, 7, 7}};
80+
bool alarm = alarm_control(&db);
81+
// alarm => true
82+
```
83+
84+
## 4. Checking the data for anomalies with the `uv_alarm` function
85+
86+
In this task, you will implement the `uv_alarm` function to determine whether an alarm should be triggered based on UV light exposure levels and sensor activity.
87+
The `uv_alarm` function should use the provided `uv_light_heuristic` function, which operates on a vector of data and returns a value based on certain thresholds.
88+
This is a mockup version of the complex code that will run during production, please don't change the interface.
89+
90+
### Task
91+
92+
Define the `uv_alarm` function in the `speedywagon` namespace. It should:
93+
94+
- Take a pointer to a `pillar_men_sensor` _struct_ as its parameter.
95+
- Return `false` if the sensor pointer is null.
96+
- Call the `uv_light_heuristic` function, passing the address of the sensor's `data` array.
97+
- Return `true` if the value returned by `uv_light_heuristic` is greater than the `sensor->activity` level, otherwise return `false`.
98+
99+
## Wrapping Up
100+
101+
You’ve been entrusted with an essential task for the Speedywagon Foundation.
102+
By testing for valid sensor connections, counting activity, and implementing alarm controls, you’ve ensured that the Foundation's battle against the Pillar Men can continue uninterrupted.
103+
104+
As a modern C++ engineer, you’d prefer using smart pointers, but alas, legacy code demands respect for the old ways.
105+
The fate of humanity may rest on these pointers, so proceed carefully, and may the Hamon energy guide you.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Introduction
2+
3+
Like many other languages, C++ has _pointers_.
4+
You already know _references_ and _pointers_ are similar, but think of them as a level closer to the inner workings of your computer.
5+
_Pointers_ are variables that hold object addresses.
6+
They are used to directly interact with objects, enabling dynamic memory allocation and efficient data manipulation in C++.
7+
8+
If you're new to _pointers_, they can feel a little mysterious but once you get used to them, they're quite straight-forward.
9+
10+
They're a crucial part of C++, so take some time to really understand them.
11+
The bare-bone version in this concept is also called _dumb pointer_ or _raw pointer_.
12+
With modern C++ there are also _smart pointers_, the basic type is not smart at all and you have to handle all the work manually.
13+
14+
Before digging into the details, it's worth understanding the use of _pointers_.
15+
_Pointers_ are a way to share an object's address with other parts of our program, which is useful for two major reasons:
16+
1. Like _references_, pointers avoid copies and help to reduce the resource-footprint of your program.
17+
2. Unlike _references_, pointers can be reassigned to different objects.
18+
3. Pointers can also point to a null value, to indicate, that they currently do not point to any object.
19+
20+
## General Syntax
21+
22+
A pointer declaration in C++ involves specifying the data type to which the the pointer is pointing, followed by an asterisk (`*`) and the pointer's name.
23+
When pointers are declared, they are not automatically initialized.
24+
Without explicit assignment, a pointer typically holds an indeterminate value, often referred to as a "garbage address."
25+
While certain compilers might initialize pointers to `nullptr`, this behavior is not guaranteed across all compilers, so it's essential not to rely on it.
26+
It's best practice to explicitly initialize raw pointers and verify their non-null status before utilization to avoid potential issues.
27+
28+
```cpp
29+
int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid
30+
```
31+
32+
To assign the address of a variable to a pointer, you use the address-of operator (`&`).
33+
Dereferencing a pointer is done using the _indirection operator_ (`*`) operator.
34+
35+
```cpp
36+
std::string opponent{"Solomon Lane"};
37+
// 'ethan' points to the address of the string opponent
38+
std::string* ethan{&opponent};
39+
// Instead of ethan's, the opponent's name address is given to the passPort
40+
std::string passportName{*ethan};
41+
```
42+
43+
Attention: dereferencing has to be done explicitly, while _references_ just worked like an alias.
44+
45+
## Pointer Arithmetic
46+
47+
_Pointer arithmetic_ allows you to perform arithmetic operations on pointers, which is particularly useful when working with arrays.
48+
Adding an integer to a pointer makes it point to a different element.
49+
50+
```cpp
51+
// Stargate addresses
52+
int gateAddresses[] = {462, 753, 218, 611, 977};
53+
// 'ptr' points to the first element of 'gateAddresses'
54+
int* ptr{gateAddresses};
55+
// Accesses the third Stargate address through pointer arithmetic
56+
int dialedAddress{*(ptr + 2)};
57+
// Chevron encoded! Dialing Stargate address:
58+
openStarGate(dialedAddress);
59+
```
60+
61+
~~~~exercism/caution
62+
Pointer arithmetic in C++ can easily lead to __undefined behavior__ if not handled carefully.
63+
Undefined behavior can manifest in unexpected program outcomes, crashes, or even security vulnerabilities.
64+
One infamous example of the consequences of undefined behavior occurred in the [explosion of the Ariane 5 rocket][ariane-flight-v88] in 1996, where a software exception caused by the conversion of a 64-bit floating-point number to a 16-bit signed integer led to a catastrophic failure.
65+
~~~~
66+
67+
## Accessing member variables
68+
69+
In C++, the `->` operator is used to access members of an object through a pointer to that object.
70+
It is a shorthand which simplifies accessing members of objects pointed to by pointers.
71+
For instance, if `ptr` is a pointer to an object with a member variable `x`, instead of using `(*ptr).x`, you can directly use `ptr->x`.
72+
This operator enhances code readability and reduces verbosity when working with pointers to objects.
73+
74+
Here's a brief example, with a _struct_ `Superhero` that has a member variable `superpower`.
75+
The main function creates a pointer `dianaPrince` to a `Superhero` object (representing Wonder Woman).
76+
The `->` operator is used to access the member variable `superpower`, showcasing Wonder Woman's iconic "Lasso of Truth."
77+
78+
```cpp
79+
struct Superhero {
80+
std::string superpower;
81+
};
82+
83+
Superhero* dianaPrince = new Superhero;
84+
dianaPrince->superpower = "Lasso of Truth";
85+
// Using the -> operator to access member variable superpower:
86+
std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower;
87+
// Memory cleanup:
88+
delete dianaPrince;
89+
```
90+
91+
## Pointers vs. references
92+
93+
Pointers and references both enable indirect access to objects, but they differ in their capabilities and safety considerations.
94+
Pointers offer the flexibility of changing their target object and can be assigned null.
95+
However, this flexibility introduces risks, such as dereferencing null pointers or creating dangling pointers.
96+
References, on the other hand, cannot be null and are bound to valid objects upon creation, avoiding these risks.
97+
Given their safer nature, references should be preferred over pointers unless the additional functionalities provided by pointers are necessary.
98+
99+
[ariane-flight-v88]: https://en.wikipedia.org/wiki/Ariane_flight_V88
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Introduction
2+
3+
%{concept:pointers}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"authors": [
3+
"vaeng"
4+
],
5+
"files": {
6+
"solution": [
7+
"speedywagon.cpp",
8+
"speedywagon.h"
9+
],
10+
"test": [
11+
"speedywagon_test.cpp"
12+
],
13+
"exemplar": [
14+
".meta/exemplar.cpp",
15+
".meta/exemplar.h"
16+
]
17+
},
18+
"forked_from": [],
19+
"blurb": "Learn about pointers by writing wrappers for an old library."
20+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Design
2+
3+
## Goal
4+
5+
The goal of this exercise is to teach the basics of pointers and how they work in C++.
6+
7+
## Learning objectives
8+
9+
- Know how to create a pointer from a variable
10+
- Know how to work with pointers to structs
11+
- Know how to work with array pointers
12+
13+
## Out of scope
14+
15+
- Smart pointers
16+
17+
## Concepts
18+
19+
The Concepts this exercise unlocks are:
20+
21+
- `pointers`: how to work with pointers;
22+
23+
## Prerequisites
24+
25+
- `classes`
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "speedywagon.h"
2+
3+
namespace speedywagon {
4+
5+
int uv_light_heuristic(std::vector<int>* data_array) {
6+
double avg{};
7+
for (auto element : *data_array) {
8+
avg += element;
9+
}
10+
avg /= data_array->size();
11+
int uv_index{};
12+
for (auto element : *data_array) {
13+
if (element > avg) ++uv_index;
14+
}
15+
return uv_index;
16+
}
17+
18+
bool connection_check(pillar_men_sensor* sensor) { return sensor != nullptr; }
19+
20+
int activity_counter(pillar_men_sensor* sensor_array, int capacity) {
21+
int sum{};
22+
for (int i{}; i < capacity; ++i) {
23+
sum += (sensor_array + i)->activity;
24+
}
25+
return sum;
26+
}
27+
28+
bool alarm_control(pillar_men_sensor* sensor) {
29+
if (sensor == nullptr) return false;
30+
return sensor->activity > 0;
31+
}
32+
33+
bool uv_alarm(pillar_men_sensor* sensor) {
34+
if (sensor == nullptr) return false;
35+
return uv_light_heuristic(&(sensor->data)) > sensor->activity;
36+
}
37+
38+
} // namespace speedywagon
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <vector>
5+
6+
namespace speedywagon {
7+
8+
struct pillar_men_sensor {
9+
int activity{};
10+
std::string location{};
11+
std::vector<int> data{};
12+
};
13+
14+
int uv_light_heuristic(std::vector<int>* data_array);
15+
16+
bool connection_check(pillar_men_sensor* sensor);
17+
18+
int activity_counter(pillar_men_sensor* sensor_array, int capacity);
19+
20+
bool alarm_control(pillar_men_sensor* sensor);
21+
22+
bool uv_alarm(pillar_men_sensor* sensor);
23+
24+
} // namespace speedywagon

0 commit comments

Comments
 (0)