Pascal 转 C++ 教程2

Author Avatar
Axell 8月 07, 2018
  • 在其它设备中阅读本文章

Pascal 转 C++ 教程2

C++ 分支、循环、函数

C++ 中可以使用万能头文件 #include <bits/stdc++.h>

分支

if语句

C++中if语句的用法和Pascal基本类似,但主要有三个不同点:进行判断的条件表达式一定要用圆括号包上、条件表达式后面没有then、else前单独的语句后要加分号。

    if (a == b)  // 这里没有then
       printf("a equals b\n");  // 这里有分号
    else
       printf("a does not equal b\n");

和Pascal中一样,else子句是可选的,如果if子句或else子句中需要执行多条语句,需要用大括号包住。

    if (a == b) printf("a equals b\n");
    bool flag;
    if (a == b) {
       flag = true;
       printf("a equals b\n");
    } else {
       flag = false;
       printf("a does not equal b\n");
    }
条件表达式

条件表达式中使用&&(and)、||(or)和!(not) 的方法和Pascal中基本类型。需要注意&&和||的优先级比<、>、<=、>=、==、!=都要低,因此可以直接这样写:
if (a <= b && b <= c)
在&&和||中,&&优先级较高,也就是说
(a <= b || b <= c && b <= d)
等价于
(a <= b || (b <= c && b <= d))
需要注意!运算符的优先级很高,要适当加入括号,例如if (! (a == b))就等价于if (a != b)
还有bool类型的变量可以直接用于条件判断,无需用==运算符判断,例如flag是bool类型的变量时,直接就可以写if (flag)if (! flag)
C++中任何表达式都可以被转换成bool类型进行逻辑判断,只有0表示false,其他值都表示true。
这样的话,if (x)就等价于if (x != 0)
习惯于写Pascal程序的话,开始写C++程序时常常会犯这样的错误:if (a = b)。这样的语句是能够编译通过并执行的,它的逻辑是a=b这样的赋值表达式是有返回值的,返回值为a(或b)的值,然后再转换成bool类型进行逻辑判断。也就是说,这个if语句等价于先将b赋值给a,再判断a是否等于0,不等于0的话执行if子句中的内容。在编译的时候加上-Wall参数,有的编译器会对这样的用法给出警告信息。

switch语句

switch语句类似Pascal中的case语句。被switch的类型只能是整数类型、字符型或枚举类型。

    int x;
    scanf("%d", &x);
    switch (x) {
       case 0:
           printf("x is 0\n");
           break;
       case 1:
           printf("x is 1\n");
           break;
       case 2:
           printf("x is 2\n");
           break;
       default:
           printf("x is other value\n");
    }

每个case用于判断一个值,最后一个default块,如果没有case满足就会执行default下面的指令。注意每个case的最后要有break,每个case中不需要单独再使用花括号。还有default子句一般写在最后面。

问号运算符

C++中有一种运算符可以进行条件判断,选择表达式的值。

    int a, b, c;
    scanf("%d%d", &a, &b);
    c = (a < b) ? a : b;

问号前面的是进行判断的逻辑表达式,后面用冒号隔开两个表达式,冒号前面的表示逻辑表达式为true时的返回值,后面的表示逻辑表达式为false时的返回值。例如上面的c就被赋值为了a和b中的较小值。

循环

while循环

C++中的while循环用法和Pascal基本一样(但C++没有do)

    int x = 0;
    while (x < 10) {
       printf("%d\n", x);
       x ++;
    }

do-while循环

do-while循环类似Pascal的repeat-until循环,但是结束的逻辑相反,也就是当条件成立时继续循环。

    int x = 0;
    do {
       printf("%d\n", x);
       x ++;
    } while (x < 10);

for循环

for循环是最常用的循环方式,但是C++中的for循环和Pascal中有很大的区别。
for循环的形式一般是这样的:

    for (expr1; expr2; expr3) {
       // 循环体
    }

其中expr1、expr2、expr3分别表示三个表达式,它和下面的while循环等价:

    expr1;
    while (expr2) {
       // 循环体
       expr3;
    }

for循环中的expr1可以是变量的定义。
for循环最常用的形式是这样的:

    for (int i = 0; i < n; i ++) {
       // 循环体
    }

这里循环变量i从0循环到n-1。(至于为什么是从0到n-1,是因为数组下标是从0开始的,for循环经常和数组结合使用的)

break和continue

break用于跳出当前循环,continue用于进入当前循环的下一轮,用法和Pascal基本相同。需要注意的是,continue用在for循环中时,最后的expr3会执行。

    for (int i = 0; i < 5; i ++) {
       if (i == 4) break;
       if (i % 2 != 0) continue;
       printf("%d\n", i);
    }
    // 输出0和2

代码块

一对匹配的花括号之间的代码称作一个代码块,代码块可以进行嵌套。
在一个代码块内定义的变量只在这个代码块内存在。

    for (int i = 0; i < n; i ++) {
       int x = 10;
       printf("%d\n", x);
    }

例如上面的变量i和x只在for循环体内部存在,for循环结束后就不存在这两个变量了。
如果两个嵌套的代码块有同名变量,在里面的和外面的是不同的变量,外面的变量到了里面就被隐藏了。

    int x = 3;
    for (int i = 0; i < n; i ++) {
       int x = 10;
       printf("%d\n", x);  // 这里打印10
    }
    printf("%d\n", x);  // 这里打印3

