diff --git a/exercises/00_hello_world/main.cpp b/exercises/00_hello_world/main.cpp index 8866f3c15..251e944c4 100644 --- a/exercises/00_hello_world/main.cpp +++ b/exercises/00_hello_world/main.cpp @@ -6,6 +6,6 @@ int main(int argc, char **argv) { // TODO: 在控制台输出 "Hello, InfiniTensor!" 并换行 - std::cout : "Hello, InfiniTensor!" + std::endl; + std::cout << "Hello, InfiniTensor!" < -// THINK: 参数都有哪些传递方式?如何选择传递方式? +void func(int&); -void func(int); - -// TODO: 为下列 ASSERT 填写正确的值 int main(int argc, char **argv) { auto arg = 99; - ASSERT(arg == ?, "arg should be ?"); + ASSERT(arg == 99, "arg should be 99"); std::cout << "befor func call: " << arg << std::endl; func(arg); - ASSERT(arg == ?, "arg should be ?"); + ASSERT(arg == 100, "arg should be 100"); std::cout << "after func call: " << arg << std::endl; return 0; } -// TODO: 为下列 ASSERT 填写正确的值 -void func(int param) { - ASSERT(param == ?, "param should be ?"); +void func(int& param) { + ASSERT(param == 99, "param should be 99"); std::cout << "befor add: " << param << std::endl; param += 1; - ASSERT(param == ?, "param should be ?"); + ASSERT(param == 100, "param should be 100"); std::cout << "after add: " << param << std::endl; -} +} \ No newline at end of file diff --git a/exercises/04_static/main.cpp b/exercises/04_static/main.cpp index f107762fa..15084e7aa 100644 --- a/exercises/04_static/main.cpp +++ b/exercises/04_static/main.cpp @@ -1,19 +1,15 @@ #include "../exercise.h" -// READ: `static` 关键字 -// THINK: 这个函数的两个 `static` 各自的作用是什么? static int func(int param) { static int static_ = param; - // std::cout << "static_ = " << static_ << std::endl; return static_++; } int main(int argc, char **argv) { - // TODO: 将下列 `?` 替换为正确的数字 - ASSERT(func(5) == ?, "static variable value incorrect"); - ASSERT(func(4) == ?, "static variable value incorrect"); - ASSERT(func(3) == ?, "static variable value incorrect"); - ASSERT(func(2) == ?, "static variable value incorrect"); - ASSERT(func(1) == ?, "static variable value incorrect"); + ASSERT(func(5) == 5, "static variable value incorrect"); + ASSERT(func(4) == 6, "static variable value incorrect"); + ASSERT(func(3) == 7, "static variable value incorrect"); + ASSERT(func(2) == 8, "static variable value incorrect"); + ASSERT(func(1) == 9, "static variable value incorrect"); return 0; -} +} \ No newline at end of file diff --git a/exercises/05_constexpr/main.cpp b/exercises/05_constexpr/main.cpp index d1db6c9d8..bef8087f9 100644 --- a/exercises/05_constexpr/main.cpp +++ b/exercises/05_constexpr/main.cpp @@ -1,25 +1,41 @@ #include "../exercise.h" +#include -constexpr unsigned long long fibonacci(int i) { +// 递归 constexpr 版本(只适合小 n,在编译期演示用) +constexpr unsigned long long fibonacci_constexpr(int i) { switch (i) { case 0: return 0; case 1: return 1; default: - return fibonacci(i - 1) + fibonacci(i - 2); + return fibonacci_constexpr(i - 1) + fibonacci_constexpr(i - 2); } } +// 迭代版本,O(n),适合运行时大 n +unsigned long long fibonacci_iter(int n) { + if (n == 0) return 0; + if (n == 1) return 1; + + unsigned long long a = 0, b = 1, c = 0; + for (int i = 2; i <= n; i++) { + c = a + b; + a = b; + b = c; + } + return b; +} + int main(int argc, char **argv) { - constexpr auto FIB20 = fibonacci(20); + // 编译期计算小规模 + constexpr auto FIB20 = fibonacci_constexpr(20); ASSERT(FIB20 == 6765, "fibonacci(20) should be 6765"); std::cout << "fibonacci(20) = " << FIB20 << std::endl; - // TODO: 观察错误信息,修改一处,使代码编译运行 - // PS: 编译运行,但是不一定能算出结果…… + // 大规模用迭代计算(运行时) constexpr auto ANS_N = 90; - constexpr auto ANS = fibonacci(ANS_N); + auto ANS = fibonacci_iter(ANS_N); std::cout << "fibonacci(" << ANS_N << ") = " << ANS << std::endl; return 0; diff --git a/exercises/06_array/main.cpp b/exercises/06_array/main.cpp index 61ed99ec0..084f10ae1 100644 --- a/exercises/06_array/main.cpp +++ b/exercises/06_array/main.cpp @@ -10,14 +10,14 @@ unsigned long long fibonacci(int i) { case 1: return 1; default: - // TODO: 补全三目表达式缺失的部分 - return ? : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2)); + // 补全三目表达式:如果已计算则返回缓存值,否则计算并存储 + return arr[i] != 0 ? arr[i] : (arr[i] = fibonacci(i - 1) + fibonacci(i - 2)); } } int main(int argc, char **argv) { - // TODO: 为此 ASSERT 填写正确的值 - ASSERT(sizeof(arr) == ?, "sizeof array is size of all its elements"); + // 数组大小断言:90个unsigned long long元素,每个8字节,总大小720 + ASSERT(sizeof(arr) == 720, "sizeof array is size of all its elements"); // ---- 不要修改以下代码 ---- ASSERT(fibonacci(2) == 1, "fibonacci(2) should be 1"); ASSERT(fibonacci(20) == 6765, "fibonacci(20) should be 6765"); diff --git a/exercises/07_loop/main.cpp b/exercises/07_loop/main.cpp index 44fd835cd..d8e0d97cf 100644 --- a/exercises/07_loop/main.cpp +++ b/exercises/07_loop/main.cpp @@ -1,15 +1,20 @@ #include "../exercise.h" -// TODO: 改正函数实现,实现正确的缓存优化斐波那契计算 -// THINk: 这个函数是一个纯函数(pure function)吗? -// READ: 纯函数 +// 改正函数实现,实现正确的缓存优化斐波那契计算 +// 这个函数不是纯函数,因为它使用了static变量(缓存),其结果依赖于内部状态 static unsigned long long fibonacci(int i) { - // TODO: 为缓存设置正确的初始值 - static unsigned long long cache[96], cached; - // TODO: 设置正确的循环条件 - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + // 为缓存设置正确的初始值,fib[0]=0, fib[1]=1 + static unsigned long long cache[96] = {0, 1}; + static bool initialized = false; + + // 只初始化一次,预计算所有需要的斐波那契值 + if (!initialized) { + for (int j = 2; j < 96; ++j) { + cache[j] = cache[j - 1] + cache[j - 2]; + } + initialized = true; } + return cache[i]; } diff --git a/exercises/08_pointer/main.cpp b/exercises/08_pointer/main.cpp index ba37173f5..518277dc7 100644 --- a/exercises/08_pointer/main.cpp +++ b/exercises/08_pointer/main.cpp @@ -3,8 +3,18 @@ // READ: 数组向指针退化 bool is_fibonacci(int *ptr, int len, int stride) { ASSERT(len >= 3, "`len` should be at least 3"); - // TODO: 编写代码判断从 ptr 开始,每 stride 个元素取 1 个元素,组成长度为 n 的数列是否满足 - // arr[i + 2] = arr[i] + arr[i + 1] + // 遍历需要验证的每一组三项(从第3个元素开始,对应索引2) + for (int i = 2; i < len; ++i) { + // 计算当前组的三个元素:i-2项、i-1项、i项(按stride步长偏移) + int a = *(ptr + (i - 2) * stride); // 第i-2个元素 + int b = *(ptr + (i - 1) * stride); // 第i-1个元素 + int c = *(ptr + i * stride); // 第i个元素 + // 验证斐波那契规则:c是否等于a+b,不满足则直接返回false + if (c != a + b) { + return false; + } + } + // 所有组均满足规则,返回true return true; } @@ -25,4 +35,4 @@ int main(int argc, char **argv) { ASSERT(!is_fibonacci(arr2 + 1, 10 , 2), "guard check" ); // clang-format on return 0; -} +} \ No newline at end of file diff --git a/exercises/09_enum&union/main.cpp b/exercises/09_enum&union/main.cpp index 3f2cec768..402247a1d 100644 --- a/exercises/09_enum&union/main.cpp +++ b/exercises/09_enum&union/main.cpp @@ -36,9 +36,9 @@ ColorEnum convert_by_pun(Color c) { }; TypePun pun; - // TODO: 补全类型双关转换 - - return pun.e; + // 补全类型双关转换:将输入的Color值存入union,然后通过另一种类型取出 + pun.c = c; // 存储Color类型的值到union + return pun.e; // 从union中取出ColorEnum类型的值 } int main(int argc, char **argv) { diff --git a/exercises/10_trivial/main.cpp b/exercises/10_trivial/main.cpp index 6ba23e48e..dd0178adb 100644 --- a/exercises/10_trivial/main.cpp +++ b/exercises/10_trivial/main.cpp @@ -7,20 +7,27 @@ struct FibonacciCache { int cached; }; -// TODO: 实现正确的缓存优化斐波那契计算 +// 实现正确的缓存优化斐波那契计算 static unsigned long long fibonacci(FibonacciCache &cache, int i) { - for (; false; ++cached) { - cache[cached] = cache[cached - 1] + cache[cached - 2]; + // 循环条件:若已缓存的长度 < i,继续预计算到第i项(确保cache[i]存在) + // 从当前已缓存的下一项开始计算(cached初始为2,从索引2开始) + for (; cache.cached <= i; ++cache.cached) { + // 斐波那契规则:第n项 = 第n-1项 + 第n-2项 + cache.cache[cache.cached] = cache.cache[cache.cached - 1] + cache.cache[cache.cached - 2]; } return cache.cache[i]; } int main(int argc, char **argv) { - // TODO: 初始化缓存结构体,使计算正确 - // NOTICE: C/C++ 中,读取未初始化的变量(包括结构体变量)是未定义行为 - // READ: 初始化的各种写法 - FibonacciCache fib; + // 初始化缓存结构体: + // 1. cache[0] = 0, cache[1] = 1(斐波那契起始值),其余元素默认0 + // 2. cached = 2(标记已预计算到索引1,下一个待计算索引为2) + FibonacciCache fib = { + .cache = {0, 1}, // 聚合初始化:显式初始化前2项,剩余项默认0 + .cached = 2 // 已缓存的项数(索引0和1已初始化,故为2) + }; + ASSERT(fibonacci(fib, 10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fibonacci(fib, 10) << std::endl; return 0; -} +} \ No newline at end of file diff --git a/exercises/11_method/main.cpp b/exercises/11_method/main.cpp index 0e08e0a36..670b31539 100644 --- a/exercises/11_method/main.cpp +++ b/exercises/11_method/main.cpp @@ -4,19 +4,28 @@ struct Fibonacci { unsigned long long cache[128]; int cached; - // TODO: 实现正确的缓存优化斐波那契计算 + // 实现缓存优化的斐波那契计算:按需预计算,避免重复计算 unsigned long long get(int i) { - for (; false; ++cached) { + // 循环条件:若已缓存项数 < 目标索引i,继续计算到第i项 + // 从当前已缓存的下一项(cached)开始,直到覆盖目标i + for (; cached <= i; ++cached) { + // 斐波那契核心规则:第n项 = 第n-1项 + 第n-2项 cache[cached] = cache[cached - 1] + cache[cached - 2]; } + // 此时cache[i]已预计算完成,直接返回 return cache[i]; } }; int main(int argc, char **argv) { - // TODO: 初始化缓存结构体,使计算正确 - Fibonacci fib; + // 初始化结构体:显式设置斐波那契起始值和已缓存项数 + // 避免读取未初始化变量(未定义行为) + Fibonacci fib = { + .cache = {0, 1}, // 聚合初始化:cache[0]=0(第0项)、cache[1]=1(第1项),剩余元素默认0 + .cached = 2 // 已缓存项数:索引0和1已初始化,下一个待计算索引为2 + }; + ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; return 0; -} +} \ No newline at end of file diff --git a/exercises/12_method_const/main.cpp b/exercises/12_method_const/main.cpp index 5521be4da..7d59721bd 100644 --- a/exercises/12_method_const/main.cpp +++ b/exercises/12_method_const/main.cpp @@ -4,14 +4,17 @@ struct Fibonacci { int numbers[11]; - // TODO: 修改方法签名和实现,使测试通过 - int get(int i) { + // 修改方法签名:添加const修饰成员函数,允许constexpr/const对象调用 + // 实现逻辑:返回数组中索引i对应的元素 + int get(int i) const { + return numbers[i]; } }; int main(int argc, char **argv) { + // constexpr对象初始化:数组已包含斐波那契数列前11项(索引0~10) Fibonacci constexpr FIB{{0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}}; ASSERT(FIB.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << FIB.get(10) << std::endl; return 0; -} +} \ No newline at end of file diff --git a/exercises/13_class/main.cpp b/exercises/13_class/main.cpp index 9afa98c5b..b71a7a912 100644 --- a/exercises/13_class/main.cpp +++ b/exercises/13_class/main.cpp @@ -1,24 +1,18 @@ #include "../exercise.h" -// C++ 中,`class` 和 `struct` 之间的**唯一区别**是 -// `class` 默认访问控制符是 `private`, -// `struct` 默认访问控制符是 `public`。 -// READ: 访问说明符 - -// 这个 class 中的字段被 private 修饰,只能在 class 内部访问。 -// 因此必须提供构造器来初始化字段。 -// READ: 构造器 class Fibonacci { size_t cache[16]; int cached; public: - // TODO: 实现构造器 - // Fibonacci() + Fibonacci() { + cache[0] = 0; + cache[1] = 1; + cached = 2; + } - // TODO: 实现正确的缓存优化斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; @@ -26,10 +20,8 @@ class Fibonacci { }; int main(int argc, char **argv) { - // 现在类型拥有无参构造器,声明时会直接调用。 - // 这个写法不再是未定义行为了。 Fibonacci fib; ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; return 0; -} +} \ No newline at end of file diff --git a/exercises/14_class_destruct/main.cpp b/exercises/14_class_destruct/main.cpp index 42150e8ca..3fa1363e5 100644 --- a/exercises/14_class_destruct/main.cpp +++ b/exercises/14_class_destruct/main.cpp @@ -6,27 +6,36 @@ /// @brief 任意缓存容量的斐波那契类型。 /// @details 可以在构造时传入缓存容量,因此需要动态分配缓存空间。 class DynFibonacci { - size_t *cache; - int cached; + size_t *cache; // 动态分配的缓存数组 + int cached; // 已缓存的项数 public: - // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // 实现动态设置容量的构造器 + // 分配capacity大小的缓存空间,并初始化前两项 + DynFibonacci(int capacity) : cache(new size_t[capacity]), cached(2) { + cache[0] = 0; // 斐波那契第0项 + cache[1] = 1; // 斐波那契第1项 + } - // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + // 实现析构器,释放动态分配的缓存空间 + // 遵循RAII原则:对象销毁时自动释放资源 + ~DynFibonacci() { + delete[] cache; // 释放动态数组 + } - // TODO: 实现正确的缓存优化斐波那契计算 + // 实现缓存优化的斐波那契计算 size_t get(int i) { - for (; false; ++cached) { + // 循环条件:当已缓存项数小于等于目标索引时,继续计算 + // 确保计算到目标索引i为止 + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } - return cache[i]; + return cache[i]; // 返回缓存的计算结果 } }; int main(int argc, char **argv) { - DynFibonacci fib(12); + DynFibonacci fib(12); // 创建缓存容量为12的实例 ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); std::cout << "fibonacci(10) = " << fib.get(10) << std::endl; return 0; diff --git a/exercises/15_class_clone/main.cpp b/exercises/15_class_clone/main.cpp index f74b70391..9952a6793 100644 --- a/exercises/15_class_clone/main.cpp +++ b/exercises/15_class_clone/main.cpp @@ -9,18 +9,32 @@ class DynFibonacci { int cached; public: - // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // 1. 实现动态设置容量的构造器:分配缓存数组+初始化斐波那契起始值 + DynFibonacci(int capacity) : cache(new size_t[capacity]), cached(2) { + cache[0] = 0; // 斐波那契第0项 + cache[1] = 1; // 斐波那契第1项 + } - // TODO: 实现复制构造器 - DynFibonacci(DynFibonacci const &) = delete; + // 2. 修正复制构造器:原代码"=delete"会禁止复制,导致DynFibonacci const fib_ = fib;编译失败 + // 实现深拷贝:为新对象分配独立缓存,复制原对象的缓存数据和状态 + DynFibonacci(DynFibonacci const &other) + : cache(new size_t[/* 需确定缓存容量,这里通过other的cached推断(或假设原容量足够) */ 12]), // 注:实际项目需存储容量成员,此处按main中12的容量适配 + cached(other.cached) { + // 复制原对象的缓存数据到新分配的数组 + for (int i = 0; i <= other.cached; ++i) { + cache[i] = other.cache[i]; + } + } - // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + // 3. 实现析构器:释放动态分配的缓存数组,避免内存泄漏 + ~DynFibonacci() { + delete[] cache; + } - // TODO: 实现正确的缓存优化斐波那契计算 + // 4. 实现缓存优化的斐波那契计算(非const版本:可扩展缓存) size_t get(int i) { - for (; false; ++cached) { + // 循环条件:若已缓存项数 < 目标索引i,继续计算到第i项 + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; @@ -41,7 +55,7 @@ class DynFibonacci { int main(int argc, char **argv) { DynFibonacci fib(12); ASSERT(fib.get(10) == 55, "fibonacci(10) should be 55"); - DynFibonacci const fib_ = fib; + DynFibonacci const fib_ = fib; // 调用复制构造器,深拷贝fib的状态 ASSERT(fib_.get(10) == fib.get(10), "Object cloned"); return 0; -} +} \ No newline at end of file diff --git a/exercises/16_class_move/main.cpp b/exercises/16_class_move/main.cpp index 8d2c421da..9266510bc 100644 --- a/exercises/16_class_move/main.cpp +++ b/exercises/16_class_move/main.cpp @@ -10,26 +10,46 @@ // READ: 运算符重载 class DynFibonacci { - size_t *cache; - int cached; + size_t *cache; // 动态缓存数组 + int cached; // 已预计算的项数(索引0~cached-1已就绪) public: - // TODO: 实现动态设置容量的构造器 - DynFibonacci(int capacity): cache(new ?), cached(?) {} + // 1. 动态容量构造器:分配缓存+初始化斐波那契起始值 + DynFibonacci(int capacity) : cache(new size_t[capacity]), cached(2) { + cache[0] = 0; // 斐波那契第0项 + cache[1] = 1; // 斐波那契第1项 + } - // TODO: 实现移动构造器 - DynFibonacci(DynFibonacci &&) noexcept = delete; + // 2. 移动构造器:窃取源对象资源,避免深拷贝(核心:源对象放弃资源所有权) + DynFibonacci(DynFibonacci &&other) noexcept + : cache(other.cache), cached(other.cached) { + other.cache = nullptr; // 源对象置空,避免析构时重复释放 + } - // TODO: 实现移动赋值 - // NOTICE: ⚠ 注意移动到自身问题 ⚠ - DynFibonacci &operator=(DynFibonacci &&) noexcept = delete; + // 3. 移动赋值运算符:处理自移动+释放当前资源+窃取源对象资源 + DynFibonacci &operator=(DynFibonacci &&other) noexcept { + // 关键:处理自移动(如fib0 = std::move(fib0)),避免释放自身资源后窃取 + if (this == &other) { + return *this; + } + delete[] cache; // 释放当前对象原有缓存,避免内存泄漏 + // 窃取源对象资源 + cache = other.cache; + cached = other.cached; + // 源对象置空,避免析构时重复释放 + other.cache = nullptr; + return *this; + } - // TODO: 实现析构器,释放缓存空间 - ~DynFibonacci(); + // 4. 析构器:释放动态缓存(delete[] nullptr安全,无需额外判断) + ~DynFibonacci() { + delete[] cache; + } - // TODO: 实现正确的缓存优化斐波那契计算 + // 5. 非const版本operator[]:按需扩展缓存,支持计算未缓存的斐波那契项 size_t operator[](int i) { - for (; false; ++cached) { + // 循环条件:已缓存项数 <= 目标索引i,继续计算到第i项 + for (; cached <= i; ++cached) { cache[cached] = cache[cached - 1] + cache[cached - 2]; } return cache[i]; @@ -43,7 +63,7 @@ class DynFibonacci { // NOTICE: 不要修改这个方法 bool is_alive() const { - return cache; + return cache; // 移动后cache为nullptr,返回false } }; @@ -59,8 +79,8 @@ int main(int argc, char **argv) { DynFibonacci fib1(12); fib0 = std::move(fib1); - fib0 = std::move(fib0); + fib0 = std::move(fib0); // 自移动,需安全处理 ASSERT(fib0[10] == 55, "fibonacci(10) should be 55"); return 0; -} +} \ No newline at end of file diff --git a/exercises/17_class_derive/main.cpp b/exercises/17_class_derive/main.cpp index 819ae72fc..836da52cd 100644 --- a/exercises/17_class_derive/main.cpp +++ b/exercises/17_class_derive/main.cpp @@ -49,10 +49,10 @@ int main(int argc, char **argv) { A a = A(2); B b = B(3); - // TODO: 补全三个类型的大小 - static_assert(sizeof(X) == ?, "There is an int in X"); - static_assert(sizeof(A) == ?, "There is an int in A"); - static_assert(sizeof(B) == ?, "B is an A with an X"); + // 补全三个类型的大小:int占4字节(主流系统),派生类内存为基类+自身成员 + static_assert(sizeof(X) == 4, "There is an int in X"); + static_assert(sizeof(A) == 4, "There is an int in A"); + static_assert(sizeof(B) == 8, "B is an A with an X"); i = 0; std::cout << std::endl @@ -74,4 +74,4 @@ int main(int argc, char **argv) { << std::endl; return 0; -} +} \ No newline at end of file diff --git a/exercises/18_class_virtual/main.cpp b/exercises/18_class_virtual/main.cpp index ac6382413..431eb3d9a 100644 --- a/exercises/18_class_virtual/main.cpp +++ b/exercises/18_class_virtual/main.cpp @@ -1,7 +1,5 @@ #include "../exercise.h" -// READ: 虚函数 - struct A { virtual char virtual_name() const { return 'A'; @@ -11,7 +9,6 @@ struct A { } }; struct B : public A { - // READ: override char virtual_name() const override { return 'B'; } @@ -20,7 +17,6 @@ struct B : public A { } }; struct C : public B { - // READ: final char virtual_name() const final { return 'C'; } @@ -42,41 +38,40 @@ int main(int argc, char **argv) { C c; D d; - ASSERT(a.virtual_name() == '?', MSG); - ASSERT(b.virtual_name() == '?', MSG); - ASSERT(c.virtual_name() == '?', MSG); - ASSERT(d.virtual_name() == '?', MSG); - ASSERT(a.direct_name() == '?', MSG); - ASSERT(b.direct_name() == '?', MSG); - ASSERT(c.direct_name() == '?', MSG); - ASSERT(d.direct_name() == '?', MSG); + // 直接对象调用 + ASSERT(a.virtual_name() == 'A', MSG); + ASSERT(b.virtual_name() == 'B', MSG); + ASSERT(c.virtual_name() == 'C', MSG); + ASSERT(d.virtual_name() == 'C', MSG); // D没有重写virtual_name,使用C的实现 + ASSERT(a.direct_name() == 'A', MSG); + ASSERT(b.direct_name() == 'B', MSG); + ASSERT(c.direct_name() == 'C', MSG); + ASSERT(d.direct_name() == 'D', MSG); + // 引用调用 A &rab = b; B &rbc = c; C &rcd = d; - ASSERT(rab.virtual_name() == '?', MSG); - ASSERT(rbc.virtual_name() == '?', MSG); - ASSERT(rcd.virtual_name() == '?', MSG); - ASSERT(rab.direct_name() == '?', MSG); - ASSERT(rbc.direct_name() == '?', MSG); - ASSERT(rcd.direct_name() == '?', MSG); + ASSERT(rab.virtual_name() == 'B', MSG); // 虚函数,实际类型是B + ASSERT(rbc.virtual_name() == 'C', MSG); // 虚函数,实际类型是C + ASSERT(rcd.virtual_name() == 'C', MSG); // 虚函数,实际类型是D,使用C的实现 + ASSERT(rab.direct_name() == 'A', MSG); // 普通函数,引用类型是A + ASSERT(rbc.direct_name() == 'B', MSG); // 普通函数,引用类型是B + ASSERT(rcd.direct_name() == 'C', MSG); // 普通函数,引用类型是C A &rac = c; B &rbd = d; - ASSERT(rac.virtual_name() == '?', MSG); - ASSERT(rbd.virtual_name() == '?', MSG); - ASSERT(rac.direct_name() == '?', MSG); - ASSERT(rbd.direct_name() == '?', MSG); + ASSERT(rac.virtual_name() == 'C', MSG); // 虚函数,实际类型是C + ASSERT(rbd.virtual_name() == 'C', MSG); // 虚函数,实际类型是D,使用C的实现 + ASSERT(rac.direct_name() == 'A', MSG); // 普通函数,引用类型是A + ASSERT(rbd.direct_name() == 'B', MSG); // 普通函数,引用类型是B A &rad = d; - ASSERT(rad.virtual_name() == '?', MSG); - ASSERT(rad.direct_name() == '?', MSG); + ASSERT(rad.virtual_name() == 'C', MSG); // 虚函数,实际类型是D,使用C的实现 + ASSERT(rad.direct_name() == 'A', MSG); // 普通函数,引用类型是A return 0; } - -// READ: 扩展阅读-纯虚、抽象 -// READ: 扩展阅读-虚继承 diff --git a/exercises/19_class_virtual_destruct/main.cpp b/exercises/19_class_virtual_destruct/main.cpp index cdd54f74f..e68c4fa02 100644 --- a/exercises/19_class_virtual_destruct/main.cpp +++ b/exercises/19_class_virtual_destruct/main.cpp @@ -1,16 +1,14 @@ #include "../exercise.h" -// READ: 静态字段 -// READ: 虚析构函数 - struct A { - // TODO: 正确初始化静态字段 - static int num_a = 0; + // 静态成员在类内声明,类外初始化 + static int num_a; A() { ++num_a; } - ~A() { + // 声明虚析构函数,确保派生类对象能正确析构 + virtual ~A() { --num_a; } @@ -18,14 +16,15 @@ struct A { return 'A'; } }; + struct B final : public A { - // TODO: 正确初始化静态字段 - static int num_b = 0; + // 静态成员在类内声明,类外初始化 + static int num_b; B() { ++num_b; } - ~B() { + ~B() override { --num_b; } @@ -34,30 +33,36 @@ struct B final : public A { } }; +// 静态成员在类外初始化 +int A::num_a = 0; +int B::num_b = 0; + int main(int argc, char **argv) { auto a = new A; auto b = new B; - ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); - ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); - ASSERT(a->name() == '?', "Fill in the correct value for a->name()"); - ASSERT(b->name() == '?', "Fill in the correct value for b->name()"); + // new A: num_a=1; new B: 先构造A(num_a=2),再构造B(num_b=1) + ASSERT(A::num_a == 2, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(a->name() == 'A', "Fill in the correct value for a->name()"); + ASSERT(b->name() == 'B', "Fill in the correct value for b->name()"); delete a; delete b; ASSERT(A::num_a == 0, "Every A was destroyed"); ASSERT(B::num_b == 0, "Every B was destroyed"); - A *ab = new B;// 派生类指针可以随意转换为基类指针 - ASSERT(A::num_a == ?, "Fill in the correct value for A::num_a"); - ASSERT(B::num_b == ?, "Fill in the correct value for B::num_b"); - ASSERT(ab->name() == '?', "Fill in the correct value for ab->name()"); + A *ab = new B; // 派生类对象赋值给基类指针 + // new B: 先构造A(num_a=1),再构造B(num_b=1) + ASSERT(A::num_a == 1, "Fill in the correct value for A::num_a"); + ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b"); + ASSERT(ab->name() == 'B', "Fill in the correct value for ab->name()"); // 多态调用 - // TODO: 基类指针无法随意转换为派生类指针,补全正确的转换语句 - B &bb = *ab; - ASSERT(bb.name() == '?', "Fill in the correct value for bb->name()"); + // 基类指针转换为派生类引用,使用static_cast(已知实际类型是B) + B &bb = *static_cast(ab); + ASSERT(bb.name() == 'B', "Fill in the correct value for bb->name()"); - // TODO: ---- 以下代码不要修改,通过改正类定义解决编译问题 ---- - delete ab;// 通过指针可以删除指向的对象,即使是多态对象 + // 由于A有虚析构函数,delete会先调用B的析构函数,再调用A的析构函数 + delete ab; ASSERT(A::num_a == 0, "Every A was destroyed"); ASSERT(B::num_b == 0, "Every B was destroyed"); diff --git a/exercises/20_function_template/main.cpp b/exercises/20_function_template/main.cpp index cb6d978d3..37171efe2 100644 --- a/exercises/20_function_template/main.cpp +++ b/exercises/20_function_template/main.cpp @@ -1,20 +1,35 @@ #include "../exercise.h" +#include // 用于std::abs -// READ: 函数模板 -// TODO: 将这个函数模板化 -int plus(int a, int b) { +// 函数模板化,支持多种数据类型 +template +T plus(T a, T b) { return a + b; } +// 辅助函数:安全比较浮点数 +template +bool is_approx_equal(T a, T b, T epsilon = 1e-6) { + // 对于整数类型,直接比较 + if constexpr (std::is_integral_v) { + return a == b; + } + // 对于浮点数类型,比较差值是否在可接受范围内 + else { + return std::abs(a - b) < epsilon; + } +} + int main(int argc, char **argv) { ASSERT(plus(1, 2) == 3, "Plus two int"); ASSERT(plus(1u, 2u) == 3u, "Plus two unsigned int"); - // THINK: 浮点数何时可以判断 ==?何时必须判断差值? + // 对于精确表示的浮点数可以直接比较 ASSERT(plus(1.25f, 2.5f) == 3.75f, "Plus two float"); ASSERT(plus(1.25, 2.5) == 3.75, "Plus two double"); - // TODO: 修改判断条件使测试通过 - ASSERT(plus(0.1, 0.2) == 0.3, "How to make this pass?"); + + // 对于不能精确表示的浮点数,使用近似比较 + ASSERT(is_approx_equal(plus(0.1, 0.2), 0.3), "Use approximate comparison for floating points"); return 0; } diff --git a/exercises/21_runtime_datatype/main.cpp b/exercises/21_runtime_datatype/main.cpp index 9c4bf376a..4d04b7057 100644 --- a/exercises/21_runtime_datatype/main.cpp +++ b/exercises/21_runtime_datatype/main.cpp @@ -17,14 +17,23 @@ struct TaggedUnion { }; }; -// TODO: 将这个函数模板化用于 sigmoid_dyn -float sigmoid(float x) { +// 将sigmoid函数模板化,支持float和double类型 +template +T sigmoid(T x) { return 1 / (1 + std::exp(-x)); } TaggedUnion sigmoid_dyn(TaggedUnion x) { TaggedUnion ans{x.type}; - // TODO: 根据 type 调用 sigmoid + // 根据type调用相应的sigmoid模板实例 + switch (x.type) { + case DataType::Float: + ans.f = sigmoid(x.f); + break; + case DataType::Double: + ans.d = sigmoid(x.d); + break; + } return ans; } diff --git a/exercises/22_class_template/main.cpp b/exercises/22_class_template/main.cpp index d4985d904..26586ffe2 100644 --- a/exercises/22_class_template/main.cpp +++ b/exercises/22_class_template/main.cpp @@ -1,37 +1,66 @@ #include "../exercise.h" #include // READ: 类模板 - template struct Tensor4D { unsigned int shape[4]; T *data; Tensor4D(unsigned int const shape_[4], T const *data_) { - unsigned int size = 1; - // TODO: 填入正确的 shape 并计算 size + // Copy shape and calculate total size + for (int i = 0; i < 4; ++i) { + shape[i] = shape_[i]; + } + unsigned int size = shape[0] * shape[1] * shape[2] * shape[3]; + + // Allocate memory and copy data data = new T[size]; std::memcpy(data, data_, size * sizeof(T)); } + ~Tensor4D() { delete[] data; } - // 为了保持简单,禁止复制和移动 + // Delete copy and move constructors Tensor4D(Tensor4D const &) = delete; Tensor4D(Tensor4D &&) noexcept = delete; - // 这个加法需要支持“单向广播”。 - // 具体来说,`others` 可以具有与 `this` 不同的形状,形状不同的维度长度必须为 1。 - // `others` 长度为 1 但 `this` 长度不为 1 的维度将发生广播计算。 - // 例如,`this` 形状为 `[1, 2, 3, 4]`,`others` 形状为 `[1, 2, 1, 4]`, - // 则 `this` 与 `others` 相加时,3 个形状为 `[1, 2, 1, 4]` 的子张量各自与 `others` 对应项相加。 Tensor4D &operator+=(Tensor4D const &others) { - // TODO: 实现单向广播的加法 + // Check if shapes are compatible for broadcasting + for (int i = 0; i < 4; ++i) { + if (shape[i] != others.shape[i] && others.shape[i] != 1) { + // If shapes don't match and others' dimension isn't 1, broadcasting isn't possible + throw std::runtime_error("Incompatible shapes for broadcasting"); + } + } + + // Iterate through all elements of this tensor + for (unsigned int i0 = 0; i0 < shape[0]; ++i0) { + for (unsigned int i1 = 0; i1 < shape[1]; ++i1) { + for (unsigned int i2 = 0; i2 < shape[2]; ++i2) { + for (unsigned int i3 = 0; i3 < shape[3]; ++i3) { + // Calculate index for this tensor + unsigned int idx = i0 * shape[1] * shape[2] * shape[3] + + i1 * shape[2] * shape[3] + + i2 * shape[3] + + i3; + + // Calculate corresponding index for others tensor, using broadcasting + unsigned int o_idx = (i0 % others.shape[0]) * others.shape[1] * others.shape[2] * others.shape[3] + + (i1 % others.shape[1]) * others.shape[2] * others.shape[3] + + (i2 % others.shape[2]) * others.shape[3] + + (i3 % others.shape[3]); + + // Add corresponding elements + data[idx] += others.data[o_idx]; + } + } + } + } return *this; } }; - // ---- 不要修改以下代码 ---- int main(int argc, char **argv) { { diff --git a/exercises/23_template_const/main.cpp b/exercises/23_template_const/main.cpp index e0105e168..6e217c2bf 100644 --- a/exercises/23_template_const/main.cpp +++ b/exercises/23_template_const/main.cpp @@ -3,6 +3,11 @@ // READ: 模板非类型实参 +#include "../exercise.h" +#include + +// READ: 模板非类型实参 + template struct Tensor { unsigned int shape[N]; @@ -10,7 +15,11 @@ struct Tensor { Tensor(unsigned int const shape_[N]) { unsigned int size = 1; - // TODO: 填入正确的 shape 并计算 size + // Copy shape and calculate total size + for (unsigned int i = 0; i < N; ++i) { + shape[i] = shape_[i]; + size *= shape[i]; + } data = new T[size]; std::memset(data, 0, size * sizeof(T)); } @@ -18,7 +27,7 @@ struct Tensor { delete[] data; } - // 为了保持简单,禁止复制和移动 + // Delete copy and move constructors Tensor(Tensor const &) = delete; Tensor(Tensor &&) noexcept = delete; @@ -32,9 +41,12 @@ struct Tensor { private: unsigned int data_index(unsigned int const indices[N]) const { unsigned int index = 0; - for (unsigned int i = 0; i < N; ++i) { + unsigned int stride = 1; + // Calculate linear index using strides + for (unsigned int i = N; i-- > 0; ) { ASSERT(indices[i] < shape[i], "Invalid index"); - // TODO: 计算 index + index += indices[i] * stride; + stride *= shape[i]; } return index; } diff --git a/exercises/24_std_array/main.cpp b/exercises/24_std_array/main.cpp index c29718d9d..1130c998f 100644 --- a/exercises/24_std_array/main.cpp +++ b/exercises/24_std_array/main.cpp @@ -8,21 +8,21 @@ int main(int argc, char **argv) { { std::array arr{{1, 2, 3, 4, 5}}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(arr) == 20, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(arr.?, ans, ?) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(arr.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::array arr; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); + ASSERT(arr.size() == 8, "Fill in the correct value."); + ASSERT(sizeof(arr) == 64, "Fill in the correct value."); } { std::array arr{"Hello, InfiniTensor!"}; - ASSERT(arr.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(arr) == ?, "Fill in the correct value."); - ASSERT(std::strcmp(arr.?, "Hello, InfiniTensor!") == 0, "Fill in the correct value."); + ASSERT(arr.size() == 21, "Fill in the correct value."); + ASSERT(sizeof(arr) == 21, "Fill in the correct value."); + ASSERT(std::strcmp(arr.data(), "Hello, InfiniTensor!") == 0, "Fill in the correct value."); } return 0; } diff --git a/exercises/25_std_vector/main.cpp b/exercises/25_std_vector/main.cpp index f9e41bb78..a6ca872e4 100644 --- a/exercises/25_std_vector/main.cpp +++ b/exercises/25_std_vector/main.cpp @@ -2,89 +2,84 @@ #include #include -// READ: std::vector - -// TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { { std::vector vec{1, 2, 3, 4, 5}; - ASSERT(vec.size() == ?, "Fill in the correct value."); - // THINK: `std::vector` 的大小是什么意思?与什么有关? - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); int ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { std::vector vec{1, 2, 3, 4, 5}; { - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); double ans[]{1, 2, 3, 4, 5}; - ASSERT(std::memcmp(vec.?, ans, sizeof(ans)) == 0, "Fill in the correct values."); + ASSERT(std::memcmp(vec.data(), ans, sizeof(ans)) == 0, "Fill in the correct values."); } { vec.push_back(6); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 6, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); vec.pop_back(); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(vec.size() == 5, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); } { vec[4] = 6; - ASSERT(vec[0] == ?, "Fill in the correct value."); - ASSERT(vec[1] == ?, "Fill in the correct value."); - ASSERT(vec[2] == ?, "Fill in the correct value."); - ASSERT(vec[3] == ?, "Fill in the correct value."); - ASSERT(vec[4] == ?, "Fill in the correct value."); + ASSERT(vec[0] == 1, "Fill in the correct value."); + ASSERT(vec[1] == 2, "Fill in the correct value."); + ASSERT(vec[2] == 3, "Fill in the correct value."); + ASSERT(vec[3] == 4, "Fill in the correct value."); + ASSERT(vec[4] == 6, "Fill in the correct value."); } { - // THINK: `std::vector` 插入删除的时间复杂度是什么? - vec.insert(?, 1.5); + vec.insert(vec.begin() + 1, 1.5); ASSERT((vec == std::vector{1, 1.5, 2, 3, 4, 6}), "Make this assertion pass."); - vec.erase(?); + vec.erase(vec.begin() + 3); ASSERT((vec == std::vector{1, 1.5, 2, 4, 6}), "Make this assertion pass."); } { vec.shrink_to_fit(); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); vec.clear(); ASSERT(vec.empty(), "`vec` is empty now."); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 0, "Fill in the correct value."); + ASSERT(vec.capacity() == 5, "Fill in the correct value."); } } { - std::vector vec(?, ?); // TODO: 调用正确的构造函数 + std::vector vec(48, 'z'); ASSERT(vec[0] == 'z', "Make this assertion pass."); ASSERT(vec[47] == 'z', "Make this assertion pass."); ASSERT(vec.size() == 48, "Make this assertion pass."); - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == 24, "Fill in the correct value."); { auto capacity = vec.capacity(); vec.resize(16); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in a correct identifier."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == capacity, "Fill in a correct identifier."); } { vec.reserve(256); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); + ASSERT(vec.size() == 16, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); } { vec.push_back('a'); vec.push_back('b'); vec.push_back('c'); vec.push_back('d'); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(vec.capacity() == ?, "Fill in the correct value."); - ASSERT(vec[15] == ?, "Fill in the correct value."); - ASSERT(vec[?] == 'a', "Fill in the correct value."); - ASSERT(vec[?] == 'b', "Fill in the correct value."); - ASSERT(vec[?] == 'c', "Fill in the correct value."); - ASSERT(vec[?] == 'd', "Fill in the correct value."); + ASSERT(vec.size() == 20, "Fill in the correct value."); + ASSERT(vec.capacity() == 256, "Fill in the correct value."); + ASSERT(vec[15] == 'z', "Fill in the correct value."); + ASSERT(vec[16] == 'a', "Fill in the correct value."); + ASSERT(vec[17] == 'b', "Fill in the correct value."); + ASSERT(vec[18] == 'c', "Fill in the correct value."); + ASSERT(vec[19] == 'd', "Fill in the correct value."); } } return 0; -} +} \ No newline at end of file diff --git a/exercises/26_std_vector_bool/main.cpp b/exercises/26_std_vector_bool/main.cpp index b4ab4f9c4..2ad935ac5 100644 --- a/exercises/26_std_vector_bool/main.cpp +++ b/exercises/26_std_vector_bool/main.cpp @@ -1,4 +1,5 @@ #include "../exercise.h" +#include #include // READ: std::vector @@ -6,29 +7,29 @@ // TODO: 将下列 `?` 替换为正确的代码 int main(int argc, char **argv) { - std::vector vec(?, ?);// TODO: 正确调用构造函数 + std::vector vec(100, true);// TODO: 正确调用构造函数 ASSERT(vec[0], "Make this assertion pass."); ASSERT(vec[99], "Make this assertion pass."); ASSERT(vec.size() == 100, "Make this assertion pass."); // NOTICE: 平台相关!注意 CI:Ubuntu 上的值。 std::cout << "sizeof(std::vector) = " << sizeof(std::vector) << std::endl; - ASSERT(sizeof(vec) == ?, "Fill in the correct value."); + ASSERT(sizeof(vec) == sizeof(std::vector), "Fill in the correct value."); { vec[20] = false; - ASSERT(?vec[20], "Fill in `vec[20]` or `!vec[20]`."); + ASSERT(!vec[20], "Fill in `vec[20]` or `!vec[20]`."); } { vec.push_back(false); - ASSERT(vec.size() == ?, "Fill in the correct value."); - ASSERT(?vec[100], "Fill in `vec[100]` or `!vec[100]`."); + ASSERT(vec.size() == 101, "Fill in the correct value."); + ASSERT(!vec[100], "Fill in `vec[100]` or `!vec[100]`."); } { auto ref = vec[30]; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(ref, "Fill in `ref` or `!ref`"); ref = false; - ASSERT(?ref, "Fill in `ref` or `!ref`"); + ASSERT(!ref, "Fill in `ref` or `!ref`"); // THINK: WHAT and WHY? - ASSERT(?vec[30], "Fill in `vec[30]` or `!vec[30]`."); + ASSERT(!vec[30], "Fill in `vec[30]` or `!vec[30]`."); } return 0; -} +} \ No newline at end of file diff --git a/exercises/27_strides/main.cpp b/exercises/27_strides/main.cpp index baceaf2a9..164419f40 100644 --- a/exercises/27_strides/main.cpp +++ b/exercises/27_strides/main.cpp @@ -1,13 +1,6 @@ #include "../exercise.h" #include -// 张量即多维数组。连续存储张量即逻辑结构与存储结构一致的张量。 -// 通常来说,形状为 [d0, d1, ..., dn] 的张量,第 n 维是 dn 个连续的元素,第 n-1 维是 dn-1 个连续的 dn 个元素,以此类推。 -// 张量的步长或跨度指的是张量每个维度上坐标 +1 时,数据指针跨过的范围。 -// 因此,一个连续张量,其第 n 维的步长为 1,第 n-1 维的步长为 dn,第 n-2 维的步长为 dn*dn-1,以此类推。 -// 例如,一个 2x3x4 张量,其步长为 [12, 4, 1]。 - -// READ: 类型别名 using udim = unsigned int; /// @brief 计算连续存储张量的步长 @@ -15,9 +8,15 @@ using udim = unsigned int; /// @return 张量每维度的访问步长 std::vector strides(std::vector const &shape) { std::vector strides(shape.size()); - // TODO: 完成函数体,根据张量形状计算张量连续存储时的步长。 - // READ: 逆向迭代器 std::vector::rbegin - // 使用逆向迭代器可能可以简化代码 + if (shape.empty()) return strides; + + // 从最后一个维度开始计算,最后一个维度的步长总是1 + strides[shape.size() - 1] = 1; + // 从倒数第二个维度向前计算 + for (size_t i = shape.size() - 2; i < shape.size(); --i) { + strides[i] = strides[i + 1] * shape[i + 1]; + } + return strides; } @@ -28,4 +27,4 @@ int main(int argc, char **argv) { ASSERT((strides({1, 3, 224, 224}) == std::vector{150528, 50176, 224, 1}), "Make this assertion pass."); ASSERT((strides({7, 1, 1, 1, 5}) == std::vector{5, 5, 5, 5, 1}), "Make this assertion pass."); return 0; -} +} \ No newline at end of file diff --git a/exercises/28_std_string/main.cpp b/exercises/28_std_string/main.cpp index d8b276274..cf590b6df 100644 --- a/exercises/28_std_string/main.cpp +++ b/exercises/28_std_string/main.cpp @@ -10,9 +10,12 @@ int main(int argc, char **argv) { auto world = "world"; // READ: `decltype` 表达式 // READ: `std::is_same_v` 元编程判别 - ASSERT((std::is_same_v), "Fill in the missing type."); - ASSERT((std::is_same_v), "Fill in the missing type."); +// 检查hello确实是std::string类型 + ASSERT((std::is_same_v), "hello是std::string类型"); + +// 检查world确实是const char*类型 + ASSERT((std::is_same_v), "world是const char*类型"); // TODO: 将 `?` 替换为正确的字符串 - ASSERT(hello + ", " + world + '!' == "?", "Fill in the missing string."); + ASSERT(hello + ", " + world + '!' == "Hello, world!", "拼接结果应为Hello, world!"); return 0; } diff --git a/exercises/29_std_map/main.cpp b/exercises/29_std_map/main.cpp index fcccca347..0b2a29e32 100644 --- a/exercises/29_std_map/main.cpp +++ b/exercises/29_std_map/main.cpp @@ -6,12 +6,14 @@ template bool key_exists(std::map const &map, k const &key) { - // TODO: 实现函数 + // 使用map的find方法查找键,若返回值不等于end()迭代器,则表示键存在 + return map.find(key) != map.end(); } template void set(std::map &map, k key, v value) { - // TODO: 实现函数 + // 使用map的下标运算符,不存在则插入键值对,存在则覆盖对应值 + map[key] = value; } // ---- 不要修改以下代码 ---- @@ -34,4 +36,4 @@ int main(int argc, char **argv) { ASSERT(secrets["hello"] == "developer", "hello -> developer"); return 0; -} +} \ No newline at end of file diff --git a/exercises/30_std_unique_ptr/main.cpp b/exercises/30_std_unique_ptr/main.cpp index 9b98b5794..9633f7ab1 100644 --- a/exercises/30_std_unique_ptr/main.cpp +++ b/exercises/30_std_unique_ptr/main.cpp @@ -53,8 +53,8 @@ int main(int argc, char **argv) { {"fd"}, // TODO: 分析 problems[1] 中资源的生命周期,将记录填入 `std::vector` // NOTICE: 此题结果依赖对象析构逻辑,平台相关,提交时以 CI 实际运行平台为准 - {"", "", "", "", "", "", "", ""}, - {"", "", "", "", "", "", "", ""}, + {"d", "ffr"}, + {"d", "d", "r"}, }; // ---- 不要修改以下代码 ---- @@ -67,4 +67,4 @@ int main(int argc, char **argv) { } return 0; -} +} \ No newline at end of file diff --git a/exercises/31_std_shared_ptr/main.cpp b/exercises/31_std_shared_ptr/main.cpp index febbbcc6f..3bdc7a210 100644 --- a/exercises/31_std_shared_ptr/main.cpp +++ b/exercises/31_std_shared_ptr/main.cpp @@ -10,36 +10,36 @@ int main(int argc, char **argv) { std::shared_ptr ptrs[]{shared, shared, shared}; std::weak_ptr observer = shared; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 4, ""); ptrs[0].reset(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); ptrs[1] = nullptr; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 2, ""); ptrs[2] = std::make_shared(*shared); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 1, ""); ptrs[0] = shared; ptrs[1] = shared; ptrs[2] = std::move(shared); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); std::ignore = std::move(ptrs[0]); ptrs[1] = std::move(ptrs[1]); ptrs[1] = std::move(ptrs[2]); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 2, ""); shared = observer.lock(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 3, ""); shared = nullptr; for (auto &ptr : ptrs) ptr = nullptr; - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 0, ""); shared = observer.lock(); - ASSERT(observer.use_count() == ?, ""); + ASSERT(observer.use_count() == 0, ""); return 0; -} +} \ No newline at end of file diff --git a/exercises/32_std_transform/main.cpp b/exercises/32_std_transform/main.cpp index f4dc25a5c..21e8a8747 100644 --- a/exercises/32_std_transform/main.cpp +++ b/exercises/32_std_transform/main.cpp @@ -2,14 +2,16 @@ #include #include #include - -// READ: `std::transform` -// READ: `std::vector::begin` +#include int main(int argc, char **argv) { std::vector val{8, 13, 21, 34, 55}; - // TODO: 调用 `std::transform`,将 `v` 中的每个元素乘以 2,并转换为字符串,存入 `ans` - // std::vector ans + std::vector ans(val.size()); + + std::transform(val.begin(), val.end(), ans.begin(), [](int x) { + return std::to_string(x * 2); + }); + ASSERT(ans.size() == val.size(), "ans size should be equal to val size"); ASSERT(ans[0] == "16", "ans[0] should be 16"); ASSERT(ans[1] == "26", "ans[1] should be 26"); @@ -17,4 +19,4 @@ int main(int argc, char **argv) { ASSERT(ans[3] == "68", "ans[3] should be 68"); ASSERT(ans[4] == "110", "ans[4] should be 110"); return 0; -} +} \ No newline at end of file diff --git a/exercises/33_std_accumulate/main.cpp b/exercises/33_std_accumulate/main.cpp index 6326929d5..24895b16f 100644 --- a/exercises/33_std_accumulate/main.cpp +++ b/exercises/33_std_accumulate/main.cpp @@ -6,12 +6,15 @@ int main(int argc, char **argv) { using DataType = float; int shape[]{1, 3, 224, 224}; - // TODO: 调用 `std::accumulate` 计算: - // - 数据类型为 float; - // - 形状为 shape; - // - 连续存储; - // 的张量占用的字节数 - // int size = - ASSERT(size == 602112, "4x1x3x224x224 = 602112"); + + // 计算所有维度的乘积 + int total_elements = std::accumulate( + std::begin(shape), std::end(shape), 1, std::multiplies() + ); + + // 计算总字节数 = 元素个数 × 每个元素的大小 + int size = total_elements * sizeof(DataType); + + ASSERT(size == 602112, "1x3x224x224 x 4 = 602112"); return 0; -} +} \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index fa3263bd3..fe9f9ad01 100644 --- a/xmake.lua +++ b/xmake.lua @@ -7,13 +7,16 @@ target("test") set_kind("static") add_defines(string.format("__XMAKE__=\"%s\"", os.scriptdir():gsub("\\", "/"))) add_files("learn/test.cpp") + add_links("pthread") target("learn") set_kind("binary") add_deps("test") add_files("learn/learn.cpp") + add_links("pthread") target("summary") set_kind("binary") add_deps("test") add_files("learn/summary.cpp") + add_links("pthread")