summaryrefslogtreecommitdiffhomepage
path: root/zh-cn
diff options
context:
space:
mode:
authorBoris Verkhovskiy <boris.verk@gmail.com>2024-04-04 00:27:01 -0700
committerBoris Verkhovskiy <boris.verk@gmail.com>2024-04-04 00:27:01 -0700
commit818b8eec46b11b36b5235ecbce540557afec4687 (patch)
treef52126bebd376a14e86b895a40648c15d0d24bc0 /zh-cn
parent4ab1be1be5205a453127fe0ef595620a0cfb1624 (diff)
Convert \r\n to \n
Diffstat (limited to 'zh-cn')
-rw-r--r--zh-cn/c++-cn.html.markdown1144
-rw-r--r--zh-cn/elisp-cn.html.markdown690
-rw-r--r--zh-cn/matlab-cn.html.markdown1008
3 files changed, 1421 insertions, 1421 deletions
diff --git a/zh-cn/c++-cn.html.markdown b/zh-cn/c++-cn.html.markdown
index a6a61949..db36ebc4 100644
--- a/zh-cn/c++-cn.html.markdown
+++ b/zh-cn/c++-cn.html.markdown
@@ -1,572 +1,572 @@
----
-language: C++
-filename: learncpp-cn.cpp
-contributors:
- - ["Steven Basart", "http://github.com/xksteven"]
- - ["Matt Kline", "https://github.com/mrkline"]
-translators:
- - ["Arnie97", "https://github.com/Arnie97"]
-lang: zh-cn
----
-
-C++是一种系统编程语言。用它的发明者,
-[Bjarne Stroustrup的话](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote)来说,C++的设计目标是:
-
-- 成为“更好的C语言”
-- 支持数据的抽象与封装
-- 支持面向对象编程
-- 支持泛型编程
-
-C++提供了对硬件的紧密控制(正如C语言一样),
-能够编译为机器语言,由处理器直接执行。
-与此同时,它也提供了泛型、异常和类等高层功能。
-虽然C++的语法可能比某些出现较晚的语言更复杂,它仍然得到了人们的青睞——
-功能与速度的平衡使C++成为了目前应用最广泛的系统编程语言之一。
-
-```c++
-////////////////
-// 与C语言的比较
-////////////////
-
-// C++_几乎_是C语言的一个超集,它与C语言的基本语法有许多相同之处,
-// 例如变量和函数的声明,原生数据类型等等。
-
-// 和C语言一样,在C++中,你的程序会从main()开始执行,
-// 该函数的返回值应当为int型,这个返回值会作为程序的退出状态值。
-// 不过,大多数的编译器(gcc,clang等)也接受 void main() 的函数原型。
-// (参见 http://en.wikipedia.org/wiki/Exit_status 来获取更多信息)
-int main(int argc, char** argv)
-{
- // 和C语言一样,命令行参数通过argc和argv传递。
- // argc代表命令行参数的数量,
- // 而argv是一个包含“C语言风格字符串”(char *)的数组,
- // 其中每个字符串代表一个命令行参数的内容,
- // 首个命令行参数是调用该程序时所使用的名称。
- // 如果你不关心命令行参数的值,argc和argv可以被忽略。
- // 此时,你可以用int main()作为函数原型。
-
- // 退出状态值为0时,表示程序执行成功
- return 0;
-}
-
-// 然而,C++和C语言也有一些区别:
-
-// 在C++中,字符字面量的大小是一个字节。
-sizeof('c') == 1
-
-// 在C语言中,字符字面量的大小与int相同。
-sizeof('c') == sizeof(10)
-
-
-// C++的函数原型与函数定义是严格匹配的
-void func(); // 这个函数不能接受任何参数
-
-// 而在C语言中
-void func(); // 这个函数能接受任意数量的参数
-
-// 在C++中,用nullptr代替C语言中的NULL
-int* ip = nullptr;
-
-// C++也可以使用C语言的标准头文件,
-// 但是需要加上前缀“c”并去掉末尾的“.h”。
-#include <cstdio>
-
-int main()
-{
- printf("Hello, world!\n");
- return 0;
-}
-
-///////////
-// 函数重载
-///////////
-
-// C++支持函数重载,你可以定义一组名称相同而参数不同的函数。
-
-void print(char const* myString)
-{
- printf("String %s\n", myString);
-}
-
-void print(int myInt)
-{
- printf("My int is %d", myInt);
-}
-
-int main()
-{
- print("Hello"); // 解析为 void print(const char*)
- print(15); // 解析为 void print(int)
-}
-
-///////////////////
-// 函数参数的默认值
-///////////////////
-
-// 你可以为函数的参数指定默认值,
-// 它们将会在调用者没有提供相应参数时被使用。
-
-void doSomethingWithInts(int a = 1, int b = 4)
-{
- // 对两个参数进行一些操作
-}
-
-int main()
-{
- doSomethingWithInts(); // a = 1, b = 4
- doSomethingWithInts(20); // a = 20, b = 4
- doSomethingWithInts(20, 5); // a = 20, b = 5
-}
-
-// 默认参数必须放在所有的常规参数之后。
-
-void invalidDeclaration(int a = 1, int b) // 这是错误的!
-{
-}
-
-
-///////////
-// 命名空间
-///////////
-
-// 命名空间为变量、函数和其他声明提供了分离的的作用域。
-// 命名空间可以嵌套使用。
-
-namespace First {
- namespace Nested {
- void foo()
- {
- printf("This is First::Nested::foo\n");
- }
- } // 结束嵌套的命名空间Nested
-} // 结束命名空间First
-
-namespace Second {
- void foo()
- {
- printf("This is Second::foo\n")
- }
-}
-
-void foo()
-{
- printf("This is global foo\n");
-}
-
-int main()
-{
- // 如果没有特别指定,就从“Second”中取得所需的内容。
- using namespace Second;
-
- foo(); // 显示“This is Second::foo”
- First::Nested::foo(); // 显示“This is First::Nested::foo”
- ::foo(); // 显示“This is global foo”
-}
-
-////////////
-// 输入/输出
-////////////
-
-// C++使用“流”来输入输出。<<是流的插入运算符,>>是流提取运算符。
-// cin、cout、和cerr分别代表
-// stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。
-
-#include <iostream> // 引入包含输入/输出流的头文件
-
-using namespace std; // 输入输出流在std命名空间(也就是标准库)中。
-
-int main()
-{
- int myInt;
-
- // 在标准输出(终端/显示器)中显示
- cout << "Enter your favorite number:\n";
- // 从标准输入(键盘)获得一个值
- cin >> myInt;
-
- // cout也提供了格式化功能
- cout << "Your favorite number is " << myInt << "\n";
- // 显示“Your favorite number is <myInt>”
-
- cerr << "Used for error messages";
-}
-
-/////////
-// 字符串
-/////////
-
-// C++中的字符串是对象,它们有很多成员函数
-#include <string>
-
-using namespace std; // 字符串也在std命名空间(标准库)中。
-
-string myString = "Hello";
-string myOtherString = " World";
-
-// + 可以用于连接字符串。
-cout << myString + myOtherString; // "Hello World"
-
-cout << myString + " You"; // "Hello You"
-
-// C++中的字符串是可变的,具有“值语义”。
-myString.append(" Dog");
-cout << myString; // "Hello Dog"
-
-
-/////////////
-// 引用
-/////////////
-
-// 除了支持C语言中的指针类型以外,C++还提供了_引用_。
-// 引用是一种特殊的指针类型,一旦被定义就不能重新赋值,并且不能被设置为空值。
-// 使用引用时的语法与原变量相同:
-// 也就是说,对引用类型进行解引用时,不需要使用*;
-// 赋值时也不需要用&来取地址。
-
-using namespace std;
-
-string foo = "I am foo";
-string bar = "I am bar";
-
-
-string& fooRef = foo; // 建立了一个对foo的引用。
-fooRef += ". Hi!"; // 通过引用来修改foo的值
-cout << fooRef; // "I am foo. Hi!"
-
-// 这句话的并不会改变fooRef的指向,其效果与“foo = bar”相同。
-// 也就是说,在执行这条语句之后,foo == "I am bar"。
-fooRef = bar;
-
-const string& barRef = bar; // 建立指向bar的常量引用。
-// 和C语言中一样,(指针和引用)声明为常量时,对应的值不能被修改。
-barRef += ". Hi!"; // 这是错误的,不能修改一个常量引用的值。
-
-///////////////////
-// 类与面向对象编程
-///////////////////
-
-// 有关类的第一个示例
-#include <iostream>
-
-// 声明一个类。
-// 类通常在头文件(.h或.hpp)中声明。
-class Dog {
- // 成员变量和成员函数默认情况下是私有(private)的。
- std::string name;
- int weight;
-
-// 在这个标签之后,所有声明都是公有(public)的,
-// 直到重新指定“private:”(私有继承)或“protected:”(保护继承)为止
-public:
-
- // 默认的构造器
- Dog();
-
- // 这里是成员函数声明的一个例子。
- // 可以注意到,我们在此处使用了std::string,而不是using namespace std
- // 语句using namespace绝不应当出现在头文件当中。
- void setName(const std::string& dogsName);
-
- void setWeight(int dogsWeight);
-
- // 如果一个函数不对对象的状态进行修改,
- // 应当在声明中加上const。
- // 这样,你就可以对一个以常量方式引用的对象执行该操作。
- // 同时可以注意到,当父类的成员函数需要被子类重写时,
- // 父类中的函数必须被显式声明为_虚函数(virtual)_。
- // 考虑到性能方面的因素,函数默认情况下不会被声明为虚函数。
- virtual void print() const;
-
- // 函数也可以在class body内部定义。
- // 这样定义的函数会自动成为内联函数。
- void bark() const { std::cout << name << " barks!\n" }
-
- // 除了构造器以外,C++还提供了析构器。
- // 当一个对象被删除或者脱离其定义域时,它的析构函数会被调用。
- // 这使得RAII这样的强大范式(参见下文)成为可能。
- // 为了衍生出子类来,基类的析构函数必须定义为虚函数。
- virtual ~Dog();
-
-}; // 在类的定义之后,要加一个分号
-
-// 类的成员函数通常在.cpp文件中实现。
-void Dog::Dog()
-{
- std::cout << "A dog has been constructed\n";
-}
-
-// 对象(例如字符串)应当以引用的形式传递,
-// 对于不需要修改的对象,最好使用常量引用。
-void Dog::setName(const std::string& dogsName)
-{
- name = dogsName;
-}
-
-void Dog::setWeight(int dogsWeight)
-{
- weight = dogsWeight;
-}
-
-// 虚函数的virtual关键字只需要在声明时使用,不需要在定义时重复
-void Dog::print() const
-{
- std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
-}
-
-void Dog::~Dog()
-{
- std::cout << "Goodbye " << name << "\n";
-}
-
-int main() {
- Dog myDog; // 此时显示“A dog has been constructed”
- myDog.setName("Barkley");
- myDog.setWeight(10);
- myDog.print(); // 显示“Dog is Barkley and weighs 10 kg”
- return 0;
-} // 显示“Goodbye Barkley”
-
-// 继承:
-
-// 这个类继承了Dog类中的公有(public)和保护(protected)对象
-class OwnedDog : public Dog {
-
- void setOwner(const std::string& dogsOwner)
-
- // 重写OwnedDogs类的print方法。
- // 如果你不熟悉子类多态的话,可以参考这个页面中的概述:
- // http://zh.wikipedia.org/wiki/%E5%AD%90%E7%B1%BB%E5%9E%8B
-
- // override关键字是可选的,它确保你所重写的是基类中的方法。
- void print() const override;
-
-private:
- std::string owner;
-};
-
-// 与此同时,在对应的.cpp文件里:
-
-void OwnedDog::setOwner(const std::string& dogsOwner)
-{
- owner = dogsOwner;
-}
-
-void OwnedDog::print() const
-{
- Dog::print(); // 调用基类Dog中的print方法
- // "Dog is <name> and weights <weight>"
-
- std::cout << "Dog is owned by " << owner << "\n";
- // "Dog is owned by <owner>"
-}
-
-/////////////////////
-// 初始化与运算符重载
-/////////////////////
-
-// 在C++中,通过定义一些特殊名称的函数,
-// 你可以重载+、-、*、/等运算符的行为。
-// 当运算符被使用时,这些特殊函数会被调用,从而实现运算符重载。
-
-#include <iostream>
-using namespace std;
-
-class Point {
-public:
- // 可以以这样的方式为成员变量设置默认值。
- double x = 0;
- double y = 0;
-
- // 定义一个默认的构造器。
- // 除了将Point初始化为(0, 0)以外,这个函数什么都不做。
- Point() { };
-
- // 下面使用的语法称为初始化列表,
- // 这是初始化类中成员变量的正确方式。
- Point (double a, double b) :
- x(a),
- y(b)
- { /* 除了初始化成员变量外,什么都不做 */ }
-
- // 重载 + 运算符
- Point operator+(const Point& rhs) const;
-
- // 重载 += 运算符
- Point& operator+=(const Point& rhs);
-
- // 增加 - 和 -= 运算符也是有意义的,但这里不再赘述。
-};
-
-Point Point::operator+(const Point& rhs) const
-{
- // 创建一个新的点,
- // 其横纵坐标分别为这个点与另一点在对应方向上的坐标之和。
- return Point(x + rhs.x, y + rhs.y);
-}
-
-Point& Point::operator+=(const Point& rhs)
-{
- x += rhs.x;
- y += rhs.y;
- return *this;
-}
-
-int main () {
- Point up (0,1);
- Point right (1,0);
- // 这里使用了Point类型的运算符“+”
- // 调用up(Point类型)的“+”方法,并以right作为函数的参数
- Point result = up + right;
- // 显示“Result is upright (1,1)”
- cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
- return 0;
-}
-
-///////////
-// 异常处理
-///////////
-
-// 标准库中提供了一些基本的异常类型
-// (参见http://en.cppreference.com/w/cpp/error/exception)
-// 但是,其他任何类型也可以作为一个异常被拋出
-#include <exception>
-
-// 在_try_代码块中拋出的异常可以被随后的_catch_捕获。
-try {
- // 不要用 _new_关键字在堆上为异常分配空间。
- throw std::exception("A problem occurred");
-}
-// 如果拋出的异常是一个对象,可以用常量引用来捕获它
-catch (const std::exception& ex)
-{
- std::cout << ex.what();
-// 捕获尚未被_catch_处理的所有错误
-} catch (...)
-{
- std::cout << "Unknown exception caught";
- throw; // 重新拋出异常
-}
-
-///////
-// RAII
-///////
-
-// RAII指的是“资源获取就是初始化”(Resource Allocation Is Initialization),
-// 它被视作C++中最强大的编程范式之一。
-// 简单说来,它指的是,用构造函数来获取一个对象的资源,
-// 相应的,借助析构函数来释放对象的资源。
-
-// 为了理解这一范式的用处,让我们考虑某个函数使用文件句柄时的情况:
-void doSomethingWithAFile(const char* filename)
-{
- // 首先,让我们假设一切都会顺利进行。
-
- FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
-
- doSomethingWithTheFile(fh);
- doSomethingElseWithIt(fh);
-
- fclose(fh); // 关闭文件句柄
-}
-
-// 不幸的是,随着错误处理机制的引入,事情会变得复杂。
-// 假设fopen函数有可能执行失败,
-// 而doSomethingWithTheFile和doSomethingElseWithIt会在失败时返回错误代码。
-// (虽然异常是C++中处理错误的推荐方式,
-// 但是某些程序员,尤其是有C语言背景的,并不认可异常捕获机制的作用)。
-// 现在,我们必须检查每个函数调用是否成功执行,并在问题发生的时候关闭文件句柄。
-bool doSomethingWithAFile(const char* filename)
-{
- FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
- if (fh == nullptr) // 当执行失败是,返回的指针是nullptr
- return false; // 向调用者汇报错误
-
- // 假设每个函数会在执行失败时返回false
- if (!doSomethingWithTheFile(fh)) {
- fclose(fh); // 关闭文件句柄,避免造成内存泄漏。
- return false; // 反馈错误
- }
- if (!doSomethingElseWithIt(fh)) {
- fclose(fh); // 关闭文件句柄
- return false; // 反馈错误
- }
-
- fclose(fh); // 关闭文件句柄
- return true; // 指示函数已成功执行
-}
-
-// C语言的程序员通常会借助goto语句简化上面的代码:
-bool doSomethingWithAFile(const char* filename)
-{
- FILE* fh = fopen(filename, "r");
- if (fh == nullptr)
- return false;
-
- if (!doSomethingWithTheFile(fh))
- goto failure;
-
- if (!doSomethingElseWithIt(fh))
- goto failure;
-
- fclose(fh); // 关闭文件
- return true; // 执行成功
-
-failure:
- fclose(fh);
- return false; // 反馈错误
-}
-
-// 如果用异常捕获机制来指示错误的话,
-// 代码会变得清晰一些,但是仍然有优化的余地。
-void doSomethingWithAFile(const char* filename)
-{
- FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
- if (fh == nullptr)
- throw std::exception("Could not open the file.");
-
- try {
- doSomethingWithTheFile(fh);
- doSomethingElseWithIt(fh);
- }
- catch (...) {
- fclose(fh); // 保证出错的时候文件被正确关闭
- throw; // 之后,重新抛出这个异常
- }
-
- fclose(fh); // 关闭文件
- // 所有工作顺利完成
-}
-
-// 相比之下,使用C++中的文件流类(fstream)时,
-// fstream会利用自己的析构器来关闭文件句柄。
-// 只要离开了某一对象的定义域,它的析构函数就会被自动调用。
-void doSomethingWithAFile(const std::string& filename)
-{
- // ifstream是输入文件流(input file stream)的简称
- std::ifstream fh(filename); // 打开一个文件
-
- // 对文件进行一些操作
- doSomethingWithTheFile(fh);
- doSomethingElseWithIt(fh);
-
-} // 文件已经被析构器自动关闭
-
-// 与上面几种方式相比,这种方式有着_明显_的优势:
-// 1. 无论发生了什么情况,资源(此例当中是文件句柄)都会被正确关闭。
-// 只要你正确使用了析构器,就_不会_因为忘记关闭句柄,造成资源的泄漏。
-// 2. 可以注意到,通过这种方式写出来的代码十分简洁。
-// 析构器会在后台关闭文件句柄,不再需要你来操心这些琐事。
-// 3. 这种方式的代码具有异常安全性。
-// 无论在函数中的何处拋出异常,都不会阻碍对文件资源的释放。
-
-// 地道的C++代码应当把RAII的使用扩展到各种类型的资源上,包括:
-// - 用unique_ptr和shared_ptr管理的内存
-// - 各种数据容器,例如标准库中的链表、向量(容量自动扩展的数组)、散列表等;
-// 当它们脱离作用域时,析构器会自动释放其中储存的内容。
-// - 用lock_guard和unique_lock实现的互斥
-```
-扩展阅读:
-
-* [CPP Reference](http://cppreference.com/w/cpp) 提供了最新的语法参考。
-* 可以在 [CPlusPlus](http://cplusplus.com) 找到一些补充资料。
-* 可以在 [TheChernoProject - C ++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb)上找到涵盖语言基础和设置编码环境的教程。
+---
+language: C++
+filename: learncpp-cn.cpp
+contributors:
+ - ["Steven Basart", "http://github.com/xksteven"]
+ - ["Matt Kline", "https://github.com/mrkline"]
+translators:
+ - ["Arnie97", "https://github.com/Arnie97"]
+lang: zh-cn
+---
+
+C++是一种系统编程语言。用它的发明者,
+[Bjarne Stroustrup的话](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote)来说,C++的设计目标是:
+
+- 成为“更好的C语言”
+- 支持数据的抽象与封装
+- 支持面向对象编程
+- 支持泛型编程
+
+C++提供了对硬件的紧密控制(正如C语言一样),
+能够编译为机器语言,由处理器直接执行。
+与此同时,它也提供了泛型、异常和类等高层功能。
+虽然C++的语法可能比某些出现较晚的语言更复杂,它仍然得到了人们的青睞——
+功能与速度的平衡使C++成为了目前应用最广泛的系统编程语言之一。
+
+```c++
+////////////////
+// 与C语言的比较
+////////////////
+
+// C++_几乎_是C语言的一个超集,它与C语言的基本语法有许多相同之处,
+// 例如变量和函数的声明,原生数据类型等等。
+
+// 和C语言一样,在C++中,你的程序会从main()开始执行,
+// 该函数的返回值应当为int型,这个返回值会作为程序的退出状态值。
+// 不过,大多数的编译器(gcc,clang等)也接受 void main() 的函数原型。
+// (参见 http://en.wikipedia.org/wiki/Exit_status 来获取更多信息)
+int main(int argc, char** argv)
+{
+ // 和C语言一样,命令行参数通过argc和argv传递。
+ // argc代表命令行参数的数量,
+ // 而argv是一个包含“C语言风格字符串”(char *)的数组,
+ // 其中每个字符串代表一个命令行参数的内容,
+ // 首个命令行参数是调用该程序时所使用的名称。
+ // 如果你不关心命令行参数的值,argc和argv可以被忽略。
+ // 此时,你可以用int main()作为函数原型。
+
+ // 退出状态值为0时,表示程序执行成功
+ return 0;
+}
+
+// 然而,C++和C语言也有一些区别:
+
+// 在C++中,字符字面量的大小是一个字节。
+sizeof('c') == 1
+
+// 在C语言中,字符字面量的大小与int相同。
+sizeof('c') == sizeof(10)
+
+
+// C++的函数原型与函数定义是严格匹配的
+void func(); // 这个函数不能接受任何参数
+
+// 而在C语言中
+void func(); // 这个函数能接受任意数量的参数
+
+// 在C++中,用nullptr代替C语言中的NULL
+int* ip = nullptr;
+
+// C++也可以使用C语言的标准头文件,
+// 但是需要加上前缀“c”并去掉末尾的“.h”。
+#include <cstdio>
+
+int main()
+{
+ printf("Hello, world!\n");
+ return 0;
+}
+
+///////////
+// 函数重载
+///////////
+
+// C++支持函数重载,你可以定义一组名称相同而参数不同的函数。
+
+void print(char const* myString)
+{
+ printf("String %s\n", myString);
+}
+
+void print(int myInt)
+{
+ printf("My int is %d", myInt);
+}
+
+int main()
+{
+ print("Hello"); // 解析为 void print(const char*)
+ print(15); // 解析为 void print(int)
+}
+
+///////////////////
+// 函数参数的默认值
+///////////////////
+
+// 你可以为函数的参数指定默认值,
+// 它们将会在调用者没有提供相应参数时被使用。
+
+void doSomethingWithInts(int a = 1, int b = 4)
+{
+ // 对两个参数进行一些操作
+}
+
+int main()
+{
+ doSomethingWithInts(); // a = 1, b = 4
+ doSomethingWithInts(20); // a = 20, b = 4
+ doSomethingWithInts(20, 5); // a = 20, b = 5
+}
+
+// 默认参数必须放在所有的常规参数之后。
+
+void invalidDeclaration(int a = 1, int b) // 这是错误的!
+{
+}
+
+
+///////////
+// 命名空间
+///////////
+
+// 命名空间为变量、函数和其他声明提供了分离的的作用域。
+// 命名空间可以嵌套使用。
+
+namespace First {
+ namespace Nested {
+ void foo()
+ {
+ printf("This is First::Nested::foo\n");
+ }
+ } // 结束嵌套的命名空间Nested
+} // 结束命名空间First
+
+namespace Second {
+ void foo()
+ {
+ printf("This is Second::foo\n")
+ }
+}
+
+void foo()
+{
+ printf("This is global foo\n");
+}
+
+int main()
+{
+ // 如果没有特别指定,就从“Second”中取得所需的内容。
+ using namespace Second;
+
+ foo(); // 显示“This is Second::foo”
+ First::Nested::foo(); // 显示“This is First::Nested::foo”
+ ::foo(); // 显示“This is global foo”
+}
+
+////////////
+// 输入/输出
+////////////
+
+// C++使用“流”来输入输出。<<是流的插入运算符,>>是流提取运算符。
+// cin、cout、和cerr分别代表
+// stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。
+
+#include <iostream> // 引入包含输入/输出流的头文件
+
+using namespace std; // 输入输出流在std命名空间(也就是标准库)中。
+
+int main()
+{
+ int myInt;
+
+ // 在标准输出(终端/显示器)中显示
+ cout << "Enter your favorite number:\n";
+ // 从标准输入(键盘)获得一个值
+ cin >> myInt;
+
+ // cout也提供了格式化功能
+ cout << "Your favorite number is " << myInt << "\n";
+ // 显示“Your favorite number is <myInt>”
+
+ cerr << "Used for error messages";
+}
+
+/////////
+// 字符串
+/////////
+
+// C++中的字符串是对象,它们有很多成员函数
+#include <string>
+
+using namespace std; // 字符串也在std命名空间(标准库)中。
+
+string myString = "Hello";
+string myOtherString = " World";
+
+// + 可以用于连接字符串。
+cout << myString + myOtherString; // "Hello World"
+
+cout << myString + " You"; // "Hello You"
+
+// C++中的字符串是可变的,具有“值语义”。
+myString.append(" Dog");
+cout << myString; // "Hello Dog"
+
+
+/////////////
+// 引用
+/////////////
+
+// 除了支持C语言中的指针类型以外,C++还提供了_引用_。
+// 引用是一种特殊的指针类型,一旦被定义就不能重新赋值,并且不能被设置为空值。
+// 使用引用时的语法与原变量相同:
+// 也就是说,对引用类型进行解引用时,不需要使用*;
+// 赋值时也不需要用&来取地址。
+
+using namespace std;
+
+string foo = "I am foo";
+string bar = "I am bar";
+
+
+string& fooRef = foo; // 建立了一个对foo的引用。
+fooRef += ". Hi!"; // 通过引用来修改foo的值
+cout << fooRef; // "I am foo. Hi!"
+
+// 这句话的并不会改变fooRef的指向,其效果与“foo = bar”相同。
+// 也就是说,在执行这条语句之后,foo == "I am bar"。
+fooRef = bar;
+
+const string& barRef = bar; // 建立指向bar的常量引用。
+// 和C语言中一样,(指针和引用)声明为常量时,对应的值不能被修改。
+barRef += ". Hi!"; // 这是错误的,不能修改一个常量引用的值。
+
+///////////////////
+// 类与面向对象编程
+///////////////////
+
+// 有关类的第一个示例
+#include <iostream>
+
+// 声明一个类。
+// 类通常在头文件(.h或.hpp)中声明。
+class Dog {
+ // 成员变量和成员函数默认情况下是私有(private)的。
+ std::string name;
+ int weight;
+
+// 在这个标签之后,所有声明都是公有(public)的,
+// 直到重新指定“private:”(私有继承)或“protected:”(保护继承)为止
+public:
+
+ // 默认的构造器
+ Dog();
+
+ // 这里是成员函数声明的一个例子。
+ // 可以注意到,我们在此处使用了std::string,而不是using namespace std
+ // 语句using namespace绝不应当出现在头文件当中。
+ void setName(const std::string& dogsName);
+
+ void setWeight(int dogsWeight);
+
+ // 如果一个函数不对对象的状态进行修改,
+ // 应当在声明中加上const。
+ // 这样,你就可以对一个以常量方式引用的对象执行该操作。
+ // 同时可以注意到,当父类的成员函数需要被子类重写时,
+ // 父类中的函数必须被显式声明为_虚函数(virtual)_。
+ // 考虑到性能方面的因素,函数默认情况下不会被声明为虚函数。
+ virtual void print() const;
+
+ // 函数也可以在class body内部定义。
+ // 这样定义的函数会自动成为内联函数。
+ void bark() const { std::cout << name << " barks!\n" }
+
+ // 除了构造器以外,C++还提供了析构器。
+ // 当一个对象被删除或者脱离其定义域时,它的析构函数会被调用。
+ // 这使得RAII这样的强大范式(参见下文)成为可能。
+ // 为了衍生出子类来,基类的析构函数必须定义为虚函数。
+ virtual ~Dog();
+
+}; // 在类的定义之后,要加一个分号
+
+// 类的成员函数通常在.cpp文件中实现。
+void Dog::Dog()
+{
+ std::cout << "A dog has been constructed\n";
+}
+
+// 对象(例如字符串)应当以引用的形式传递,
+// 对于不需要修改的对象,最好使用常量引用。
+void Dog::setName(const std::string& dogsName)
+{
+ name = dogsName;
+}
+
+void Dog::setWeight(int dogsWeight)
+{
+ weight = dogsWeight;
+}
+
+// 虚函数的virtual关键字只需要在声明时使用,不需要在定义时重复
+void Dog::print() const
+{
+ std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
+}
+
+void Dog::~Dog()
+{
+ std::cout << "Goodbye " << name << "\n";
+}
+
+int main() {
+ Dog myDog; // 此时显示“A dog has been constructed”
+ myDog.setName("Barkley");
+ myDog.setWeight(10);
+ myDog.print(); // 显示“Dog is Barkley and weighs 10 kg”
+ return 0;
+} // 显示“Goodbye Barkley”
+
+// 继承:
+
+// 这个类继承了Dog类中的公有(public)和保护(protected)对象
+class OwnedDog : public Dog {
+
+ void setOwner(const std::string& dogsOwner)
+
+ // 重写OwnedDogs类的print方法。
+ // 如果你不熟悉子类多态的话,可以参考这个页面中的概述:
+ // http://zh.wikipedia.org/wiki/%E5%AD%90%E7%B1%BB%E5%9E%8B
+
+ // override关键字是可选的,它确保你所重写的是基类中的方法。
+ void print() const override;
+
+private:
+ std::string owner;
+};
+
+// 与此同时,在对应的.cpp文件里:
+
+void OwnedDog::setOwner(const std::string& dogsOwner)
+{
+ owner = dogsOwner;
+}
+
+void OwnedDog::print() const
+{
+ Dog::print(); // 调用基类Dog中的print方法
+ // "Dog is <name> and weights <weight>"
+
+ std::cout << "Dog is owned by " << owner << "\n";
+ // "Dog is owned by <owner>"
+}
+
+/////////////////////
+// 初始化与运算符重载
+/////////////////////
+
+// 在C++中,通过定义一些特殊名称的函数,
+// 你可以重载+、-、*、/等运算符的行为。
+// 当运算符被使用时,这些特殊函数会被调用,从而实现运算符重载。
+
+#include <iostream>
+using namespace std;
+
+class Point {
+public:
+ // 可以以这样的方式为成员变量设置默认值。
+ double x = 0;
+ double y = 0;
+
+ // 定义一个默认的构造器。
+ // 除了将Point初始化为(0, 0)以外,这个函数什么都不做。
+ Point() { };
+
+ // 下面使用的语法称为初始化列表,
+ // 这是初始化类中成员变量的正确方式。
+ Point (double a, double b) :
+ x(a),
+ y(b)
+ { /* 除了初始化成员变量外,什么都不做 */ }
+
+ // 重载 + 运算符
+ Point operator+(const Point& rhs) const;
+
+ // 重载 += 运算符
+ Point& operator+=(const Point& rhs);
+
+ // 增加 - 和 -= 运算符也是有意义的,但这里不再赘述。
+};
+
+Point Point::operator+(const Point& rhs) const
+{
+ // 创建一个新的点,
+ // 其横纵坐标分别为这个点与另一点在对应方向上的坐标之和。
+ return Point(x + rhs.x, y + rhs.y);
+}
+
+Point& Point::operator+=(const Point& rhs)
+{
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+}
+
+int main () {
+ Point up (0,1);
+ Point right (1,0);
+ // 这里使用了Point类型的运算符“+”
+ // 调用up(Point类型)的“+”方法,并以right作为函数的参数
+ Point result = up + right;
+ // 显示“Result is upright (1,1)”
+ cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
+ return 0;
+}
+
+///////////
+// 异常处理
+///////////
+
+// 标准库中提供了一些基本的异常类型
+// (参见http://en.cppreference.com/w/cpp/error/exception)
+// 但是,其他任何类型也可以作为一个异常被拋出
+#include <exception>
+
+// 在_try_代码块中拋出的异常可以被随后的_catch_捕获。
+try {
+ // 不要用 _new_关键字在堆上为异常分配空间。
+ throw std::exception("A problem occurred");
+}
+// 如果拋出的异常是一个对象,可以用常量引用来捕获它
+catch (const std::exception& ex)
+{
+ std::cout << ex.what();
+// 捕获尚未被_catch_处理的所有错误
+} catch (...)
+{
+ std::cout << "Unknown exception caught";
+ throw; // 重新拋出异常
+}
+
+///////
+// RAII
+///////
+
+// RAII指的是“资源获取就是初始化”(Resource Allocation Is Initialization),
+// 它被视作C++中最强大的编程范式之一。
+// 简单说来,它指的是,用构造函数来获取一个对象的资源,
+// 相应的,借助析构函数来释放对象的资源。
+
+// 为了理解这一范式的用处,让我们考虑某个函数使用文件句柄时的情况:
+void doSomethingWithAFile(const char* filename)
+{
+ // 首先,让我们假设一切都会顺利进行。
+
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+
+ fclose(fh); // 关闭文件句柄
+}
+
+// 不幸的是,随着错误处理机制的引入,事情会变得复杂。
+// 假设fopen函数有可能执行失败,
+// 而doSomethingWithTheFile和doSomethingElseWithIt会在失败时返回错误代码。
+// (虽然异常是C++中处理错误的推荐方式,
+// 但是某些程序员,尤其是有C语言背景的,并不认可异常捕获机制的作用)。
+// 现在,我们必须检查每个函数调用是否成功执行,并在问题发生的时候关闭文件句柄。
+bool doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+ if (fh == nullptr) // 当执行失败是,返回的指针是nullptr
+ return false; // 向调用者汇报错误
+
+ // 假设每个函数会在执行失败时返回false
+ if (!doSomethingWithTheFile(fh)) {
+ fclose(fh); // 关闭文件句柄,避免造成内存泄漏。
+ return false; // 反馈错误
+ }
+ if (!doSomethingElseWithIt(fh)) {
+ fclose(fh); // 关闭文件句柄
+ return false; // 反馈错误
+ }
+
+ fclose(fh); // 关闭文件句柄
+ return true; // 指示函数已成功执行
+}
+
+// C语言的程序员通常会借助goto语句简化上面的代码:
+bool doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r");
+ if (fh == nullptr)
+ return false;
+
+ if (!doSomethingWithTheFile(fh))
+ goto failure;
+
+ if (!doSomethingElseWithIt(fh))
+ goto failure;
+
+ fclose(fh); // 关闭文件
+ return true; // 执行成功
+
+failure:
+ fclose(fh);
+ return false; // 反馈错误
+}
+
+// 如果用异常捕获机制来指示错误的话,
+// 代码会变得清晰一些,但是仍然有优化的余地。
+void doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+ if (fh == nullptr)
+ throw std::exception("Could not open the file.");
+
+ try {
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+ }
+ catch (...) {
+ fclose(fh); // 保证出错的时候文件被正确关闭
+ throw; // 之后,重新抛出这个异常
+ }
+
+ fclose(fh); // 关闭文件
+ // 所有工作顺利完成
+}
+
+// 相比之下,使用C++中的文件流类(fstream)时,
+// fstream会利用自己的析构器来关闭文件句柄。
+// 只要离开了某一对象的定义域,它的析构函数就会被自动调用。
+void doSomethingWithAFile(const std::string& filename)
+{
+ // ifstream是输入文件流(input file stream)的简称
+ std::ifstream fh(filename); // 打开一个文件
+
+ // 对文件进行一些操作
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+
+} // 文件已经被析构器自动关闭
+
+// 与上面几种方式相比,这种方式有着_明显_的优势:
+// 1. 无论发生了什么情况,资源(此例当中是文件句柄)都会被正确关闭。
+// 只要你正确使用了析构器,就_不会_因为忘记关闭句柄,造成资源的泄漏。
+// 2. 可以注意到,通过这种方式写出来的代码十分简洁。
+// 析构器会在后台关闭文件句柄,不再需要你来操心这些琐事。
+// 3. 这种方式的代码具有异常安全性。
+// 无论在函数中的何处拋出异常,都不会阻碍对文件资源的释放。
+
+// 地道的C++代码应当把RAII的使用扩展到各种类型的资源上,包括:
+// - 用unique_ptr和shared_ptr管理的内存
+// - 各种数据容器,例如标准库中的链表、向量(容量自动扩展的数组)、散列表等;
+// 当它们脱离作用域时,析构器会自动释放其中储存的内容。
+// - 用lock_guard和unique_lock实现的互斥
+```
+扩展阅读:
+
+* [CPP Reference](http://cppreference.com/w/cpp) 提供了最新的语法参考。
+* 可以在 [CPlusPlus](http://cplusplus.com) 找到一些补充资料。
+* 可以在 [TheChernoProject - C ++](https://www.youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb)上找到涵盖语言基础和设置编码环境的教程。
diff --git a/zh-cn/elisp-cn.html.markdown b/zh-cn/elisp-cn.html.markdown
index 3f6ccbcf..a429fcbc 100644
--- a/zh-cn/elisp-cn.html.markdown
+++ b/zh-cn/elisp-cn.html.markdown
@@ -1,345 +1,345 @@
----
-language: elisp
-contributors:
- - ["Bastien Guerry", "http://bzg.fr"]
-translators:
- - ["Chenbo Li", "http://binarythink.net"]
-filename: learn-emacs-lisp-zh.el
-lang: zh-cn
----
-
-```scheme
-;; 15分钟学会Emacs Lisp (v0.2a)
-;;(作者:bzg,https://github.com/bzg
-;; 译者:lichenbo,http://douban.com/people/lichenbo)
-;;
-;; 请先阅读Peter Norvig的一篇好文:
-;; http://norvig.com/21-days.html
-;; (译者注:中文版请见http://blog.youxu.info/21-days/)
-;;
-;; 之后安装GNU Emacs 24.3:
-;;
-;; Debian: apt-get install emacs (视具体发行版而定)
-;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
-;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
-;;
-;; 更多信息可以在这里找到:
-;; http://www.gnu.org/software/emacs/#Obtaining
-
-;; 很重要的警告:
-;;
-;; 按照这个教程来学习并不会对你的电脑有任何损坏
-;; 除非你自己在学习的过程中愤怒地把它砸了
-;; 如果出现了这种情况,我不会承担任何责任
-;;
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; 打开emacs
-;;
-;; 按'q'消除欢迎界面
-;;
-;; 现在请注意窗口底部的那一个灰色长条
-;;
-;; "*scratch*" 是你现在编辑界面的名字。
-;; 这个编辑界面叫做一个"buffer"。
-;;
-;; 每当你打开Emacs时,都会默认打开这个scratch buffer
-;; 此时你并没有在编辑任何文件,而是在编辑一个buffer
-;; 之后你可以将这个buffer保存到一个文件中。
-;;
-;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令
-;;
-;; Emacs在每个buffer中都有一组内置的命令
-;; 而当你激活某种特定的模式时,就可以使用相应的命令
-;; 这里我们使用`lisp-interaction-mode',
-;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; 分号是注释开始的标志
-;;
-;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"):
-(+ 2 2)
-
-;; 这个s式的意思是 "对2进行加2操作".
-
-;; s式周围有括号,而且也可以嵌套:
-(+ 2 (+ 1 1))
-
-;; 一个s式可以包含原子符号或者其他s式
-;; 在上面的例子中,1和2是原子符号
-;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式.
-
-;; 在 `lisp-interaction-mode' 中你可以计算s式.
-;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j')
-
-(+ 3 (+ 1 2))
-;; ^ 光标放到这里
-;; 按下`C-j' 就会输出 6
-
-;; `C-j' 会在buffer中插入当前运算的结果
-
-;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域
-;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e'
-
-;; `setq' 可以将一个值赋给一个变量
-(setq my-name "Bastien")
-;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示)
-
-;; `insert' 会在光标处插入字符串:
-(insert "Hello!")
-;; `C-xC-e' 输出 "Hello!"
-
-;; 在这里我们只传给了insert一个参数"Hello!", 但是
-;; 我们也可以传给它更多的参数,比如2个:
-
-(insert "Hello" " world!")
-;; `C-xC-e' 输出 "Hello world!"
-
-;; 你也可以用变量名来代替字符串
-(insert "Hello, I am " my-name)
-;; `C-xC-e' 输出 "Hello, I am Bastien"
-
-;; 你可以把s式嵌入函数中
-(defun hello () (insert "Hello, I am " my-name))
-;; `C-xC-e' 输出 hello
-
-;; 现在执行这个函数
-(hello)
-;; `C-xC-e' 输出 Hello, I am Bastien
-
-;; 函数中空括号的意思是我们不需要接受任何参数
-;; 但是我们不能一直总是用my-name这个变量
-;; 所以我们现在使我们的函数接受一个叫做"name"的参数
-
-(defun hello (name) (insert "Hello " name))
-;; `C-xC-e' 输出 hello
-
-;; 现在我们调用这个函数,并且将"you"作为参数传递
-
-(hello "you")
-;; `C-xC-e' 输出 "Hello you"
-
-;; 成功!
-
-;; 现在我们可以休息一下
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer:
-
-(switch-to-buffer-other-window "*test*")
-;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
-
-;; 用鼠标单击上面的buffer就会使光标移回。
-;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中
-
-;; 你可以用 `progn'命令将s式结合起来:
-(progn
- (switch-to-buffer-other-window "*test*")
- (hello "you"))
-;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you"
-
-;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了
-
-;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。
-
-;; 清除当前buffer也是常用操作之一:
-(progn
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- (hello "there"))
-
-;; 也可以回到其他的窗口中
-(progn
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- (hello "you")
- (other-window 1))
-
-;; 你可以用 `let' 将一个值和一个局部变量绑定:
-(let ((local-name "you"))
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- (hello local-name)
- (other-window 1))
-
-;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。
-
-;; 格式化字符串的方法:
-(format "Hello %s!\n" "visitor")
-
-;; %s 是字符串占位符,这里被"visitor"替代.
-;; \n 是换行符。
-
-;; 现在我们用格式化的方法再重写一下我们的函数:
-(defun hello (name)
- (insert (format "Hello %s!\n" name)))
-
-(hello "you")
-
-;; 我们再用`let'新建另一个函数:
-(defun greeting (name)
- (let ((your-name "Bastien"))
- (insert (format "Hello %s!\n\nI am %s."
- name ; the argument of the function
- your-name ; the let-bound variable "Bastien"
- ))))
-
-;; 之后执行:
-(greeting "you")
-
-;; 有些函数可以和用户交互:
-(read-from-minibuffer "Enter your name: ")
-
-;; 这个函数会返回在执行时用户输入的信息
-
-;; 现在我们让`greeting'函数显示你的名字:
-(defun greeting (from-name)
- (let ((your-name (read-from-minibuffer "Enter your name: ")))
- (insert (format "Hello!\n\nI am %s and you are %s."
- from-name ; the argument of the function
- your-name ; the let-bound var, entered at prompt
- ))))
-
-(greeting "Bastien")
-
-;; 我们让结果在另一个窗口中显示:
-(defun greeting (from-name)
- (let ((your-name (read-from-minibuffer "Enter your name: ")))
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- (insert (format "Hello %s!\n\nI am %s." your-name from-name))
- (other-window 1)))
-
-;; 测试一下:
-(greeting "Bastien")
-
-;; 第二节结束,休息一下吧。
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; 我们将一些名字存到列表中:
-(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
-
-;; 用 `car'来取得第一个名字:
-(car list-of-names)
-
-;; 用 `cdr'取得剩下的名字:
-(cdr list-of-names)
-
-;; 用 `push'把名字添加到列表的开头:
-(push "Stephanie" list-of-names)
-
-;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作.
-;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car')
-;; 但还有一些却是有的 (比如 `push').
-
-;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数:
-(mapcar 'hello list-of-names)
-
-;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行:
-(defun greeting ()
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- (mapcar 'hello list-of-names)
- (other-window 1))
-
-(greeting)
-
-;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。
-;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello'
-
-;; 现在我们对显示的buffer中的内容进行一些更改:
-
-(defun replace-hello-by-bonjour ()
- (switch-to-buffer-other-window "*test*")
- (goto-char (point-min))
- (while (search-forward "Hello")
- (replace-match "Bonjour"))
- (other-window 1))
-
-;; (goto-char (point-min)) 将光标移到buffer的开始
-;; (search-forward "Hello") 查找字符串"Hello"
-;; (while x y) 当x返回某个值时执行y这个s式
-;; 当x返回`nil' (空), 退出循环
-
-(replace-hello-by-bonjour)
-
-;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour"
-
-;; 你也会得到以下错误提示: "Search failed: Hello".
-;;
-;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在
-;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示
-
-;; (search-forward "Hello" nil t) 可以达到这个要求:
-
-;; `nil' 参数的意思是 : 查找并不限于某个范围内
-;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示
-
-;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示:
-
-(defun hello-to-bonjour ()
- (switch-to-buffer-other-window "*test*")
- (erase-buffer)
- ;; 为`list-of-names'中的每个名字调用hello
- (mapcar 'hello list-of-names)
- (goto-char (point-min))
- ;; 将"Hello" 替换为"Bonjour"
- (while (search-forward "Hello" nil t)
- (replace-match "Bonjour"))
- (other-window 1))
-
-(hello-to-bonjour)
-
-;; 给这些名字加粗:
-
-(defun boldify-names ()
- (switch-to-buffer-other-window "*test*")
- (goto-char (point-min))
- (while (re-search-forward "Bonjour \\(.+\\)!" nil t)
- (add-text-properties (match-beginning 1)
- (match-end 1)
- (list 'face 'bold)))
- (other-window 1))
-
-;; 这个函数使用了 `re-search-forward':
-;; 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式
-
-;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是:
-;; 字符串 "Bonjour ", 之后跟着
-;; 一组 | \\( ... \\) 结构
-;; 任意字符 | . 的含义
-;; 有可能重复的 | + 的含义
-;; 之后跟着 "!" 这个字符串
-
-;; 准备好了?试试看。
-
-(boldify-names)
-
-;; `add-text-properties' 可以添加文字属性, 比如文字样式
-
-;; 好的,我们成功了!
-
-;; 如果你想对一个变量或者函数有更多的了解:
-;;
-;; C-h v 变量 回车
-;; C-h f 函数 回车
-;;
-;; 阅读Emacs Lisp官方文档:
-;;
-;; C-h i m elisp 回车
-;;
-;; 在线阅读Emacs Lisp文档:
-;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
-
-;; 感谢以下同学的建议和反馈:
-;; - Wes Hardaker
-;; - notbob
-;; - Kevin Montuori
-;; - Arne Babenhauserheide
-;; - Alan Schmitt
-;; - spacegoing
-```
-
+---
+language: elisp
+contributors:
+ - ["Bastien Guerry", "http://bzg.fr"]
+translators:
+ - ["Chenbo Li", "http://binarythink.net"]
+filename: learn-emacs-lisp-zh.el
+lang: zh-cn
+---
+
+```scheme
+;; 15分钟学会Emacs Lisp (v0.2a)
+;;(作者:bzg,https://github.com/bzg
+;; 译者:lichenbo,http://douban.com/people/lichenbo)
+;;
+;; 请先阅读Peter Norvig的一篇好文:
+;; http://norvig.com/21-days.html
+;; (译者注:中文版请见http://blog.youxu.info/21-days/)
+;;
+;; 之后安装GNU Emacs 24.3:
+;;
+;; Debian: apt-get install emacs (视具体发行版而定)
+;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg
+;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip
+;;
+;; 更多信息可以在这里找到:
+;; http://www.gnu.org/software/emacs/#Obtaining
+
+;; 很重要的警告:
+;;
+;; 按照这个教程来学习并不会对你的电脑有任何损坏
+;; 除非你自己在学习的过程中愤怒地把它砸了
+;; 如果出现了这种情况,我不会承担任何责任
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 打开emacs
+;;
+;; 按'q'消除欢迎界面
+;;
+;; 现在请注意窗口底部的那一个灰色长条
+;;
+;; "*scratch*" 是你现在编辑界面的名字。
+;; 这个编辑界面叫做一个"buffer"。
+;;
+;; 每当你打开Emacs时,都会默认打开这个scratch buffer
+;; 此时你并没有在编辑任何文件,而是在编辑一个buffer
+;; 之后你可以将这个buffer保存到一个文件中。
+;;
+;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令
+;;
+;; Emacs在每个buffer中都有一组内置的命令
+;; 而当你激活某种特定的模式时,就可以使用相应的命令
+;; 这里我们使用`lisp-interaction-mode',
+;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 分号是注释开始的标志
+;;
+;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"):
+(+ 2 2)
+
+;; 这个s式的意思是 "对2进行加2操作".
+
+;; s式周围有括号,而且也可以嵌套:
+(+ 2 (+ 1 1))
+
+;; 一个s式可以包含原子符号或者其他s式
+;; 在上面的例子中,1和2是原子符号
+;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式.
+
+;; 在 `lisp-interaction-mode' 中你可以计算s式.
+;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j')
+
+(+ 3 (+ 1 2))
+;; ^ 光标放到这里
+;; 按下`C-j' 就会输出 6
+
+;; `C-j' 会在buffer中插入当前运算的结果
+
+;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域
+;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e'
+
+;; `setq' 可以将一个值赋给一个变量
+(setq my-name "Bastien")
+;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示)
+
+;; `insert' 会在光标处插入字符串:
+(insert "Hello!")
+;; `C-xC-e' 输出 "Hello!"
+
+;; 在这里我们只传给了insert一个参数"Hello!", 但是
+;; 我们也可以传给它更多的参数,比如2个:
+
+(insert "Hello" " world!")
+;; `C-xC-e' 输出 "Hello world!"
+
+;; 你也可以用变量名来代替字符串
+(insert "Hello, I am " my-name)
+;; `C-xC-e' 输出 "Hello, I am Bastien"
+
+;; 你可以把s式嵌入函数中
+(defun hello () (insert "Hello, I am " my-name))
+;; `C-xC-e' 输出 hello
+
+;; 现在执行这个函数
+(hello)
+;; `C-xC-e' 输出 Hello, I am Bastien
+
+;; 函数中空括号的意思是我们不需要接受任何参数
+;; 但是我们不能一直总是用my-name这个变量
+;; 所以我们现在使我们的函数接受一个叫做"name"的参数
+
+(defun hello (name) (insert "Hello " name))
+;; `C-xC-e' 输出 hello
+
+;; 现在我们调用这个函数,并且将"you"作为参数传递
+
+(hello "you")
+;; `C-xC-e' 输出 "Hello you"
+
+;; 成功!
+
+;; 现在我们可以休息一下
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer:
+
+(switch-to-buffer-other-window "*test*")
+;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
+
+;; 用鼠标单击上面的buffer就会使光标移回。
+;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中
+
+;; 你可以用 `progn'命令将s式结合起来:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (hello "you"))
+;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you"
+
+;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了
+
+;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。
+
+;; 清除当前buffer也是常用操作之一:
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "there"))
+
+;; 也可以回到其他的窗口中
+(progn
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello "you")
+ (other-window 1))
+
+;; 你可以用 `let' 将一个值和一个局部变量绑定:
+(let ((local-name "you"))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (hello local-name)
+ (other-window 1))
+
+;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。
+
+;; 格式化字符串的方法:
+(format "Hello %s!\n" "visitor")
+
+;; %s 是字符串占位符,这里被"visitor"替代.
+;; \n 是换行符。
+
+;; 现在我们用格式化的方法再重写一下我们的函数:
+(defun hello (name)
+ (insert (format "Hello %s!\n" name)))
+
+(hello "you")
+
+;; 我们再用`let'新建另一个函数:
+(defun greeting (name)
+ (let ((your-name "Bastien"))
+ (insert (format "Hello %s!\n\nI am %s."
+ name ; the argument of the function
+ your-name ; the let-bound variable "Bastien"
+ ))))
+
+;; 之后执行:
+(greeting "you")
+
+;; 有些函数可以和用户交互:
+(read-from-minibuffer "Enter your name: ")
+
+;; 这个函数会返回在执行时用户输入的信息
+
+;; 现在我们让`greeting'函数显示你的名字:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (insert (format "Hello!\n\nI am %s and you are %s."
+ from-name ; the argument of the function
+ your-name ; the let-bound var, entered at prompt
+ ))))
+
+(greeting "Bastien")
+
+;; 我们让结果在另一个窗口中显示:
+(defun greeting (from-name)
+ (let ((your-name (read-from-minibuffer "Enter your name: ")))
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (insert (format "Hello %s!\n\nI am %s." your-name from-name))
+ (other-window 1)))
+
+;; 测试一下:
+(greeting "Bastien")
+
+;; 第二节结束,休息一下吧。
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; 我们将一些名字存到列表中:
+(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
+
+;; 用 `car'来取得第一个名字:
+(car list-of-names)
+
+;; 用 `cdr'取得剩下的名字:
+(cdr list-of-names)
+
+;; 用 `push'把名字添加到列表的开头:
+(push "Stephanie" list-of-names)
+
+;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作.
+;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car')
+;; 但还有一些却是有的 (比如 `push').
+
+;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数:
+(mapcar 'hello list-of-names)
+
+;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行:
+(defun greeting ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ (mapcar 'hello list-of-names)
+ (other-window 1))
+
+(greeting)
+
+;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。
+;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello'
+
+;; 现在我们对显示的buffer中的内容进行一些更改:
+
+(defun replace-hello-by-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (search-forward "Hello")
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+;; (goto-char (point-min)) 将光标移到buffer的开始
+;; (search-forward "Hello") 查找字符串"Hello"
+;; (while x y) 当x返回某个值时执行y这个s式
+;; 当x返回`nil' (空), 退出循环
+
+(replace-hello-by-bonjour)
+
+;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour"
+
+;; 你也会得到以下错误提示: "Search failed: Hello".
+;;
+;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在
+;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示
+
+;; (search-forward "Hello" nil t) 可以达到这个要求:
+
+;; `nil' 参数的意思是 : 查找并不限于某个范围内
+;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示
+
+;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示:
+
+(defun hello-to-bonjour ()
+ (switch-to-buffer-other-window "*test*")
+ (erase-buffer)
+ ;; 为`list-of-names'中的每个名字调用hello
+ (mapcar 'hello list-of-names)
+ (goto-char (point-min))
+ ;; 将"Hello" 替换为"Bonjour"
+ (while (search-forward "Hello" nil t)
+ (replace-match "Bonjour"))
+ (other-window 1))
+
+(hello-to-bonjour)
+
+;; 给这些名字加粗:
+
+(defun boldify-names ()
+ (switch-to-buffer-other-window "*test*")
+ (goto-char (point-min))
+ (while (re-search-forward "Bonjour \\(.+\\)!" nil t)
+ (add-text-properties (match-beginning 1)
+ (match-end 1)
+ (list 'face 'bold)))
+ (other-window 1))
+
+;; 这个函数使用了 `re-search-forward':
+;; 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式
+
+;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是:
+;; 字符串 "Bonjour ", 之后跟着
+;; 一组 | \\( ... \\) 结构
+;; 任意字符 | . 的含义
+;; 有可能重复的 | + 的含义
+;; 之后跟着 "!" 这个字符串
+
+;; 准备好了?试试看。
+
+(boldify-names)
+
+;; `add-text-properties' 可以添加文字属性, 比如文字样式
+
+;; 好的,我们成功了!
+
+;; 如果你想对一个变量或者函数有更多的了解:
+;;
+;; C-h v 变量 回车
+;; C-h f 函数 回车
+;;
+;; 阅读Emacs Lisp官方文档:
+;;
+;; C-h i m elisp 回车
+;;
+;; 在线阅读Emacs Lisp文档:
+;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html
+
+;; 感谢以下同学的建议和反馈:
+;; - Wes Hardaker
+;; - notbob
+;; - Kevin Montuori
+;; - Arne Babenhauserheide
+;; - Alan Schmitt
+;; - spacegoing
+```
+
diff --git a/zh-cn/matlab-cn.html.markdown b/zh-cn/matlab-cn.html.markdown
index ca08b36b..bb1ab79a 100644
--- a/zh-cn/matlab-cn.html.markdown
+++ b/zh-cn/matlab-cn.html.markdown
@@ -1,504 +1,504 @@
----
-language: MATLAB
-filename: matlab-cn.m
-contributors:
- - ["mendozao", "http://github.com/mendozao"]
- - ["jamesscottbrown", "http://jamesscottbrown.com"]
-translators:
- - ["sunxb10", "https://github.com/sunxb10"]
-lang: zh-cn
-
----
-
-MATLAB 是 MATrix LABoratory(矩阵实验室)的缩写。
-它是一种功能强大的数值计算语言,在工程和数学领域中应用广泛。
-
-如果您有任何需要反馈或交流的内容,请联系本教程作者:
-[@the_ozzinator](https://twitter.com/the_ozzinator)
-或 [osvaldo.t.mendoza@gmail.com](mailto:osvaldo.t.mendoza@gmail.com)。
-
-```matlab
-% 以百分号作为注释符
-
-%{
-多行注释
-可以
-这样
-表示
-%}
-
-% 指令可以随意跨行,但需要在跨行处用 '...' 标明:
- a = 1 + 2 + ...
- + 4
-
-% 可以在MATLAB中直接向操作系统发出指令
-!ping google.com
-
-who % 显示内存中的所有变量
-whos % 显示内存中的所有变量以及它们的类型
-clear % 清除内存中的所有变量
-clear('A') % 清除指定的变量
-openvar('A') % 在变量编辑器中编辑指定变量
-
-clc % 清除命令窗口中显示的所有指令
-diary % 将命令窗口中的内容写入本地文件
-ctrl-c % 终止当前计算
-
-edit('myfunction.m') % 在编辑器中打开指定函数或脚本
-type('myfunction.m') % 在命令窗口中打印指定函数或脚本的源码
-
-profile on % 打开 profile 代码分析工具
-profile off % 关闭 profile 代码分析工具
-profile viewer % 查看 profile 代码分析工具的分析结果
-
-help command % 在命令窗口中显示指定命令的帮助文档
-doc command % 在帮助窗口中显示指定命令的帮助文档
-lookfor command % 在所有 MATLAB 内置函数的头部注释块的第一行中搜索指定命令
-lookfor command -all % 在所有 MATLAB 内置函数的整个头部注释块中搜索指定命令
-
-
-% 输出格式
-format short % 浮点数保留 4 位小数
-format long % 浮点数保留 15 位小数
-format bank % 金融格式,浮点数只保留 2 位小数
-fprintf('text') % 在命令窗口中显示 "text"
-disp('text') % 在命令窗口中显示 "text"
-
-
-% 变量与表达式
-myVariable = 4 % 命令窗口中将新创建的变量
-myVariable = 4; % 加上分号可使命令窗口中不显示当前语句执行结果
-4 + 6 % ans = 10
-8 * myVariable % ans = 32
-2 ^ 3 % ans = 8
-a = 2; b = 3;
-c = exp(a)*sin(pi/2) % c = 7.3891
-
-
-% 调用函数有两种方式:
-% 标准函数语法:
-load('myFile.mat', 'y') % 参数放在括号内,以英文逗号分隔
-% 指令语法:
-load myFile.mat y % 不加括号,以空格分隔参数
-% 注意在指令语法中参数不需要加引号:在这种语法下,所有输入参数都只能是文本文字,
-% 不能是变量的具体值,同样也不能是输出变量
-[V,D] = eig(A); % 这条函数调用无法转换成等价的指令语法
-[~,D] = eig(A); % 如果结果中只需要 D 而不需要 V 则可以这样写
-
-
-
-% 逻辑运算
-1 > 5 % 假,ans = 0
-10 >= 10 % 真,ans = 1
-3 ~= 4 % 不等于 -> ans = 1
-3 == 3 % 等于 -> ans = 1
-3 > 1 && 4 > 1 % 与 -> ans = 1
-3 > 1 || 4 > 1 % 或 -> ans = 1
-~1 % 非 -> ans = 0
-
-% 逻辑运算可直接应用于矩阵,运算结果也是矩阵
-A > 5
-% 对矩阵中每个元素做逻辑运算,若为真,则在运算结果的矩阵中对应位置的元素就是 1
-A( A > 5 )
-% 如此返回的向量,其元素就是 A 矩阵中所有逻辑运算为真的元素
-
-% 字符串
-a = 'MyString'
-length(a) % ans = 8
-a(2) % ans = y
-[a,a] % ans = MyStringMyString
-b = '字符串' % MATLAB目前已经可以支持包括中文在内的多种文字
-length(b) % ans = 3
-b(2) % ans = 符
-[b,b] % ans = 字符串字符串
-
-
-% 元组(cell 数组)
-a = {'one', 'two', 'three'}
-a(1) % ans = 'one' - 返回一个元组
-a{1} % ans = one - 返回一个字符串
-
-
-% 结构体
-A.b = {'one','two'};
-A.c = [1 2];
-A.d.e = false;
-
-
-% 向量
-x = [4 32 53 7 1]
-x(2) % ans = 32,MATLAB中向量的下标索引从1开始,不是0
-x(2:3) % ans = 32 53
-x(2:end) % ans = 32 53 7 1
-
-x = [4; 32; 53; 7; 1] % 列向量
-
-x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10
-
-
-% 矩阵
-A = [1 2 3; 4 5 6; 7 8 9]
-% 以分号分隔不同的行,以空格或逗号分隔同一行中的不同元素
-% A =
-
-% 1 2 3
-% 4 5 6
-% 7 8 9
-
-A(2,3) % ans = 6,A(row, column)
-A(6) % ans = 8
-% (隐式地将 A 的三列首尾相接组成一个列向量,然后取其下标为 6 的元素)
-
-
-A(2,3) = 42 % 将第 2 行第 3 列的元素设为 42
-% A =
-
-% 1 2 3
-% 4 5 42
-% 7 8 9
-
-A(2:3,2:3) % 取原矩阵中的一块作为新矩阵
-%ans =
-
-% 5 42
-% 8 9
-
-A(:,1) % 第 1 列的所有元素
-%ans =
-
-% 1
-% 4
-% 7
-
-A(1,:) % 第 1 行的所有元素
-%ans =
-
-% 1 2 3
-
-[A ; A] % 将两个矩阵上下相接构成新矩阵
-%ans =
-
-% 1 2 3
-% 4 5 42
-% 7 8 9
-% 1 2 3
-% 4 5 42
-% 7 8 9
-
-% 等价于
-vertcat(A, A);
-
-
-[A , A] % 将两个矩阵左右相接构成新矩阵
-
-%ans =
-
-% 1 2 3 1 2 3
-% 4 5 42 4 5 42
-% 7 8 9 7 8 9
-
-% 等价于
-horzcat(A, A);
-
-
-A(:, [3 1 2]) % 重新排布原矩阵的各列
-%ans =
-
-% 3 1 2
-% 42 4 5
-% 9 7 8
-
-size(A) % 返回矩阵的行数和列数,ans = 3 3
-
-A(1, :) =[] % 删除矩阵的第 1 行
-A(:, 1) =[] % 删除矩阵的第 1 列
-
-transpose(A) % 矩阵(非共轭)转置,等价于 A.' (注意!有个点)
-ctranspose(A) % 矩阵的共轭转置(对矩阵中的每个元素取共轭复数),等价于 A'
-
-
-% 元素运算 vs. 矩阵运算
-% 单独运算符就是对矩阵整体进行矩阵运算
-% 在运算符加上英文句点就是对矩阵中的元素进行元素计算
-% 示例如下:
-A * B % 矩阵乘法,要求 A 的列数等于 B 的行数
-A .* B % 元素乘法,要求 A 和 B 形状一致,即两矩阵行列数完全一致
- % 元素乘法的结果是与 A 和 B 形状一致的矩阵
- % 其每个元素等于 A 对应位置的元素乘 B 对应位置的元素
-
-% 以下函数中,函数名以 m 结尾的执行矩阵运算,其余执行元素运算:
-exp(A) % 对矩阵中每个元素做指数运算
-expm(A) % 对矩阵整体做指数运算
-sqrt(A) % 对矩阵中每个元素做开方运算
-sqrtm(A) % 对矩阵整体做开方运算(即试图求出一个矩阵,该矩阵与自身的乘积等于 A 矩阵)
-
-
-% 绘图
-x = 0:0.1:2*pi; % 生成一向量,其元素从 0 开始,以 0.1 的间隔一直递增到 2*pi
- % 其中 pi 为圆周率
-y = sin(x);
-plot(x,y)
-xlabel('x axis')
-ylabel('y axis')
-title('Plot of y = sin(x)')
-axis([0 2*pi -1 1]) % x 轴范围是从 0 到 2*pi,y 轴范围是从 -1 到 1
-
-plot(x,y1,'-',x,y2,'--',x,y3,':') % 在同一张图中绘制多条曲线
-legend('Line 1 label', 'Line 2 label') % 为图片加注图例
-% 图例数量应当小于或等于实际绘制的曲线数目,从 plot 绘制的第一条曲线开始对应
-
-% 在同一张图上绘制多条曲线的另一种方法:
-% 使用 hold on,令系统保留前次绘图结果并在其上直接叠加新的曲线,
-% 如果没有 hold on,则每个 plot 都会首先清除之前的绘图结果再进行绘制。
-% 在 hold on 和 hold off 中可以放置任意多的 plot 指令,
-% 它们和 hold on 前最后一个 plot 指令的结果都将显示在同一张图中。
-plot(x, y1)
-hold on
-plot(x, y2)
-plot(x, y3)
-plot(x, y4)
-hold off
-
-loglog(x, y) % 对数—对数绘图
-semilogx(x, y) % 半对数(x 轴对数)绘图
-semilogy(x, y) % 半对数(y 轴对数)绘图
-
-fplot (@(x) x^2, [2,5]) % 绘制函数 x^2 在 [2, 5] 区间的曲线
-
-grid on % 在绘制的图中显示网格,使用 grid off 可取消网格显示
-axis square % 将当前坐标系设定为正方形(保证在图形显示上各轴等长)
-axis equal % 将当前坐标系设定为相等(保证在实际数值上各轴等长)
-
-scatter(x, y); % 散点图
-hist(x); % 直方图
-
-z = sin(x);
-plot3(x,y,z); % 绘制三维曲线
-
-pcolor(A) % 伪彩色图(热图)
-contour(A) % 等高线图
-mesh(A) % 网格曲面图
-
-h = figure % 创建新的图片对象并返回其句柄 h
-figure(h) % 将句柄 h 对应的图片作为当前图片
-close(h) % 关闭句柄 h 对应的图片
-close all % 关闭 MATLAB 中所用打开的图片
-close % 关闭当前图片
-
-shg % 显示图形窗口
-clf clear % 清除图形窗口中的图像,并重置图像属性
-
-% 图像属性可以通过图像句柄进行设定
-% 在创建图像时可以保存图像句柄以便于设置
-% 也可以用 gcf 函数返回当前图像的句柄
-h = plot(x, y); % 在创建图像时显式地保存图像句柄
-set(h, 'Color', 'r')
-% 颜色代码:
-% 'y' 黄色,'m' 洋红,'c' 青色
-% 'r' 红色,'g' 绿色,'b' 蓝色
-% 'w' 白色,'k' 黑色
-set(h, 'Color', [0.5, 0.5, 0.4])
-% 也可以使用 RGB 值指定颜色
-set(h, 'LineStyle', '--')
-% 线型代码:'--' 实线,'---' 虚线,':' 点线,'-.' 点划线,'none' 不划线
-get(h, 'LineStyle')
-% 获取当前句柄的线型
-
-
-% 用 gca 函数返回当前图像的坐标轴句柄
-set(gca, 'XDir', 'reverse'); % 令 x 轴反向
-
-% 用 subplot 指令创建平铺排列的多张子图
-subplot(2,3,1); % 选择 2 x 3 排列的子图中的第 1 张图
-plot(x1); title('First Plot') % 在选中的图中绘图
-subplot(2,3,2); % 选择 2 x 3 排列的子图中的第 2 张图
-plot(x2); title('Second Plot') % 在选中的图中绘图
-
-
-% 要调用函数或脚本,必须保证它们在你的当前工作目录中
-path % 显示当前工作目录
-addpath /path/to/dir % 将指定路径加入到当前工作目录中
-rmpath /path/to/dir % 将指定路径从当前工作目录中删除
-cd /path/to/move/into % 以制定路径作为当前工作目录
-
-
-% 变量可保存到 .mat 格式的本地文件
-save('myFileName.mat') % 保存当前工作空间中的所有变量
-load('myFileName.mat') % 将指定文件中的变量载入到当前工作空间
-
-
-% .m 脚本文件
-% 脚本文件是一个包含多条 MATLAB 指令的外部文件,以 .m 为后缀名
-% 使用脚本文件可以避免在命令窗口中重复输入冗长的指令
-
-
-% .m 函数文件
-% 与脚本文件类似,同样以 .m 作为后缀名
-% 但函数文件可以接受用户输入的参数并返回运算结果
-% 并且函数拥有自己的工作空间(变量域),不必担心变量名称冲突
-% 函数文件的名称应当与其所定义的函数的名称一致
-% 比如下面例子中函数文件就应命名为 double_input.m
-% 使用 'help double_input.m' 可返回函数定义中第一行注释信息
-function output = double_input(x)
- % double_input(x) 返回 x 的 2 倍
- output = 2*x;
-end
-double_input(6) % ans = 12
-
-
-% 同样还可以定义子函数和内嵌函数
-% 子函数与主函数放在同一个函数文件中,且只能被这个主函数调用
-% 内嵌函数放在另一个函数体内,可以直接访问被嵌套函数的各个变量
-
-
-% 使用匿名函数可以不必创建 .m 函数文件
-% 匿名函数适用于快速定义某函数以便传递给另一指令或函数(如绘图、积分、求根、求极值等)
-% 下面示例的匿名函数返回输入参数的平方根,可以使用句柄 sqr 进行调用:
-sqr = @(x) x.^2;
-sqr(10) % ans = 100
-doc function_handle % find out more
-
-
-% 接受用户输入
-a = input('Enter the value: ')
-
-
-% 从文件中读取数据
-fopen(filename)
-% 类似函数还有 xlsread(excel 文件)、importdata(CSV 文件)、imread(图像文件)
-
-
-% 输出
-disp(a) % 在命令窗口中打印变量 a 的值
-disp('Hello World') % 在命令窗口中打印字符串
-fprintf % 按照指定格式在命令窗口中打印内容
-
-% 条件语句(if 和 elseif 语句中的括号并非必需,但推荐加括号避免混淆)
-if (a > 15)
- disp('Greater than 15')
-elseif (a == 23)
- disp('a is 23')
-else
- disp('neither condition met')
-end
-
-% 循环语句
-% 注意:对向量或矩阵使用循环语句进行元素遍历的效率很低!!
-% 注意:只要有可能,就尽量使用向量或矩阵的整体运算取代逐元素循环遍历!!
-% MATLAB 在开发时对向量和矩阵运算做了专门优化,做向量和矩阵整体运算的效率高于循环语句
-for k = 1:5
- disp(k)
-end
-
-k = 0;
-while (k < 5)
- k = k + 1;
-end
-
-
-% 程序运行计时:'tic' 是计时开始,'toc' 是计时结束并打印结果
-tic
-A = rand(1000);
-A*A*A*A*A*A*A;
-toc
-
-
-% 链接 MySQL 数据库
-dbname = 'database_name';
-username = 'root';
-password = 'root';
-driver = 'com.mysql.jdbc.Driver';
-dburl = ['jdbc:mysql://localhost:8889/' dbname];
-javaclasspath('mysql-connector-java-5.1.xx-bin.jar'); % 此处 xx 代表具体版本号
-% 这里的 mysql-connector-java-5.1.xx-bin.jar 可从 http://dev.mysql.com/downloads/connector/j/ 下载
-conn = database(dbname, username, password, driver, dburl);
-sql = ['SELECT * from table_name where id = 22'] % SQL 语句
-a = fetch(conn, sql) % a 即包含所需数据
-
-
-% 常用数学函数
-sin(x)
-cos(x)
-tan(x)
-asin(x)
-acos(x)
-atan(x)
-exp(x)
-sqrt(x)
-log(x)
-log10(x)
-abs(x)
-min(x)
-max(x)
-ceil(x)
-floor(x)
-round(x)
-rem(x)
-rand % 均匀分布的伪随机浮点数
-randi % 均匀分布的伪随机整数
-randn % 正态分布的伪随机浮点数
-
-% 常用常数
-pi
-NaN
-inf
-
-% 求解矩阵方程(如果方程无解,则返回最小二乘近似解)
-% \ 操作符等价于 mldivide 函数,/ 操作符等价于 mrdivide 函数
-x=A\b % 求解 Ax=b,比先求逆再左乘 inv(A)*b 更加高效、准确
-x=b/A % 求解 xA=b
-
-inv(A) % 逆矩阵
-pinv(A) % 伪逆矩阵
-
-
-% 常用矩阵函数
-zeros(m, n) % m x n 阶矩阵,元素全为 0
-ones(m, n) % m x n 阶矩阵,元素全为 1
-diag(A) % 返回矩阵 A 的对角线元素
-diag(x) % 构造一个对角阵,对角线元素就是向量 x 的各元素
-eye(m, n) % m x n 阶单位矩阵
-linspace(x1, x2, n) % 返回介于 x1 和 x2 之间的 n 个等距节点
-inv(A) % 矩阵 A 的逆矩阵
-det(A) % 矩阵 A 的行列式
-eig(A) % 矩阵 A 的特征值和特征向量
-trace(A) % 矩阵 A 的迹(即对角线元素之和),等价于 sum(diag(A))
-isempty(A) % 测试 A 是否为空
-all(A) % 测试 A 中所有元素是否都非 0 或都为真(逻辑值)
-any(A) % 测试 A 中是否有元素非 0 或为真(逻辑值)
-isequal(A, B) % 测试 A 和 B是否相等
-numel(A) % 矩阵 A 的元素个数
-triu(x) % 返回 x 的上三角这部分
-tril(x) % 返回 x 的下三角这部分
-cross(A, B) % 返回 A 和 B 的叉积(矢量积、外积)
-dot(A, B) % 返回 A 和 B 的点积(数量积、内积),要求 A 和 B 必须等长
-transpose(A) % 矩阵(非共轭)转置,等价于 A.' (注意!有个点)
-fliplr(A) % 将一个矩阵左右翻转
-flipud(A) % 将一个矩阵上下翻转
-
-% 矩阵分解
-[L, U, P] = lu(A) % LU 分解:PA = LU,L 是下三角阵,U 是上三角阵,P 是置换阵
-[P, D] = eig(A) % 特征值分解:AP = PD
- % D 是由特征值构成的对角阵,P 的各列就是对应的特征向量
-[U, S, V] = svd(X) % 奇异值分解:XV = US
- % U 和 V 是酉矩阵,S 是由奇异值构成的半正定实数对角阵
-
-% 常用向量函数
-max % 最大值
-min % 最小值
-length % 元素个数
-sort % 按升序排列
-sum % 各元素之和
-prod % 各元素之积
-mode % 众数
-median % 中位数
-mean % 平均值
-std % 标准差
-perms(x) % x 元素的全排列
-
-```
-
-## 相关资料
-
-* 官方网页:[MATLAB - 技术计算语言 - MATLAB & Simulink](https://ww2.mathworks.cn/products/matlab.html)
-* 官方论坛:[MATLAB Answers - MATLAB Central](https://ww2.mathworks.cn/matlabcentral/answers/)
+---
+language: MATLAB
+filename: matlab-cn.m
+contributors:
+ - ["mendozao", "http://github.com/mendozao"]
+ - ["jamesscottbrown", "http://jamesscottbrown.com"]
+translators:
+ - ["sunxb10", "https://github.com/sunxb10"]
+lang: zh-cn
+
+---
+
+MATLAB 是 MATrix LABoratory(矩阵实验室)的缩写。
+它是一种功能强大的数值计算语言,在工程和数学领域中应用广泛。
+
+如果您有任何需要反馈或交流的内容,请联系本教程作者:
+[@the_ozzinator](https://twitter.com/the_ozzinator)
+或 [osvaldo.t.mendoza@gmail.com](mailto:osvaldo.t.mendoza@gmail.com)。
+
+```matlab
+% 以百分号作为注释符
+
+%{
+多行注释
+可以
+这样
+表示
+%}
+
+% 指令可以随意跨行,但需要在跨行处用 '...' 标明:
+ a = 1 + 2 + ...
+ + 4
+
+% 可以在MATLAB中直接向操作系统发出指令
+!ping google.com
+
+who % 显示内存中的所有变量
+whos % 显示内存中的所有变量以及它们的类型
+clear % 清除内存中的所有变量
+clear('A') % 清除指定的变量
+openvar('A') % 在变量编辑器中编辑指定变量
+
+clc % 清除命令窗口中显示的所有指令
+diary % 将命令窗口中的内容写入本地文件
+ctrl-c % 终止当前计算
+
+edit('myfunction.m') % 在编辑器中打开指定函数或脚本
+type('myfunction.m') % 在命令窗口中打印指定函数或脚本的源码
+
+profile on % 打开 profile 代码分析工具
+profile off % 关闭 profile 代码分析工具
+profile viewer % 查看 profile 代码分析工具的分析结果
+
+help command % 在命令窗口中显示指定命令的帮助文档
+doc command % 在帮助窗口中显示指定命令的帮助文档
+lookfor command % 在所有 MATLAB 内置函数的头部注释块的第一行中搜索指定命令
+lookfor command -all % 在所有 MATLAB 内置函数的整个头部注释块中搜索指定命令
+
+
+% 输出格式
+format short % 浮点数保留 4 位小数
+format long % 浮点数保留 15 位小数
+format bank % 金融格式,浮点数只保留 2 位小数
+fprintf('text') % 在命令窗口中显示 "text"
+disp('text') % 在命令窗口中显示 "text"
+
+
+% 变量与表达式
+myVariable = 4 % 命令窗口中将新创建的变量
+myVariable = 4; % 加上分号可使命令窗口中不显示当前语句执行结果
+4 + 6 % ans = 10
+8 * myVariable % ans = 32
+2 ^ 3 % ans = 8
+a = 2; b = 3;
+c = exp(a)*sin(pi/2) % c = 7.3891
+
+
+% 调用函数有两种方式:
+% 标准函数语法:
+load('myFile.mat', 'y') % 参数放在括号内,以英文逗号分隔
+% 指令语法:
+load myFile.mat y % 不加括号,以空格分隔参数
+% 注意在指令语法中参数不需要加引号:在这种语法下,所有输入参数都只能是文本文字,
+% 不能是变量的具体值,同样也不能是输出变量
+[V,D] = eig(A); % 这条函数调用无法转换成等价的指令语法
+[~,D] = eig(A); % 如果结果中只需要 D 而不需要 V 则可以这样写
+
+
+
+% 逻辑运算
+1 > 5 % 假,ans = 0
+10 >= 10 % 真,ans = 1
+3 ~= 4 % 不等于 -> ans = 1
+3 == 3 % 等于 -> ans = 1
+3 > 1 && 4 > 1 % 与 -> ans = 1
+3 > 1 || 4 > 1 % 或 -> ans = 1
+~1 % 非 -> ans = 0
+
+% 逻辑运算可直接应用于矩阵,运算结果也是矩阵
+A > 5
+% 对矩阵中每个元素做逻辑运算,若为真,则在运算结果的矩阵中对应位置的元素就是 1
+A( A > 5 )
+% 如此返回的向量,其元素就是 A 矩阵中所有逻辑运算为真的元素
+
+% 字符串
+a = 'MyString'
+length(a) % ans = 8
+a(2) % ans = y
+[a,a] % ans = MyStringMyString
+b = '字符串' % MATLAB目前已经可以支持包括中文在内的多种文字
+length(b) % ans = 3
+b(2) % ans = 符
+[b,b] % ans = 字符串字符串
+
+
+% 元组(cell 数组)
+a = {'one', 'two', 'three'}
+a(1) % ans = 'one' - 返回一个元组
+a{1} % ans = one - 返回一个字符串
+
+
+% 结构体
+A.b = {'one','two'};
+A.c = [1 2];
+A.d.e = false;
+
+
+% 向量
+x = [4 32 53 7 1]
+x(2) % ans = 32,MATLAB中向量的下标索引从1开始,不是0
+x(2:3) % ans = 32 53
+x(2:end) % ans = 32 53 7 1
+
+x = [4; 32; 53; 7; 1] % 列向量
+
+x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10
+
+
+% 矩阵
+A = [1 2 3; 4 5 6; 7 8 9]
+% 以分号分隔不同的行,以空格或逗号分隔同一行中的不同元素
+% A =
+
+% 1 2 3
+% 4 5 6
+% 7 8 9
+
+A(2,3) % ans = 6,A(row, column)
+A(6) % ans = 8
+% (隐式地将 A 的三列首尾相接组成一个列向量,然后取其下标为 6 的元素)
+
+
+A(2,3) = 42 % 将第 2 行第 3 列的元素设为 42
+% A =
+
+% 1 2 3
+% 4 5 42
+% 7 8 9
+
+A(2:3,2:3) % 取原矩阵中的一块作为新矩阵
+%ans =
+
+% 5 42
+% 8 9
+
+A(:,1) % 第 1 列的所有元素
+%ans =
+
+% 1
+% 4
+% 7
+
+A(1,:) % 第 1 行的所有元素
+%ans =
+
+% 1 2 3
+
+[A ; A] % 将两个矩阵上下相接构成新矩阵
+%ans =
+
+% 1 2 3
+% 4 5 42
+% 7 8 9
+% 1 2 3
+% 4 5 42
+% 7 8 9
+
+% 等价于
+vertcat(A, A);
+
+
+[A , A] % 将两个矩阵左右相接构成新矩阵
+
+%ans =
+
+% 1 2 3 1 2 3
+% 4 5 42 4 5 42
+% 7 8 9 7 8 9
+
+% 等价于
+horzcat(A, A);
+
+
+A(:, [3 1 2]) % 重新排布原矩阵的各列
+%ans =
+
+% 3 1 2
+% 42 4 5
+% 9 7 8
+
+size(A) % 返回矩阵的行数和列数,ans = 3 3
+
+A(1, :) =[] % 删除矩阵的第 1 行
+A(:, 1) =[] % 删除矩阵的第 1 列
+
+transpose(A) % 矩阵(非共轭)转置,等价于 A.' (注意!有个点)
+ctranspose(A) % 矩阵的共轭转置(对矩阵中的每个元素取共轭复数),等价于 A'
+
+
+% 元素运算 vs. 矩阵运算
+% 单独运算符就是对矩阵整体进行矩阵运算
+% 在运算符加上英文句点就是对矩阵中的元素进行元素计算
+% 示例如下:
+A * B % 矩阵乘法,要求 A 的列数等于 B 的行数
+A .* B % 元素乘法,要求 A 和 B 形状一致,即两矩阵行列数完全一致
+ % 元素乘法的结果是与 A 和 B 形状一致的矩阵
+ % 其每个元素等于 A 对应位置的元素乘 B 对应位置的元素
+
+% 以下函数中,函数名以 m 结尾的执行矩阵运算,其余执行元素运算:
+exp(A) % 对矩阵中每个元素做指数运算
+expm(A) % 对矩阵整体做指数运算
+sqrt(A) % 对矩阵中每个元素做开方运算
+sqrtm(A) % 对矩阵整体做开方运算(即试图求出一个矩阵,该矩阵与自身的乘积等于 A 矩阵)
+
+
+% 绘图
+x = 0:0.1:2*pi; % 生成一向量,其元素从 0 开始,以 0.1 的间隔一直递增到 2*pi
+ % 其中 pi 为圆周率
+y = sin(x);
+plot(x,y)
+xlabel('x axis')
+ylabel('y axis')
+title('Plot of y = sin(x)')
+axis([0 2*pi -1 1]) % x 轴范围是从 0 到 2*pi,y 轴范围是从 -1 到 1
+
+plot(x,y1,'-',x,y2,'--',x,y3,':') % 在同一张图中绘制多条曲线
+legend('Line 1 label', 'Line 2 label') % 为图片加注图例
+% 图例数量应当小于或等于实际绘制的曲线数目,从 plot 绘制的第一条曲线开始对应
+
+% 在同一张图上绘制多条曲线的另一种方法:
+% 使用 hold on,令系统保留前次绘图结果并在其上直接叠加新的曲线,
+% 如果没有 hold on,则每个 plot 都会首先清除之前的绘图结果再进行绘制。
+% 在 hold on 和 hold off 中可以放置任意多的 plot 指令,
+% 它们和 hold on 前最后一个 plot 指令的结果都将显示在同一张图中。
+plot(x, y1)
+hold on
+plot(x, y2)
+plot(x, y3)
+plot(x, y4)
+hold off
+
+loglog(x, y) % 对数—对数绘图
+semilogx(x, y) % 半对数(x 轴对数)绘图
+semilogy(x, y) % 半对数(y 轴对数)绘图
+
+fplot (@(x) x^2, [2,5]) % 绘制函数 x^2 在 [2, 5] 区间的曲线
+
+grid on % 在绘制的图中显示网格,使用 grid off 可取消网格显示
+axis square % 将当前坐标系设定为正方形(保证在图形显示上各轴等长)
+axis equal % 将当前坐标系设定为相等(保证在实际数值上各轴等长)
+
+scatter(x, y); % 散点图
+hist(x); % 直方图
+
+z = sin(x);
+plot3(x,y,z); % 绘制三维曲线
+
+pcolor(A) % 伪彩色图(热图)
+contour(A) % 等高线图
+mesh(A) % 网格曲面图
+
+h = figure % 创建新的图片对象并返回其句柄 h
+figure(h) % 将句柄 h 对应的图片作为当前图片
+close(h) % 关闭句柄 h 对应的图片
+close all % 关闭 MATLAB 中所用打开的图片
+close % 关闭当前图片
+
+shg % 显示图形窗口
+clf clear % 清除图形窗口中的图像,并重置图像属性
+
+% 图像属性可以通过图像句柄进行设定
+% 在创建图像时可以保存图像句柄以便于设置
+% 也可以用 gcf 函数返回当前图像的句柄
+h = plot(x, y); % 在创建图像时显式地保存图像句柄
+set(h, 'Color', 'r')
+% 颜色代码:
+% 'y' 黄色,'m' 洋红,'c' 青色
+% 'r' 红色,'g' 绿色,'b' 蓝色
+% 'w' 白色,'k' 黑色
+set(h, 'Color', [0.5, 0.5, 0.4])
+% 也可以使用 RGB 值指定颜色
+set(h, 'LineStyle', '--')
+% 线型代码:'--' 实线,'---' 虚线,':' 点线,'-.' 点划线,'none' 不划线
+get(h, 'LineStyle')
+% 获取当前句柄的线型
+
+
+% 用 gca 函数返回当前图像的坐标轴句柄
+set(gca, 'XDir', 'reverse'); % 令 x 轴反向
+
+% 用 subplot 指令创建平铺排列的多张子图
+subplot(2,3,1); % 选择 2 x 3 排列的子图中的第 1 张图
+plot(x1); title('First Plot') % 在选中的图中绘图
+subplot(2,3,2); % 选择 2 x 3 排列的子图中的第 2 张图
+plot(x2); title('Second Plot') % 在选中的图中绘图
+
+
+% 要调用函数或脚本,必须保证它们在你的当前工作目录中
+path % 显示当前工作目录
+addpath /path/to/dir % 将指定路径加入到当前工作目录中
+rmpath /path/to/dir % 将指定路径从当前工作目录中删除
+cd /path/to/move/into % 以制定路径作为当前工作目录
+
+
+% 变量可保存到 .mat 格式的本地文件
+save('myFileName.mat') % 保存当前工作空间中的所有变量
+load('myFileName.mat') % 将指定文件中的变量载入到当前工作空间
+
+
+% .m 脚本文件
+% 脚本文件是一个包含多条 MATLAB 指令的外部文件,以 .m 为后缀名
+% 使用脚本文件可以避免在命令窗口中重复输入冗长的指令
+
+
+% .m 函数文件
+% 与脚本文件类似,同样以 .m 作为后缀名
+% 但函数文件可以接受用户输入的参数并返回运算结果
+% 并且函数拥有自己的工作空间(变量域),不必担心变量名称冲突
+% 函数文件的名称应当与其所定义的函数的名称一致
+% 比如下面例子中函数文件就应命名为 double_input.m
+% 使用 'help double_input.m' 可返回函数定义中第一行注释信息
+function output = double_input(x)
+ % double_input(x) 返回 x 的 2 倍
+ output = 2*x;
+end
+double_input(6) % ans = 12
+
+
+% 同样还可以定义子函数和内嵌函数
+% 子函数与主函数放在同一个函数文件中,且只能被这个主函数调用
+% 内嵌函数放在另一个函数体内,可以直接访问被嵌套函数的各个变量
+
+
+% 使用匿名函数可以不必创建 .m 函数文件
+% 匿名函数适用于快速定义某函数以便传递给另一指令或函数(如绘图、积分、求根、求极值等)
+% 下面示例的匿名函数返回输入参数的平方根,可以使用句柄 sqr 进行调用:
+sqr = @(x) x.^2;
+sqr(10) % ans = 100
+doc function_handle % find out more
+
+
+% 接受用户输入
+a = input('Enter the value: ')
+
+
+% 从文件中读取数据
+fopen(filename)
+% 类似函数还有 xlsread(excel 文件)、importdata(CSV 文件)、imread(图像文件)
+
+
+% 输出
+disp(a) % 在命令窗口中打印变量 a 的值
+disp('Hello World') % 在命令窗口中打印字符串
+fprintf % 按照指定格式在命令窗口中打印内容
+
+% 条件语句(if 和 elseif 语句中的括号并非必需,但推荐加括号避免混淆)
+if (a > 15)
+ disp('Greater than 15')
+elseif (a == 23)
+ disp('a is 23')
+else
+ disp('neither condition met')
+end
+
+% 循环语句
+% 注意:对向量或矩阵使用循环语句进行元素遍历的效率很低!!
+% 注意:只要有可能,就尽量使用向量或矩阵的整体运算取代逐元素循环遍历!!
+% MATLAB 在开发时对向量和矩阵运算做了专门优化,做向量和矩阵整体运算的效率高于循环语句
+for k = 1:5
+ disp(k)
+end
+
+k = 0;
+while (k < 5)
+ k = k + 1;
+end
+
+
+% 程序运行计时:'tic' 是计时开始,'toc' 是计时结束并打印结果
+tic
+A = rand(1000);
+A*A*A*A*A*A*A;
+toc
+
+
+% 链接 MySQL 数据库
+dbname = 'database_name';
+username = 'root';
+password = 'root';
+driver = 'com.mysql.jdbc.Driver';
+dburl = ['jdbc:mysql://localhost:8889/' dbname];
+javaclasspath('mysql-connector-java-5.1.xx-bin.jar'); % 此处 xx 代表具体版本号
+% 这里的 mysql-connector-java-5.1.xx-bin.jar 可从 http://dev.mysql.com/downloads/connector/j/ 下载
+conn = database(dbname, username, password, driver, dburl);
+sql = ['SELECT * from table_name where id = 22'] % SQL 语句
+a = fetch(conn, sql) % a 即包含所需数据
+
+
+% 常用数学函数
+sin(x)
+cos(x)
+tan(x)
+asin(x)
+acos(x)
+atan(x)
+exp(x)
+sqrt(x)
+log(x)
+log10(x)
+abs(x)
+min(x)
+max(x)
+ceil(x)
+floor(x)
+round(x)
+rem(x)
+rand % 均匀分布的伪随机浮点数
+randi % 均匀分布的伪随机整数
+randn % 正态分布的伪随机浮点数
+
+% 常用常数
+pi
+NaN
+inf
+
+% 求解矩阵方程(如果方程无解,则返回最小二乘近似解)
+% \ 操作符等价于 mldivide 函数,/ 操作符等价于 mrdivide 函数
+x=A\b % 求解 Ax=b,比先求逆再左乘 inv(A)*b 更加高效、准确
+x=b/A % 求解 xA=b
+
+inv(A) % 逆矩阵
+pinv(A) % 伪逆矩阵
+
+
+% 常用矩阵函数
+zeros(m, n) % m x n 阶矩阵,元素全为 0
+ones(m, n) % m x n 阶矩阵,元素全为 1
+diag(A) % 返回矩阵 A 的对角线元素
+diag(x) % 构造一个对角阵,对角线元素就是向量 x 的各元素
+eye(m, n) % m x n 阶单位矩阵
+linspace(x1, x2, n) % 返回介于 x1 和 x2 之间的 n 个等距节点
+inv(A) % 矩阵 A 的逆矩阵
+det(A) % 矩阵 A 的行列式
+eig(A) % 矩阵 A 的特征值和特征向量
+trace(A) % 矩阵 A 的迹(即对角线元素之和),等价于 sum(diag(A))
+isempty(A) % 测试 A 是否为空
+all(A) % 测试 A 中所有元素是否都非 0 或都为真(逻辑值)
+any(A) % 测试 A 中是否有元素非 0 或为真(逻辑值)
+isequal(A, B) % 测试 A 和 B是否相等
+numel(A) % 矩阵 A 的元素个数
+triu(x) % 返回 x 的上三角这部分
+tril(x) % 返回 x 的下三角这部分
+cross(A, B) % 返回 A 和 B 的叉积(矢量积、外积)
+dot(A, B) % 返回 A 和 B 的点积(数量积、内积),要求 A 和 B 必须等长
+transpose(A) % 矩阵(非共轭)转置,等价于 A.' (注意!有个点)
+fliplr(A) % 将一个矩阵左右翻转
+flipud(A) % 将一个矩阵上下翻转
+
+% 矩阵分解
+[L, U, P] = lu(A) % LU 分解:PA = LU,L 是下三角阵,U 是上三角阵,P 是置换阵
+[P, D] = eig(A) % 特征值分解:AP = PD
+ % D 是由特征值构成的对角阵,P 的各列就是对应的特征向量
+[U, S, V] = svd(X) % 奇异值分解:XV = US
+ % U 和 V 是酉矩阵,S 是由奇异值构成的半正定实数对角阵
+
+% 常用向量函数
+max % 最大值
+min % 最小值
+length % 元素个数
+sort % 按升序排列
+sum % 各元素之和
+prod % 各元素之积
+mode % 众数
+median % 中位数
+mean % 平均值
+std % 标准差
+perms(x) % x 元素的全排列
+
+```
+
+## 相关资料
+
+* 官方网页:[MATLAB - 技术计算语言 - MATLAB & Simulink](https://ww2.mathworks.cn/products/matlab.html)
+* 官方论坛:[MATLAB Answers - MATLAB Central](https://ww2.mathworks.cn/matlabcentral/answers/)