语法:ReturnType FunctionName(Parameters) { FunctionBody }
例:下取整函数
int floor(double x) {
// ...
}
一个函数可以接受多个参数(
(int x, int y) 不可以省略为 (int x, y)ReturnType myFunction(Type1 a1, Type2 a2, Type3 a3) {
// ...
}
一个函数可以没有返回值,这样的函数返回值类型为 void。
和数学函数不同,C 函数不仅仅是“接受一些参数、返回一个值”,它实际上就是将一小段具有特定功能的代码单独拎出来,并且给它起个名字。
一个函数可以不接受参数(void
ReturnType do_some_work(void) {
// ...
}
和 C++ 不同,参数列表空着并不代表不接受参数,而是表示 "accepting unknown parameters"。这项规则自 C23 起才被删除。
在 C99 之前,一个函数如果不写返回值类型,则返回值类型默认为 int。
事实上在旧的 C 语言中存在着大量的“默认为 int”的规则,在很多场合下这种写法极易引发难以预料的问题。
你可能见过一些人写这样的 main 函数:
main() {
// ...
}
这不符合现代 C 语言的语法,也是极不推荐的写法。
如果你调用了一个未经声明的函数
#include <stdio.h>
int main(void) {
int x = my_mysterious_function();
printf("%d\n", x);
}
C++ 编译器会给出一个十分正常的报错: "... was not declared in this scope"
a.cpp: In function ‘int main()’:
a.cpp:4:11: error: ‘my_mysterious_function’ was not declared in this scope
4 | int x = my_mysterious_function();
| ^~~~~~~~~~~~~~~~~~~~~~
如果你调用了一个未经声明的函数
#include <stdio.h>
int main(void) {
int x = my_mysterious_function();
printf("%d\n", x);
}
而 C 编译器会允许,并且给出一个令人困惑的 warning: "implicit declaration"
a.c: In function ‘main’:
a.c:4:11: warning: implicit declaration of function ‘my_mysterious_function’
[-Wimplicit-function-declaration]
4 | int x = my_mysterious_function();
| ^~~~~~~~~~~~~~~~~~~~~~
当然,它是无法运行的,链接器会抱怨“找不到名为 my_mysterious_function 的函数”。
如果你调用了一个未经声明的函数
#include <stdio.h>
int main(void) {
int x = my_mysterious_function();
printf("%d\n", x);
}
C 标准认为你“隐式地声明” (implicitly declare) 了这个函数,于是压力全都给到链接器。
这一规则 C99 起被删除,但为了向后兼容 (backward compatibility),编译器很可能仍然支持,只是给一个 warning。
main 函数的返回值函数的返回值是传给它的调用者的。
main 的“调用者”是谁?main 函数的返回值函数的返回值是传给它的调用者的。
main 的“调用者”是谁?——程序的调用者/“宿主环境” (hosted environment)main 函数返回 0 ——程序正常退出
main 函数返回其它值——代表某种错误
1 。scanf 和 printf虽然文档有点复杂,但也要试着在这里检索你需要的信息。
#include <stdio.h>
int main(void) {
int a, b;
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
return 0;
}
约定输入格式:两行,每行一个整数,分别表示 a 和 b。
scanf("%d\n%d\n", &a, &b) 会发生什么?试一试。约定输入格式:两行,每行一个整数,分别表示 a 和 b。
scanf("%d\n%d\n", &a, &b) 会卡住,直到你输入了一个非空白字符为止。
看看标准:
whitespace characters: any single whitespace character in the format string consumes all available consecutive whitespace characters from the input (determined as if by calling isspace in a loop). Note that there is no difference between
"\n"," ","\t\t", or other whitespace in the format string.
whitespace character: “空白字符”,包括空格、换行、回车、制表等。
约定输入格式:两行,每行一个整数,分别表示 a 和 b。
scanf("%d%d", &a, &b) 可以吗?试一试。约定输入格式:两行,每行一个整数,分别表示 a 和 b。
scanf("%d%d", &a, &b) 可以。
中间的换行符不写也可以?看看标准:
"%d"matches a decimal integer.
The format of the number is the same as expected by
strtolwith the value 10 for the base argument.
strtol 是什么鬼?点进去看看:
Interprets an integer value in a byte string pointed to by str.
Discards any whitespace characters (as identified by calling
isspace) until the first non-whitespace character is found, then...
printfdouble 需要用 %lf 输出。如果我用 %d 输出,会怎样?
#include <stdio.h>
int main(void) {
double pi = 3.14;
printf("%d\n", pi);
return 0;
}
它和先将 pi 转换为 int(小数部分截去)再输出的效果一样吗?
double pi = 3.14;
int pi_int = pi; // pi_int 值为 3
printf("%d\n", pi_int);
printf在 scanf 和 printf 中,conversion specifier 与对应的变量类型不匹配是 undefined behavior:你不能对程序的行为做任何假定。
以下说法统统是错的:
程序完全有可能在这里直接崩溃。此外,编译器可以假定你的程序不含 undefined behavior,所以它如果发现这里有 undefined behavior,就可以直接把这行代码删掉,这完全符合语言标准。
Note: 标有星号(*)的工具很重要,但将在我们的课程中进行功能介绍。为了更深入地了解它们的用法,我们鼓励您独立探索
git init : 初始化一个git仓库git commit : 本地保存仓库更改git reset : 回溯到某个版本git log : 显示历史提交记录git push : 把本地的更改上传远程云端git pull : 从云端拉取远端最新的更改使得和云端仓库一致