1.break和continue
break | continue |
---|---|
使用break语句是跳出当前循环,并执行当前循环之后的语句; | continue语句是终止当前循环,并继续执行下一次循环; |
2.switch语句case后有无break
有break | 无break |
---|---|
跳出 | 继续执行下面的语句,直到遇见break |
eg:
#include <stdio.h>
main()
{
int a=0,i;
for(i=1;i<5;i++){
switch(i){
case 0:
case 3: a+=2;break;
case 1:
case 2: a+=3;
default : a+=5;
}
}
printf("%d\n",a);
}
/*结果为23*/
#include <stdio.h>
main()
{
int a=0,i;
for(i=1;i<5;i++){
switch(i){
case 0:
case 3: a+=2;
case 1:
case 2: a+=3;
default : a+=5;
}
}
printf("%d\n",a);
}
/*结果为31*/
3.case 0与case0
case 0 | case0 |
---|---|
正常的case语句 | 被当作goto标签,直接走default |
eg:
#include <stdio.h>
main()
{
int a=0,i;
for(i=1;i<5;i++){
switch(i){
case 0:
case 3: a+=2;break;
case 1:
case 2: a+=3;
default : a+=5;
}
}
printf("%d\n",a);
}
/*结果为23*/
#include <stdio.h>
main()
{
int a=0,i;
for(i=1;i<5;i++){
switch(i){
case0:
case3: a+=2;break;
case1:
case2: a+=3;
default : a+=5;
}
}
printf("%d\n",a);
}
/*直接循环了4次default,所以输出为20*/
4.strlen() 和 sizeof()
strlen() | sizeof() |
---|---|
求得的是字符串的长度 | 计算字符串占的总内存空间 |
eg:str[20]={"abcd"};strlen(str); ,结果为4 | eg:str[20]="abcd";sizeof(str) ,结果为20 |
函数 | 单目运算符 |
计算时不包括’\0’ | 计算时包括’\0’ |
eg:
#include <stdio.h>
int main(){
char str[]="abcde";
printf("strlen=%d\n",strlen(str));
printf("sizeof=%d\n",sizeof(str));
return 0;
}
/*输出为:
strlen=5
sizeof=6
*/
5.合法标识符(关键字)
C语言规定,标识符只能由字母(A-Z, a-z)、数字(0~9)和下划线(_)组成,并且第一个字符必须是字母或下划线,不能是数字。
- 在考试中标识符的一些陷阱
- 调换关键字的拼写顺序,eg:
void
与viod
,前者是关键字不能用作标识符,而后者可以 - 关键字的首字母拼写,C语言规定关键字全为小写,eg:
union
与Union
,前者是关键字不能用作标识符,而后者可以
- 调换关键字的拼写顺序,eg:
6.a++和++a
a++ | ++a |
---|---|
先取值操作再自增 | 先自增再取值操作 |
int a=0,b=0;while(a++) b++; ,先取a=0,然后再自增 | int a=0,b=0;while(++a) b++; ,a先自增,此时a为1 |
7.局部变量和全局变量
局部变量 | 全局变量 |
---|---|
定义在函数内部的变量称为局部变量,它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错。 | 在所有函数外部定义的变量称为全局变量,它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件。 |
/*局部变量示例*/
int f1(int a){
int b,c; //a,b,c仅在函数f1()内有效
return a+b+c;
}
int main(){
int m,n; //m,n仅在函数main()内有效
return 0;
}
- 注意:
- 在 main 函数中定义的变量也是局部变量,只能在 main 函数中使用;同时,main 函数中也不能使用其它函数中定义的变量。main 函数也是一个函数,与其它函数地位平等。
- 形参变量、在函数体内定义的变量都是局部变量。实参给形参传值的过程也就是给局部变量赋值的过程。
- 可以在不同的函数中使用相同的变量名,它们表示不同的数据,分配不同的内存,互不干扰,也不会发生混淆。
- 在语句块中也可定义变量,它的作用域只限于当前语句块。
/*全局变量示例*/
int a, b; //全局变量
void func1(){
//TODO:
}
float x,y; //全局变量
int func2(){
//TODO:
}
int main(){
int c;//局部变量
return 0;
}
- 注意:a、b、x、y 都是在函数外部定义的全局变量。C语言代码是从前往后依次执行的,由于 x、y 定义在函数 func1() 之后,所以在 func1() 内无效;c定义在main()函数内部,所以只对main()函数起作用;而 a、b 定义在源程序的开头,所以在 func1()、func2() 和 main() 内都有效。
- 当全局变量和局部变量同名时,在局部范围内全局变量被“屏蔽”,不再起作用。或者说,变量的使用遵循就近原则,如果在当前作用域中存在同名变量,就不会向更大的作用域中去寻找变量。
8.运算符优先级
eg:有以下程序,输出结果是(2021 )
#include "stdio.h"
int main(){
int b=0;
b=(5+5,1010+1011),3+8;
printf("%d\n",b);
return 0;
}
很明显,(5+5,1010+1011)是一个逗号表达式得到的结果是1010+1011=2021,然后是赋值运算符和第二个逗号表达式的优先级,逗号的优先级最低,所以执行的是赋值语句,即b=2021。此处容易忽略第二次运算符优先级。
9.内存空间占用
struct结构体 | union共用体 |
---|---|
占用内存为各个成员占用内存总和 | 占用内存为最长的成员占用的内存 |
常见变量类型type | 占用内存空间sizeof() |
---|---|
int | Turbo C为2,VC为4。应对专升本考试默认为Turbo C,即为2。 |
short | 2 |
char | 4 |
float | 4 |
double | 8 |
int * | 8 |
char * | 8 |
float * | 8 |
double * | 8 |
10.递归
一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层,当最内层的函数执行完毕后,再一层一层地由里到外退出。
递归两个必要条件:
递归实例,求阶乘:
阶 乘 n ! 的 公 式 : n ! = { 1 , ( n = 0 , 1 ) n ∗ ( n − 1 ) ! , n > 1 阶乘n!的公式:n!=\begin{cases}1, (n=0,1)\\ n*(n-1)!,n>1\end{cases} 阶乘n!的公式:n!={1,(n=0,1)n∗(n−1)!,n>1
#include <stdio.h>
//求n的阶乘
long factorial(int n) {
if (n == 0 || n == 1) {
return 1;
}
else {
return factorial(n - 1) * n; // 递归调用
}
}
int main() {
int a;
printf("Input a number: ");
scanf("%d", &a);
printf("Factorial(%d) = %ld\n", a, factorial(a));
return 0;
}
在以上代码中factorial() 就是一个典型的递归函数。调用 factorial() 后即进入函数体,只有当 n==0
或 n==1
时函数才会执行结束,否则就一直调用它自身。
由于每次调用的实参为 n-1,即把 n-1 的值赋给形参 n,所以每次递归实参的值都减 1,直到最后 n-1 的值为 1 时再作递归调用,形参 n 的值也为1,递归就终止了,会逐层退出。
递归的进入
- 求 5!,即调用 factorial(5)。当进入 factorial() 函数体后,由于形参 n 的值为 5,不等于 0 或 1,所以执行
factorial(n-1) * n
,也即执行factorial(4) * 5
。为了求得这个表达式的结果,必须先调用 factorial(4),并暂停其他操作。换句话说,在得到 factorial(4) 的结果之前,不能进行其他操作。这就是第一次递归。 - 调用 factorial(4) 时,实参为 4,形参 n 也为 4,不等于 0 或 1,会继续执行
factorial(n-1) * n
,也即执行factorial(3) * 4
。为了求得这个表达式的结果,又必须先调用 factorial(3)。这就是第二次递归。 - 以此类推,进行四次递归调用后,实参的值为 1,会调用 factorial(1)。此时能够直接得到常量 1 的值,并把结果 return,就不需要再次调用 factorial() 函数了,递归就结束了。
层次/层数 | 实参/形参 | 调用形式 | 需要计算的表达式 | 需要等待的结果 |
---|---|---|---|---|
1 | n=5 | factorial(5) | factorial(4) * 5 | factorial(4) 的结果 |
2 | n=4 | factorial(4) | factorial(3) * 4 | factorial(3) 的结果 |
3 | n=3 | factorial(3) | factorial(2) * 3 | factorial(2) 的结果 |
4 | n=2 | factorial(2) | factorial(1) * 2 | factorial(1) 的结果 |
5 | n=1 | factorial(1) | 1 | 无 |
递归的退出
当递归进入到最内层的时候,递归就结束了,就开始逐层退出了,也就是逐层执行 return 语句。
- n 的值为 1 时达到最内层,此时 return 出去的结果为 1,也即 factorial(1) 的调用结果为 1。
- 有了 factorial(1) 的结果,就可以返回上一层计算
factorial(1) * 2
的值了。此时得到的值为 2,return 出去的结果也为 2,也即 factorial(2) 的调用结果为 2。 - 以此类推,当得到 factorial(4) 的调用结果后,就可以返回最顶层。经计算,factorial(4) 的结果为 24,那么表达式
factorial(4) * 5
的结果为 120,此时 return 得到的结果也为 120,也即 factorial(5) 的调用结果为 120,这样就得到了 5! 的值。
层次/层数 | 调用形式 | 需要计算的表达式 | 从内层递归得到的结果 (内层函数的返回值) | 表达式的值 (当次调用的结果) |
---|---|---|---|---|
5 | factorial(1) | 1 | 无 | 1 |
4 | factorial(2) | factorial(1) * 2 | factorial(1) 的返回值,也就是 1 | 2 |
3 | factorial(3) | factorial(2) * 3 | factorial(2) 的返回值,也就是 2 | 6 |
2 | factorial(4) | factorial(3) * 4 | factorial(3) 的返回值,也就是 6 | 24 |
1 | factorial(5) | factorial(4) * 5 | factorial(4) 的返回值,也就是 24 | 120 |
至此,我们已经对递归函数 factorial() 的进入和退出流程做了深入的讲解,把看似复杂的调用细节逐一呈献给大家,即使你是初学者,相信你也能解开谜团。
递归的条件
每一个递归函数都应该只进行有限次的递归调用,否则它就会进入死胡同,永远也不能退出了,这样的程序是没有意义的。
要想让递归函数逐层进入再逐层退出,需要解决两个方面的问题:
- 存在限制条件,当符合这个条件时递归便不再继续。对于 factorial(),当形参 n 等于 0 或 1 时,递归就结束了。
- 每次递归调用之后越来越接近这个限制条件。对于 factorial(),每次递归调用的实参为 n - 1,这会使得形参 n 的值逐渐减小,越来越趋近于 1 或 0。
11.转义字符
- 在程序中
int a=0x6d;
,是把一个十六进制的数给变量a,0x必须写。 - 在程序中
int a=06d
,是一个八进制的形式。 - 在转义字符中,’\x6d’才是合法的,0不能写,并且x必须小写。
- '\141’是合法的,0是不能写的。
- '\108’是非法的,因为不可以出现8。
12.强制转换
是类型上加括号,而不是变量或值上加括号。必须是(int)a
,而不是int(a)
。
特别注意:
(int)(a+b) | (int)a+b |
---|---|
将a+b转型 | 将a转型再加b |
13.对星号*
的总结
在我们目前所学到的语法中,星号*
主要有三种用途:
- 表示乘法,例如
int a = 3, b = 5, c; c = a * b;
,这是最容易理解的。 - 表示定义一个指针变量,以和普通变量区分开,例如
int a = 100; int *p = &a;
。 - 表示获取指针指向的数据,是一种间接操作,例如
int a, b, *p = &a; *p = 100; b = *p;
。