C 语言答疑-01

​ By Von Brank | 2020/10/28

目录:

  • IDE 的推荐与使用
  • 在线评测系统的推荐与使用
  • 近期所学知识梳理
  • 常见错误
  • 几道例题
  • 答疑

IDE 的推荐与使用

  • Dev-Cpp

  • Visual Studio Code

在线评测系统的推荐与使用

知识点梳理

函数


函数的基本应用

解决代码重复率高,质量低下的问题

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int i, sum;
for(i=1, sum=0; i<=10; i++) //计算1~10的和
{
sum += i;
}
printf("%d\n", sum);

for(i=11, sum=0; i<=20; i++) //计算11~20的和
{
sum += i;
}
printf("%d\n", sum);

for(i=21, sum=0; i<=30; i++) //计算21~30的和
{
sum += i;
}
printf("%d\n", sum);

写成函数形式

1
2
3
4
5
6
7
8
9
void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}

函数的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<函数头> <函数名>(参数表)
{
函数体
}

void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}

函数的调用

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
void hello()
{
printf("Hello World!!!");
}
int main()
{
hello; -> 错误写法
hello(); //没有参数也要()
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
sum(1, 10);
sum(11, 20);
sum(21, 30);
return 0;
}

函数的返回值

返回类型 写法
void function();
int int function();
double double function();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
return ans; //注意:非void类型函数结尾必须写return语句
}
int main()
{
printf("%d\n", sum(1, 10));
return 0;
}
  • return是函数的出口
  • return <变量>;是非void函数的出口,并返回一个值
  • void函数中的return;仅作为函数的出口

函数原型(声名)

  • main 函数之前声名,在main函数后定义一定程度上可以避免头重脚轻,但通常不会这么写
  • C/C++/Java 语言对于声名,定义等概念有严格要求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int sum(int a, int b); //告诉编译器这个函数的样子
int main()
{
printf("%d\n", sum(1, 10));
return 0;
}
int sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
return ans;
}

参数的传递

本质上是用传入的参数初始化函数参数表的变量

注意:

  • 传递的参数要与参数表对应类型相匹配
  • 传递参数的个数要与对应函数参数表的变量个数相匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
sum(1.1, 9.9); //不匹配的参数类型会被强制类型转换,然后以其结果初始化参数
sum(11, 20, 30); //传入的参数个数不匹配会导致编译错误
sum(21, 30);
return 0;
}

参数在函数内是本地变量

  • 变量的值作为参数初始化参数表的变量时,参变量值的改变不会改变被传入参数的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void sum(int a, int b)
{
n = 1;
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
int m = 1, n = 10;
sum(m, n);
return 0;
}
  • 与全局变量同名的参数表变量会将该全局变量屏蔽
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int a, b;
void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
sum(1, 10);
return 0;
}
  • 不与参变量同名的全局非常量变量可以在函数内直接被修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int n;
void sum(int a, int b)
{
n = 1;
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
sum(1, 10);
return 0;
}
  • 代码块内部的变量也是本地变量,与函数内的本地变量类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main()
{
int a, b;
a = 1;
b = 2;
printf("%d %d\n", a, b);
{
int a;
a = 3;
printf("%d %d\n", a, b);
}
return 0;
}

关于函数的一些细节

  • void function(void);以及void function();表示参数未知,并不表示没有参数,

如:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void f();
int main()
{
int a = 1, b = 2;
f(a, b);
return 0;
}
void f(double a, double b)
{
printf("%d %d", a, b);
}

这类写法是编译器的作者没想到的,因此在编写函数原型时一定要写全参数,在没有参数时可写void

  • 逗号预算符,在参数传递中可能导致的错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
int a, b;
void sum(int a, int b)
{
int ans = 0, i;
for(i=a; i<=b; i++)
{
ans += i;
}
printf("%d\n", ans);
}
int main()
{
int a = 1, b = 10;
sum(a, b);
sum((a, b)); //比较这两行的区别
return 0;
}
  • C/C++语言不允许函数内嵌套函数

  • 几种鬼畜的写法

    如:

    1
    2
    3
    int i, j, sum(int a, int b);

    return (ans);

    以上写法可以通过编译,但不推荐使用

main()是什么

  • int main()也是一个函数
  • 可以写成int main(void)但通常不这么写
  • main函数结尾的return 0;是有意义的

递归

  • 递归是程序运行过程中函数调用自身的行为

  • 阶乘斐波那契数列是经典的递归案例,但是学完数组之后你很可能不会再用递归来实现它们

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int Fib(int n)
    {
    if(n == 1 || n == 2) return 1;
    else return Fib(n - 1) + Fib(n - 2);
    }

    int Fac(int n)
    {
    if(n == 0) return 1;
    else return n * Fac(n - 1);
    }
  • C 语言中递归的本质——

几道题

洛谷 P5735 【深基 7.例 1】距离函数

给出平面坐标上不在一条直线上三个点坐标$ (x_1,y_1),(x_2,y_2),(x_3,y_3)$,坐标值是实数,且的绝对值不超过 100.00100.00,求围成的三角形周长。保留两位小数。

对于平面上的两个点 (x1,y1),(x2,y2)(x_1,y_1),(x_2,y_2),则这两个点之间的距离 dis=(x2x1)2+(y2y1)2dis=\sqrt{(x_2-x_1)^2+(y_2-y_1)^2}

洛谷 P5737 【深基 7.例 3】闰年展示

输入 x,y(1582x<y3000)x,y(1582\le x < y \le 3000),输出$[x,y] $区间中闰年个数,并在下一行输出所有闰年年份数字,使用空格隔开。

洛谷 P1255 数楼梯

楼梯有NN阶,上楼可以一步上一阶,也可以一步上二阶。

编一个程序,计算共有多少种不同的走法。

洛谷 P1464 Function

对于一个递归函数w(a,b,c)w(a,b,c)

  • 如果a0orb0orc0a \le 0\quad or\quad b \le 0 \quad or\quad c \le 0就返回值1111
  • 如果a>20orb>20orc>20a>20\quad or\quad b>20\quad or\quad c>20\quad就返回w(20,20,20)w(20,20,20)
  • 如果a<ba<b并且$b<c 就返回就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)$
  • 其它的情况就返回w(a1,b,c)+w(a1,b1,c)+w(a1,b,c1)w(a1,b1,c1)w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)

这是个简单的递归函数,但实现起来可能会有些问题。当a,b,ca,b,c均为1515时,调用的次数将非常的多。你要想个办法才行.

对于一些特殊情况,比如 w(30,1,0)w(30,-1,0)既满足条件11又满足条件22,这种时候我们就按最上面的条件来算,所以答案为11

洛谷 P1029 最大公约数和最小公倍数问题

输入两个正整数 x0,y0x_0, y_0,求出满足下列条件的 P,QP, Q 的个数:

  1. P,QP,Q 是正整数。
  2. 要求 P,QP, Qx0x_0 为最大公约数,以 y0y_0 为最小公倍数。

试求:满足条件的所有可能的 P,QP, Q 的个数。