Pascal 转 C++ 教程2
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://hs-blog.axell.top/archives/33/