C语言易混淆问题

1.break和continue

breakcontinue
使用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 0case0
正常的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);,结果为4eg: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)和下划线(_)组成,并且第一个字符必须是字母或下划线,不能是数字。

C语言32个关键字-博客园

C语言32个关键字-简书

C语言32个关键字-CSDN

  • 在考试中标识符的一些陷阱
    • 调换关键字的拼写顺序,eg:voidviod,前者是关键字不能用作标识符,而后者可以
    • 关键字的首字母拼写,C语言规定关键字全为小写,eg:unionUnion,前者是关键字不能用作标识符,而后者可以

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。此处容易忽略第二次运算符优先级

C语言运算符优先级参考-博客园

C语言运算符优先级参考-简书

C语言运算符优先级参考-CSDN

9.内存空间占用

struct结构体union共用体
占用内存为各个成员占用内存总和占用内存为最长的成员占用的内存
常见变量类型type占用内存空间sizeof()
intTurbo C为2,VC为4。应对专升本考试默认为Turbo C,即为2。
short2
char4
float4
double8
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(n1)!,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==0n==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() 函数了,递归就结束了。
层次/层数实参/形参调用形式需要计算的表达式需要等待的结果
1n=5factorial(5)factorial(4) * 5factorial(4) 的结果
2n=4factorial(4)factorial(3) * 4factorial(3) 的结果
3n=3factorial(3)factorial(2) * 3factorial(2) 的结果
4n=2factorial(2)factorial(1) * 2factorial(1) 的结果
5n=1factorial(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! 的值。
层次/层数调用形式需要计算的表达式从内层递归得到的结果 (内层函数的返回值)表达式的值 (当次调用的结果)
5factorial(1)11
4factorial(2)factorial(1) * 2factorial(1) 的返回值,也就是 12
3factorial(3)factorial(2) * 3factorial(2) 的返回值,也就是 26
2factorial(4)factorial(3) * 4factorial(3) 的返回值,也就是 624
1factorial(5)factorial(4) * 5factorial(4) 的返回值,也就是 24120

至此,我们已经对递归函数 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;
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小飞睡不醒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值