Pascal转C++
在 浅谈了Pascal转C++后,我们深谈Pascal转C++。
sacnf() 和 printf()
scanf 与 printf 其实是 C 语言提供的函数,保存在<cstdio>
或<stdio.h>
头文件中。一般情况下,它们的速度比 cin
和 cout
快得多的多(如果想要更快,可以用快读和快写),并且能够方便地控制输入输出格式。
#include <bits/stdc++.h>
int main() {
int x, y;
scanf("%d%d", &x, &y); // 读入 x 和 y
printf("%d\n%d", y, x); // 输出 y,换行,再输出 x
return 0;
}
其中,\n
是换行符, %d
表示读入或输出的变量是一个有符号整型 ( int 型)的变量。
类似地,常见的有:
%s
表示字符串string(包括字符数组)。
%c
表示字符。
%f
表示单精度浮点数 ( float )。
%lf
表示双精度浮点数 ( double )。
%lld
表示长整型 ( long long )。根据系统不同,也可能是 %I64d 。
%u
表示无符号整型 ( unsigned int )。
%llu
表示无符号长整型 ( unsigned long long ),也可能是 %I64u 。
除了类型标识符以外,还有一些控制格式的方式。许多都不常用,选取两个常用的列举如下:
%1d
表示长度为 1 的整型。在读入时,即使没有空格也可以逐位读入数字。在输出时,若指定的长度大于数字的位数,就会在数字前用空格填充。若指定的长度小于数字的位数,就没有效果。
%.2lf
或%0.2lf
,用于输出,保留2位小数。
为什么scanf()里有& ,printf() 里没有& ?
在这里, & 实际上是取址运算符,返回的是变量在内存中的地址。而 scanf 接收的参数就是变量的地址。具体可能要用指针才能完全清楚地说明,现在只需要记下来就好了。
注意:
读入字符串和字符数组的时候,没有&
例:#include <bits/stdc++.h> using namespace std; int main() { char a[105]; scanf("%s",a); return 0; }
#define 宏定义
#define
是一种预处理命令,用于定义宏,本质上是文本替换。例如:
#include <bits.stdc++.h>
#define N 105;
using namespace std;
int main() {
cout << N << endl;
return 0;
}
N 不是变量,而是编译器会将代码中所有 N 文本替换为 105,但是作为标识符一部分的。N 的就不会被替换,如 MN 不会被替换成 M105,同样,字符串内的也不会被替换。
比如说,我们还可以这样:
#define re(i,a,b) for(int i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define LL long long
#define ULL unsigned long long
#define max(a,b) (((a)>(b)) ? (a):(b))
#define min(a,b) (((a)<(b)) ? (a):(b))
害,差点忘了,三目运算符还没讲。
三目运算符
为什么叫三目运算符?
单目运算符: 例:i++ (只有i一个操作数)
双目运算符: 例:a+b (a、b两个操作数)
三目运算符: a ? b : c (a,b,c三个操作数)
a ? b : c
相当于:
if(a) {
return b;
} else {
return c;
}
例子:
inline int abs(int a) {
return a>0 ? a : -a;
}
inline int gcd(int a,int b) {
return b>0 ? gcd(b,a%b):a;
}
其他gcd函数的写法:https://blog.csdn.net/Ljnoit/article/details/99319849
结构体 struct
结构体(struct),可以看做是一系列称为成员元素的组合体。
可以看做是自定义的数据类型。
本页描述的 struct
不同于 C 中 struct
,在 C++ 中 struct
被扩展为类似 class
的类说明符。
定义结构体
struct Object {
int weight;
int value;
} e[105];
const Object a;
Object b, B[105], tmp;
Object *c;
上例中定义了一个名为 Object
的结构体,两个成员元素 value
,weight
,类型都为 int 。
在}
后,定义了数据类型为Object
的常量 a
,变量 b
,变量tmp
,数组 B
,指针 c
。对于某种已经存在的类型,都可以使用这里的方法进行定义常量、变量、指针、数组等。
关于指针:不必强求掌握。
定义指针
如果是定义内置类型的指针,则与平常定义指针一样。
如果是定义结构体指针,在定义中使用 StructName*
进行定义。
struct Edge {
/*
...
*/
Edge* nxt;
};
上例仅作举例,不必纠结实际意义。
访问/修改成员元素
可以使用 变量名.成员元素名 进行访问(其中双引号不写入程序,下同)。
如 : 输出 var 的 v 成员: cout << var.v
。
也可以使用 指针名->成员元素名 或者 使用 (*指针名).成员元素名 进行访问。
如 : 将结构体指针 ptr 指向的结构体的成员元素 v 赋值为 tmp : (*ptr).v = tmp 或者 ptr->v = tmp 。
为什么需要结构体?
首先,条条大路通罗马,可以不使用结构体达到相同的效果。但是结构体能够显式地将成员元素(在算法竞赛中通常是变量)捆绑在一起,如本例中的Object
结构体,便将value
,weight
放在了一起(定义这个结构体的实际意义是表示一件物品的重量与价值)。这样的好处边是限制了成员元素的使用。
想象一下,如果不使用结构体而且有两个数组value[]
,Value[]
,很容易写混淆。但如果使用结构体,能够减轻出现使用变量错误的几率。并且不同的结构体(结构体类型,如
Object
这个结构体)或者不同的结构体变量(结构体的实例,如上方的e
数组)可以拥有相同名字的成员元素(如tmp
.value
,b.value
),同名的成员元素相互独立(拥有独自的内存,比如说修改 tmp.value 不会影响b.value
的值)。
这样的好处是可以使用尽可能相同或者相近的变量去描述一个物品。比如说 Object 里有 value 这个成员变量;我们还可以定义一个Car
结构体,同时也拥有 value 这个成员;如果不使用结构体,或许我们就需要定义valueOfObject[]
,valueOfCar[]
等不同名称的数组来区分。
文件操作
读入文件内容:
freopen("data.in", "r", stdin);
data.in 就是读取的文件名,要和可执行文件放在同一目录下
输出到文件:
freopen("data.out", "w", stdout);
data.out 就是输出文件的文件名,和可执行文件在同一目录下
关闭标准输入/输出流
fclose(stdin);
fclose(stdout);
freopen()
函数在<cstdio>
或<fstream>
头文件中。
命名空间
C++ 的 命名空间 可以用来解决复杂项目中名字冲突的问题。
举个例子:C++ 标准库的所有内容均定义在 std 命名空间中,如果你定义了一个叫 cin 的变量,则可以通过 cin 来访问你定义的 cin 变量,通过 std::cin 访问标准库的 cin 对象,而不用担心产生冲突。
下面的代码声明了一个名字叫 A 的命名空间:
namespace A {
int cnt;
void f(int x) { cnt = x; }
} // namespace A
声明之后,在这个命名空间外部,你可以通过 A::f(x) 来访问命名空间 A 内部的 f 函数。
命名空间的声明是可以嵌套的,因此下面这段代码也是允许的:
namespace A {
namespace B {
void f() { ... }
} // namespace B
void f() {
B::f(); // 实际访问的是 A::B::f(),由于当前位于命名空间 A 内,所以可以省略前面的 A::
}
} // namespace A
void f() //这里定义的是全局命名空间的 f 函数,与 A::f 和 A::B::f 都不会产生冲突
{
A::f();
A::B::f();
}
声明了命名空间之后,如果在命名空间外部访问命名空间内部的成员,需要在成员名前面加上 命名空间::
。
有没有什么比较方便的方法能让我们直接通过成员名访问命名空间内的成员呢?答案是肯定的。我们可以使用 using
指令。
using
指令有如下两种形式:
1.using 命名空间::成员名;
:这条指令可以让我们省略某个成员名前的命名空间,直接通过成员名访问成员,相当于将这个成员导入了当前的作用域。
2.using namespace 命名空间;
:这条指令可以直接通过成员名访问命名空间中的 任何 成员,相当于将这个命名空间的所有成员导入了当前的作用域。
因此,如果执行了 using namespace std;
,就会将 std 中的所有名字引入到全局命名空间当中。这样,我们就可以用 cin
代替 std::cin
,用 cout
代替 std::cout
。
using 指令可能会导致命名冲突!
由于 using namespace std;
会将 std
中的 所有名字 引入,因此如果声明了与 std
重名的变量或函数,就可能会因为命名冲突而导致编译错误。
因此在工程中,并不推荐使用 using namespace
命名空间; 的指令。
有了 using 指令, C++ 语法基础 中的代码可以有这两种等价写法:
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
int x, y;
cin >> x >> y;
cout << y << endl << x;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int x, y;
cin >> x >> y;
cout << y << endl << x;
return 0;
}
在一些具有多个子任务的问题中,我们可以对每个子任务各开一个命名空间,在其中定义我们解决该子任务所需要的变量与函数,这样各个子任务间互不干扰,会在一定程度上方便调试,也会改善程序的可读性。