C语言面试题(1)

1. 局部变量和静态变量的区别

① 存储位置:

  • 普通局部变量存储在栈上。
  • 静态局部变量存储在静态存储区。

② 生命周期:

  • 当函数执行完毕时,普通局部变量会被销毁。
  • 静态局部变量的生命周期是整个程序运行期间,即使函数调用结束,静态局部变量的值也会被保留。

③ 初始值:

  • 普通局部变量在每次函数调用时都会被初始化,它们的初始值是不确定的,除非显式地进行初始化。
  • 静态局部变量在第一次函数调用时,然后保持其值不变,直到程序结束。

示例代码:

#include <stdio.h>  
  
// 定义一个函数normal_func,该函数打印局部变量的值  
void normal_func()  
{  
    // 定义一个局部变量i,并初始化为0  
    int i = 0;  
    // 将局部变量i的值加1  
    i++;  
    // 打印局部变量i的当前值  
    printf("局部变量 i = %d\n", i);  
}  
  
// 定义一个函数static_func,该函数打印静态局部变量的值  
void static_func()  
{  
    // 定义一个静态局部变量j,并初始化为0(仅在第一次调用该函数时初始化)  
    static int j = 0;  
    // 将静态局部变量j的值加1  
    j++;  
    // 打印静态局部变量j的当前值  
    printf("static局部变量 j = %d\n", j);  
}  
  
int main()  
{  
    // 调用normal_func函数三次  
    // 由于i是局部变量,每次函数调用时都会重新创建i,并初始化为0  
    // 因此,每次打印的i的值都是1  
    normal_func();    // 输出:局部变量 i = 1  
    normal_func();    // 输出:局部变量 i = 1  
    normal_func();    // 输出:局部变量 i = 1  
  
    // 调用static_func函数三次  
    // 由于j是静态局部变量,它在函数第一次调用时初始化,并保留其值  
    // 因此,每次函数调用后,j的值都会累加  
    static_func();    // 输出:static局部变量 j = 1  
    static_func();    // 输出:static局部变量 j = 2  
    static_func();    // 输出:static局部变量 j = 3  
  
    return 0;  
}

运行结果:

2. 预处理

C语言对源程序处理的四个步骤:预处理、编译、汇编、链接。

① 预处理

  • 宏定义展开、头文件展开、条件编译,这里并不会检查语法

② 编译

  • 检查语法,将预处理后文件编译生成汇编文件

③ 汇编

  • 将汇编文件生成目标文件(二进制文件)

④ 链接

  • 将目标文件链接为可执行程序

3.文件包含处理

① 文件包含处理

  • 指一个源文件可以将另外一个文件的全部内容包含进来
  • C语言提供了#include命令用来实现文件包含的操作

② #include< > 与 #include ""的区别

  • <> 表示系统直接按系统指定的目录检索
  • "" 表示系统先在 "" 指定的路径(没写路径代表当前路径)查找头文件,如果找不到,再按系统指定的目录检索

4.宏定义

在预编译时将宏名替换成字符串的过程称为"宏展开"(也叫宏替换)。

  • 宏名一般用大写,以便于与变量区别
  • 宏定义不作语法检查,只有在编译被宏展开后的源程序才会报错
  • 宏定不要不要行末加分号

代码示例:

#define PI 3.14
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define FUNC(a)  func(a)

void func(int a) {
    int b = a;
}

int main() {
    double a = PI;
    int temp = MAX(1, 2+3);
    FUNC(10);

    return 0;
}

5.条件编译

一般情况下,源程序中所有的行都参加编译。但有时希望对部分源程序行只在满足一定条件时才编译,即对这部分源程序行指定编译条件。

防止头文件被重复包含、
#ifndef _SOMEFILE_H
#define _SOMEFILE_H

//需要声明的变量、函数
//宏定义
//结构体

#endif
软件裁剪

同样的C源代码,条件选项不同可以编译出不同的可执行程序:

#include <stdio.h>

// #define A 有注释,没有注释,观察运行结果
#define A

int main() {
#ifdef A
    printf("这是大写操作\n");
#else
    printf("这是小写操作\n");
#endif

    return 0;
}

 6. 递归

① 函数递归调用:

函数可以调用函数本身(不要用main()调用main(),不是不能这么做,而是不建议)

#include <stdio.h>

int main()
{
    printf("调用main\n");
    main();

    return 0;
}

运行结果:(死循环)