函数

编写函数

C++中的函数是这样编写的:
返回值类型 函数名(参数列表)
下面是一个简单的例子:

    int getMax(int a, int b) {
       int res;
       if (a > b) res = a; else res = b;
       return res;
    }

最后的return表示退出函数并返回后面的东西,和Pascal的exit作用相同。

无返回值的函数

如果函数没有返回值,那么定义函数时的返回值类型就是void。

    void helloWorld() {
    printf("Hello World\n");
    }

注意即使参数列表为空,那对括号也是要有的。

关于return

对于返回值类型非void的函数,你最好确保每一条路线都有正确的return语句,不然函数的返回值是不确定的。
对于返回值为void的函数,如果不需要在中途退出,函数体执行结束后会自动返回,中途退出直接用return;语句。

调用函数

    int getMax(int a, int b) {
        return (a > b) ? a : b;
    }

    void helloWorld() {
        printf("Hello World\n");
    }

    int main() {
        int a, b;
        scanf("%d%d", &a, &b);
        int c = max(a, b);
        printf("%d\n", c);
        helloWorld();  // 这里要有括号
        return 0;
    }

引用类型的参数

引用类型的参数和Pascal中的形参含义相同。引用类型的参数在传递时必须传递具体变量,不能传递常量。

    void add(int &x) {
        x ++;
    }

    int main() {
        int a = 5;
        add(a);
        printf("%d\n", a);  // 输出6
        return 0;
    }

常引用类型的参数

常引用类型只能使用参数的值,但不能进行修改。虽然用普通的参数也可以确保修改不会被带回,但是普通参数是复制一份值,也就是说函数里创建了新的变量给你使用,如果参数占用的空间很多,复制需要的代价就很大,这时候使用常引用类型就显得更合适。与一般的引用类型相比,常引用不允许修改,可以防止不小心在函数内对引用的变量修改。

    bool cmp(const int &a, const int &b) {
        return a < b;
    }

    int main() {
        int a = 5, b = 10;
        if (cmp(a, b)) printf("a is less than b\n");
        return 0;
    }

指针类型的参数

用指针类型的参数也可以做到将修改带回。

    void add(int *p) {
        *p ++;
    }

    int main() {
        int a = 5;
        add(&a);  // 这里要用&运算取地址作为参数传递
        printf("%d\n", a);  // 输出6
        return 0;
    }

指针类型的引用

    void fun(int* &p) {
        p = new int; //将b重定向
        *p = 4;
    }

    int main() {
        int a = 5;
        int *b = &a;
        fun(b);
        printf("%d\n", *b);  // 输出4
        printf("%d\n", a);  // 输出5
        return 0;
    }

将数组作为参数传入

下面两个函数都可以将数组作为参数传入
函数中,并会将对数组元素的修改带回:

    void fun1(int a[]) {
        a[0] = 1;
    }
    void fun2(int *a) {
        a[0] = 2;
    }

    int main() {
        int t[5];
        fun1(t);
        fun2(t);
        return 0;
    }

特别需要注意的是,无论你是按照第一种写法还是第二种,a的类型都是int*(指向int的指针),sizeof(a)得到的值都是4。
如果你希望将数组作为值参传入,可以考虑写一个struct封装一个数组:

    struct array {
        int data[10];
    }
    void fun(array t) {
        t.data[0] = 1;
        printf("%d\n", t.data[0]);
    }

参数的默认值

函数的参数列表中,最后的连续若干个参数可以设置默认值,这样调用函数时可以少传递一些参数。注意调用函数时参数依然是按顺序传入,如果最后若干个参数没有给出,就会使用默认值。

    int fun(int a, int b = 10) {
        return (a < b) ? a : b;
    }
    int main() {
        int a = 5, b = 20;
        printf("%d\n", fun(a));  // 传入的值为5和10,打印5
        printf("%d\n", fun(b));  // 传入的值为20和10,打印10
        printf("%d\n", fun(a, b));  // 传入的值为5和20,打印5
        return 0;
    }

函数重载

C++支持函数重载,即名称相同、参数表不同的函数可以同时存在,并且是不同的。由于函数列表中可以有参数的默认值,因此要确保调用时不会产生二义性,比如下面两个函数就不能同时存在(其实准确地说,这两个函数同时被定义是允许的,但如果调用fun时只提供了一个参数就会给出编译错误):

    void fun(int a, int b = 10) {
        printf("%d\n", b);
    }
    void fun(int a) {
        printf("%d\n", a);
    }

编译器在对参数表进行匹配时,有可能进行隐式类型转换使得给定参数可以匹配参数表,但如果有多个重载,编译器会优先选择能够精确匹配的重载。

    #include <cstdio>
    using namespace std;
    void fun1(double x) { printf("fun1(double)\n"); }
    void fun2(double x) { printf("fun2(double)\n"); }
    void fun2(int x) { printf("fun2(int)\n"); }
    int main() {
        int a = 10;
        double b = 10.0;
        fun1(a); fun1(b); // 输出两个fun1(double)
        fun2(a); fun2(b); // 输出fun2(int)和fun2(double)
        return 0;
    }

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 3.0 未本地化版本许可协议进行许可。

本文链接:https://axell.wind-flower.cn/archives/33/