ch12/constref.cpp17 lines
#include <iostream>
#include <vector>
// Reads the readings; promises not to change them.
double max_value(const std::vector<double>& values) {
double best = values.empty() ? 0.0 : values[0];
for (double v : values)
if (v > best) best = v;
values[0] = best; // a slip: writes through const&
return best;
}
int main() {
const std::vector<double> temps = {3.5, 1.5, 0.5, 2.5};
std::cout << max_value(temps) << '\n';
return 0;
}
ch12/habits.sh18 lines
#!/bin/sh
# habits.sh: first-pass scan for C habits in a C++ file.
# Usage: sh habits.sh file.cpp (a hit is a lead, not proof)
f="$1"
scan() { # $1 = label, $2 = extended regex (GNU grep)
hits=$(grep -nE "$2" "$f")
[ -n "$hits" ] && printf '[%s]\n%s\n' "$1" "$hits"
}
scan "malloc/free" '\b(malloc|calloc|realloc|free)\s*\('
scan "raw array" '\b(char|int|long|double|\w+_t)\s+\w+\s*\['
scan "char string" '\bchar\s*\*|\bchar\s+\w+\s*\['
scan "printf family" '\b(s?n?printf|puts|scanf)\s*\('
scan "C string call" '\bstr(n?cpy|n?cat|len|n?cmp|dup)\s*\('
scan "length param" '\*\s*\w+,\s*(size_t|int)\s+\w+\)'
scan "#define const" '^\s*#define\s+[A-Z_]+\s+\S'
g++ -std=c++20 -fsyntax-only -Wold-style-cast "$f" 2>&1 |
grep -o '[0-9]*:[0-9]*: warning: use of old-style.*' |
sed 's/^/[C cast] /'
ch12/label.cpp20 lines
#include <cstdio>
#include <iostream>
#include <string>
std::string make_label(const std::string& station, int id) {
std::string label = station + "/" + std::to_string(id);
if (id == 1001) label += " (temperature)";
return label;
}
int main() {
std::string a = make_label("north-field", 1001);
std::string b = a; // copies the characters
b[0] = 'N'; // changes b only
std::cout << a << " | " << b << '\n';
std::cout << a.size() << " chars, equal? "
<< std::boolalpha << (a == b) << '\n';
std::printf("for a C API: %s\n", a.c_str());
return 0;
}
ch12/malloc_str.cpp20 lines
#include <cstdlib>
#include <iostream>
#include <string>
struct SensorInfo {
unsigned id;
std::string name; // a C++ object with its own rules
};
int main() {
std::size_t n = 2;
SensorInfo* s =
static_cast<SensorInfo*>(std::malloc(n * sizeof *s));
if (s == nullptr) return 1;
s[0].id = 1001;
s[0].name = "air temperature, north mast"; // crash?
std::cout << s[0].id << ' ' << s[0].name << '\n';
std::free(s);
return 0;
}
ch12/newdel.cpp21 lines
#include <cstddef>
#include <iostream>
struct Reading {
unsigned sensor_id;
long time_s;
double value;
};
int main() {
std::size_t n = 4;
Reading* one = new Reading{1001, 0, 21.5}; // one object
double* temps = new double[n]; // array of n
for (std::size_t i = 0; i < n; i++) temps[i] = 20.0 + i;
std::cout << one->value << ' ' << temps[n - 1] << '\n';
delete one; // pairs with new
delete temps; // BUG: new[] must pair with delete[]
return 0;
}
ch12/printf_str.cpp10 lines
#include <cstdio>
#include <string>
#include <vector>
int main() {
std::string label = "north-field/1001";
std::vector<double> temps = {3.5, 1.5, 0.5, 2.5};
std::printf("%s: %zu readings\n", label, temps.size());
return 0;
}
ch12/ref.cpp34 lines
#include <cstdint>
#include <iostream>
struct Reading {
std::uint32_t sensor_id;
std::int64_t time_s;
double value;
};
void calibrate_ptr(Reading* p, double offset) {
if (p == nullptr) return; // a pointer can be null
p->value += offset;
}
void calibrate_ref(Reading& r, double offset) {
r.value += offset; // r always names an object
}
int main() {
Reading t = {1001, 60, 21.50};
Reading* p = &t; // p holds t's address
Reading& ref = t; // ref is another name for t
calibrate_ptr(p, 0.25);
calibrate_ref(ref, 0.25);
calibrate_ref(t, 0.25); // no & at the call site
std::cout << "value " << t.value << '\n';
std::cout << "&t " << &t << '\n';
std::cout << "p " << p << " &p " << &p << '\n';
std::cout << "&ref " << &ref << '\n';
std::cout << "sizeof(p) " << sizeof(p)
<< " sizeof(ref) " << sizeof(ref) << '\n';
return 0;
}
ch12/seam.cpp134 lines
#include <algorithm>
#include <chrono>
#include <climits>
#include <cstdint>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
namespace stn {
struct Image {
std::size_t width = 0;
std::size_t height = 0;
std::vector<std::uint8_t> pixels; // row-major, w * h
};
Image make_image(std::size_t w, std::size_t h) {
return Image{w, h, std::vector<std::uint8_t>(w * h, 0)};
}
std::uint8_t pixel(const Image& img, std::size_t r,
std::size_t c) {
return img.pixels[r * img.width + c];
}
void set_pixel(Image& img, std::size_t r, std::size_t c,
std::uint8_t value) {
img.pixels[r * img.width + c] = value;
}
// Edge energy: how sharply brightness changes at (r, c).
int energy(const Image& img, std::size_t r, std::size_t c) {
std::size_t left = c > 0 ? c - 1 : c;
std::size_t right = c + 1 < img.width ? c + 1 : c;
std::size_t up = r > 0 ? r - 1 : r;
std::size_t down = r + 1 < img.height ? r + 1 : r;
int dx = pixel(img, r, right) - pixel(img, r, left);
int dy = pixel(img, down, c) - pixel(img, up, c);
return std::abs(dx) + std::abs(dy);
}
// Naive: cheapest seam cost from (r, c) to the bottom row.
long seam_from(const Image& img, std::size_t r, std::size_t c,
long& calls) {
calls++;
long e = energy(img, r, c);
if (r + 1 == img.height) return e; // bottom row
std::size_t lo = c > 0 ? c - 1 : c;
std::size_t hi = c + 1 < img.width ? c + 1 : c;
long best = LONG_MAX;
for (std::size_t k = lo; k <= hi; k++) {
long sub = seam_from(img, r + 1, k, calls);
best = std::min(best, sub);
}
return e + best;
}
// Memoized: the same recursion; each (r, c) is solved once.
long seam_memo(const Image& img, std::size_t r, std::size_t c,
std::vector<long>& memo, long& calls) {
calls++;
long& slot = memo[r * img.width + c]; // a reference
if (slot >= 0) return slot; // solved
long e = energy(img, r, c);
if (r + 1 == img.height) return slot = e; // bottom
std::size_t lo = c > 0 ? c - 1 : c;
std::size_t hi = c + 1 < img.width ? c + 1 : c;
long best = LONG_MAX;
for (std::size_t k = lo; k <= hi; k++) {
long sub = seam_memo(img, r + 1, k, memo, calls);
best = std::min(best, sub);
}
return slot = e + best;
}
long min_seam_naive(const Image& img, long& calls) {
long best = LONG_MAX;
for (std::size_t c = 0; c < img.width; c++)
best = std::min(best, seam_from(img, 0, c, calls));
return best;
}
long min_seam_memo(const Image& img, long& calls) {
// -1 marks a cell that is not solved yet.
std::vector<long> memo(img.width * img.height, -1);
long best = LONG_MAX;
for (std::size_t c = 0; c < img.width; c++) {
long cost = seam_memo(img, 0, c, memo, calls);
best = std::min(best, cost);
}
return best;
}
} // namespace stn
// Synthetic sky-camera frame: sky fading down, a dark mast.
stn::Image test_frame(std::size_t w, std::size_t h) {
stn::Image img = stn::make_image(w, h);
for (std::size_t r = 0; r < h; r++)
for (std::size_t c = 0; c < w; c++) {
int v = 220 - static_cast<int>(6 * r) +
static_cast<int>((r * 31 + c * 17) % 13);
if (c == w / 3) v = 40; // the mast
auto byte = static_cast<std::uint8_t>(v);
stn::set_pixel(img, r, c, byte);
}
return img;
}
int main(int argc, char** argv) {
using ms = std::chrono::duration<double, std::milli>;
using clk = std::chrono::steady_clock;
std::size_t max_h = argc > 1 ? std::stoul(argv[1]) : 16;
std::cout << " h naive calls naive ms memo calls"
<< " memo ms\n"
<< std::fixed << std::setprecision(3);
for (std::size_t h = 4; h <= max_h; h += 2) {
stn::Image img = test_frame(10, h); // width 10
long nc = 0, mc = 0;
auto t0 = clk::now();
long a = stn::min_seam_naive(img, nc);
auto t1 = clk::now();
long b = stn::min_seam_memo(img, mc);
ms naive = t1 - t0, memo = clk::now() - t1;
std::cout << std::setw(2) << h << std::setw(13) << nc
<< std::setw(10) << naive.count()
<< std::setw(12) << mc
<< std::setw(9) << memo.count()
<< (a == b ? "" : " MISMATCH") << '\n';
}
return 0;
}
ch12/stn_print.cpp30 lines
#include <cstdint>
#include <iostream>
#include <vector>
namespace stn {
struct Reading {
std::uint32_t sensor_id;
std::int64_t time_s;
double value;
};
void print(const Reading& r) {
std::cout << r.sensor_id << " v=" << r.value << '\n';
}
void print(const std::vector<Reading>& rs) {
std::cout << rs.size() << " readings\n";
for (const Reading& r : rs) print(r); // first overload
}
} // namespace stn
int main() {
std::vector<stn::Reading> rs = {{1001, 0, 21.5},
{1002, 0, 88.0}};
stn::print(rs[0]);
stn::print(rs);
return 0;
}
ch12/summary.c39 lines
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME 32
#define FROST_C 2.0
struct reading {
uint32_t sensor_id;
int64_t time_s;
double value;
};
double stn_mean(const struct reading *r, size_t n) {
double sum = 0.0;
for (size_t i = 0; i < n; i++) sum += r[i].value;
return n > 0 ? sum / (double)n : 0.0;
}
int main(void) {
char name[MAX_NAME];
snprintf(name, sizeof name, "%s", "north-field");
double temps[] = {3.5, 1.5, 0.5, 2.5};
size_t n = sizeof temps / sizeof temps[0];
struct reading *r = malloc(n * sizeof *r);
if (r == NULL) return 1;
int below = 0;
for (size_t i = 0; i < n; i++) {
r[i].sensor_id = 1001;
r[i].time_s = 60 * (int64_t)i;
r[i].value = temps[i];
if (r[i].value < FROST_C) below++;
}
printf("%s: mean %.2f C over %zu readings\n",
name, stn_mean(r, n), n);
printf("below frost line: %d\n", below);
free(r);
return 0;
}
ch12/summary.cpp40 lines
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#define MAX_NAME 32
#define FROST_C 2.0
struct reading {
uint32_t sensor_id;
int64_t time_s;
double value;
};
double stn_mean(const reading *r, size_t n) {
double sum = 0.0;
for (size_t i = 0; i < n; i++) sum += r[i].value;
return n > 0 ? sum / (double)n : 0.0;
}
int main() {
char name[MAX_NAME];
std::strcpy(name, "north-field");
double temps[] = {3.5, 1.5, 0.5, 2.5};
size_t n = sizeof temps / sizeof temps[0];
reading *r = (reading *)malloc(n * sizeof(reading));
if (r == NULL) return 1;
int below = 0;
for (size_t i = 0; i < n; i++) {
r[i].sensor_id = 1001;
r[i].time_s = 60 * (int64_t)i;
r[i].value = temps[i];
if (r[i].value < FROST_C) below++;
}
std::cout << name << ": mean " << stn_mean(r, n)
<< " C over " << n << " readings\n";
printf("below frost line: %d\n", below);
free(r);
return 0;
}
ch12/summary_modern.cpp40 lines
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
namespace stn {
constexpr double frost_line_c = 2.0;
struct Reading {
std::uint32_t sensor_id;
std::int64_t time_s;
double value;
};
double mean(const std::vector<Reading>& rs) {
double sum = 0.0;
for (const Reading& r : rs) sum += r.value;
if (rs.empty()) return 0.0;
return sum / static_cast<double>(rs.size());
}
} // namespace stn
int main() {
const std::string name = "north-field";
const std::vector<double> temps = {3.5, 1.5, 0.5, 2.5};
std::vector<stn::Reading> rs;
for (std::size_t i = 0; i < temps.size(); i++)
rs.push_back({1001, 60 * static_cast<std::int64_t>(i),
temps[i]});
int below = 0;
for (const stn::Reading& r : rs)
if (r.value < stn::frost_line_c) below++;
std::cout << std::fixed << std::setprecision(2) << name
<< ": mean " << stn::mean(rs) << " C over "
<< rs.size() << " readings\n"
<< "below frost line: " << below << '\n';
return 0;
}
ch12/vec.cpp25 lines
#include <cstddef>
#include <iostream>
#include <vector>
double mean(const std::vector<double>& v) {
double sum = 0.0;
for (double x : v) sum += x;
if (v.empty()) return 0.0;
return sum / static_cast<double>(v.size());
}
int main() {
std::vector<double> temps; // empty: size 0
for (int minute = 0; minute < 6; minute++) {
temps.push_back(20.0 + 0.5 * minute);
std::cout << "size " << temps.size()
<< " capacity " << temps.capacity()
<< '\n';
}
std::cout << "mean " << mean(temps) << '\n';
std::cout << "temps[2] " << temps[2] << '\n';
std::cout << "temps.at(9) " << std::flush;
std::cout << temps.at(9) << '\n'; // checked access
return 0;
}
ch12/vec_oob.cpp12 lines
#include <string>
#include <iostream>
#include <vector>
int main(int argc, char** argv) {
std::vector<double> temps;
for (int minute = 0; minute < 6; minute++)
temps.push_back(20.0 + 0.5 * minute);
std::size_t i = argc > 1 ? std::stoul(argv[1]) : 0;
std::cout << "temps[" << i << "] = " << temps[i] << '\n';
return 0;
}