② 递归的优点:

递归给某些编程问题提供了最简单的方法。

③ 递归的缺点:

一个有缺陷的递归会很快耗尽计算机的资源,递归的程序难以理解和维护。

7. 普通函数调用

普通函数调用是指在一个程序中,我们直接调用一个已经定义好的函数,并传递必要的参数给该函数,以执行相应的功能。

示例代码:

#include <stdio.h> // 引入标准输入输出库,用于printf函数  
  
// 定义一个函数fun_b,接受一个整数参数b  
void fun_b(int b) {  
	printf("b = %d\n", b); // 打印出传入的整数参数b  
  
	return; // 函数返回,结束fun_b的执行  
}  
  
// 定义一个函数func_a,接受一个整数参数a  
void func_a(int a) {  
	fun_b(a - 1); // 调用fun_b函数,并传入参数a减1的值  
  
	printf("a = %d\n", a); // 打印出传入的整数参数a  
}  
  
// 主函数,程序的入口点  
int main(void) {  
	func_a(2); // 调用func_a函数,并传入整数2  
    printf("main\n"); // 打印出字符串"main"  
  
	return 0; // 主函数返回0,表示程序正常结束  
}

运行顺序:

先调用,后返回(栈结构)

调用谁,返回谁的位置。

  1. 程序从main函数开始执行。
  2. main函数调用func_a并传入整数2作为参数。
  3. func_a函数被调用,参数a的值为2
  4. func_a函数内部,首先调用fun_b函数,并将a - 1(即1)作为参数传入。
  5. fun_b函数被调用,参数b的值为1
  6. fun_b函数内部执行printf,打印出b = 1
  7. fun_b函数执行完毕并返回。
  8. func_a函数继续执行,执行printf,打印出a = 2
  9. func_a函数执行完毕并返回。
  10. main函数继续执行,执行printf,打印出main
  11. main函数执行完毕并返回0,程序结束。

运行结果:

8. 函数递归调用

函数递归调用是指一个函数在其定义中直接或间接地调用自身。递归调用在解决某些问题,特别是那些可以分解为更小、相同子问题的问题时,非常有用。递归有两个关键部分:递归基(基本情况)和递归步骤(递归调用)。递归基是递归的终止条件,当满足这个条件时,递归停止。递归步骤则是函数如何调用自身来逐步接近递归基。

示例代码:

#include <stdio.h>  
  
// 定义一个递归函数用于计算阶乘  
// 参数n为要求阶乘的整数  
// 返回值是n的阶乘结果  
int factorial(int n) {  
    // 递归基:当n为0或1时,其阶乘均为1  
    if (n == 0 || n == 1) {  
        return 1;  
    } else {  
        // 递归步骤:n的阶乘等于n乘以(n-1)的阶乘  
        return n * factorial(n - 1);  
    }  
}  
  
int main() {  
    int n; // 定义一个整数变量n,用于存储用户输入的数  
  
    // 提示用户输入一个整数  
    printf("请输入一个整数:");  
      
    // 从标准输入读取用户输入的整数并存储到变量n中  
    scanf("%d", &n);  
  
    // 调用递归函数factorial计算n的阶乘,并将结果存储在变量result中  
    int result = factorial(n);  
      
    // 输出n的阶乘结果  
    printf("%d 的阶乘是 %d\n", n, result);  
  
    // 程序正常结束,返回0  
    return 0;  
}

执行顺序:

  1. 程序开始执行:从main函数开始。

  2. 输入提示:执行printf("请输入一个整数:");,在屏幕上显示提示信息。

  3. 读取输入:执行scanf("%d", &n);,等待用户输入一个整数,并将其存储在变量n中。

  4. 调用递归函数:执行int result = factorial(n);,调用factorial函数来计算n的阶乘。

    • 递归开始
      • 检查n的值。如果n是0或1,递归基成立,函数返回1。
      • 如果n不是0或1,递归步骤执行,调用factorial(n - 1)
      • 这个过程会一直递归下去,每次调用factorialn的值减1,直到n变为0或1,递归基被触发,开始逐层返回结果。
  5. 返回递归结果:当递归调用结束,factorial函数返回计算得到的阶乘结果给result变量。

  6. 输出结果:执行printf("%d 的阶乘是 %d\n", n, result);,在屏幕上显示n的阶乘结果。

  7. 程序结束main函数执行完毕,返回0,程序正常结束。

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值