C语言--基础面试真题

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

  • 普通局部变量和静态局部变量区别

    • 存储位置:

      • 普通局部变量存储在栈上

      • 静态局部变量存储在静态存储区

    • 生命周期:

      • 当函数执行完毕时,普通局部变量会被销毁

      • 静态局部变量的生命周期则是整个程序运行期间,即使函数调用结束,静态局部变量的值也会被保留

    • 初始值:

      • 普通局部变量在每次函数调用时都会被初始化,它们的初始值是不确定的,除非显式地进行初始化

      • 静态局部变量在第一次函数调用时会被初始化,然后保持其值不变,直到程序结束

  • #include <stdio.h>
    ​
    void normal_func() {
        int i = 0;
        i++;
        printf("局部变量 i = %d\n", i);
    }
    ​
    void static_func() {
        static int j = 0;
        j++;
        printf("static局部变量 j = %d\n", j);
    }
    ​
    int main() {
        // 调用3次normal_func()
        normal_func();
        normal_func();
        normal_func();
    ​
        // 调用3次static_func()
        static_func();
        static_func();
        static_func();
    ​
        return 0;
    }
  • 运行结果:

  • 局部变量 i = 1
    局部变量 i = 1
    局部变量 i = 1
    static局部变量 j = 1
    static局部变量 j = 2
    static局部变量 j = 3

2、预处理

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

    • 预处理

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

    • 编译

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

    • 汇编

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

    • 链接

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

    gcc -E hello.c -o hello.i //处理文件包含,宏和注释 
    gcc -S hello.i -o hello.s //编译为汇编文件 
    gcc -c hello.s -o hello.o //经汇编后为二进制的机器指令
    gcc hello.o -o hello      //链接所用的到库
    ​
    1 预处理:预处理相当于根据预处理命令组装成新的 C 程序,不过常以 i 为扩展 名。 
    2 编 译:将得到的 i 文件翻译成汇编代码 .s 文件。 
    3 汇 编:将汇编文件翻译成机器指令,并打包成可重定位目标程序的 O 文件。 该文件是二进制文件,字节编码是机器指令。 
    4 链 接:将引用的其他 O 文件并入到我们程序所在的 o 文件中,处理得到最终 的可执行文件

  • C编译器提供的预处理功能主要包括:

    • 文件包含 #include

    • 宏定义 #define

    • 条件编译 #if #endif ……

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(),不是不能这么做,而是不建议,往往得不到你想要的结果)。

  • 递归的优点

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

  • 递归的缺点

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

 

7、普通函数调用

#include <stdio.h>
​
void fun_b(int b) {
    printf("b = %d\n", b);
​
    return;
}
​
void func_a(int a) {
    fun_b(a - 1);
​
    printf("a = %d\n", a);
}
​
int main(void) {
    func_a(2);
    printf("main\n");
​
    return 0;
}

运行顺序:

  • 结论:

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

    • 调用谁,返回谁的位置

运行结果:

b = 1
a = 2
main

8、函数递归调用

 

#include <stdio.h>
​
//0的阶乘是1  1的阶乘1    return 1
//n! =(n-1)!*n
//(n-1)! = (n-2)!*(n-1)
//n = 1
​
​
// 递归函数计算阶乘
int factorial(int n) {
    if (n == 0 || n == 1) {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}
​
int main() {
    int n;
    printf("请输入一个整数:");
    scanf("%d", &n);
​
    // 调用递归函数计算阶乘并输出结果
    int result = factorial(n);
    printf("%d 的阶乘是 %d\n", n, result);
​
    return 0;
}
​

运行顺序:

9、大小端验证

        所谓的大端模式,是指数据的低位(就是权值较小的后面那几位)保存在内存的高地址中,而数据的高位,保存在内存的低地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;
        所谓的小端模式,是指数据的低位保存在内存的低地址中,而数 据的高位保存在内存的高地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
​
1)大端模式:
​
低地址 -----------------> 高地址
​
0x12  |  0x34  |  0x56  |  0x78
​
2)小端模式:
​
低地址 ------------------> 高地址
​
0x78  |  0x56  |  0x34  |  0x12

#include <stdio.h>
#include <stdint.h>
​
int check_endianness() {
    uint32_t temp = 0x44332211; // 4个字节,32位
    uint8_t * p = NULL;  // 8位
​
    p = (uint8_t *)&temp;  // 只取uint8_t的长度
    printf("%#x\n", *p);
    printf("%#x\n", p[0]); // *p 和 p[0]等价
​
    uint16_t * p1 = (uint16_t *)&temp; 
    printf("*p1 = %#x\n", *p1);
​
    if (*p == 0x11 ) {
        return 0; // 0是小端
    } else {
        return 1; // 大端
    }
}
​
int main() {
    int res = check_endianness();
    if (res == 0) {
        printf("小端\n");
    } else {
        printf("大端\n");
    }
​
    return 0;
}

10、大小端转换

#include <stdio.h>
​
int changeBigEndian(int data) {
​
    return (data >> 24 & 0x000000ff) |
        (data >> 8 & 0x0000ff00) |
        (data << 8 & 0x00ff0000) |
        (data << 24 & 0xff000000);
}
​
int main() {
​
​
    int mem = 0x44332211;
​
    printf("%0x\n", changeBigEndian(mem));
    return 0;
}
​

11、二分查找

#include <stdio.h>
​
// 二分查找函数
int binarySearch(int arr[], int size, int target) {
    int left = 0;
    int right = size - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (arr[mid] == target) {
            return mid; // 找到目标元素,返回索引
        } else if (arr[mid] < target) {
            left = mid + 1; // 在右半部分继续查找
        } else {
            right = mid - 1; // 在左半部分继续查找
        }
    }
    return -1; // 目标元素不存在,返回-1
}
​
int main() {
    int arr[] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
    int size = sizeof(arr) / sizeof(arr[0]);
    int target = 11;
    int index = binarySearch(arr, size, target);
    if (index != -1) {
        printf("目标元素 %d 在数组中的索引为 %d\n", target, index);
    } else {
        printf("目标元素 %d 不在数组中\n", target);
    }
    return 0;
}
​

12、什么是指针,在什么地方使用的

 指针(Pointer)是一种特殊的变量类型,它用于存储内存地址。指针的实质就是内存“地址”。
使用范围:
动态内存分配:指针常用于动态分配内存,例如使用 malloc()、calloc() 或 new 分配内存,并使用指针来管理和访问分配的内存块。
​
数组和字符串:数组名本身就是指向数组第一个元素的指针,在函数参数传递、数组访问等场景中经常用到指针。
​
函数指针:函数指针是指向函数的指针变量,可以用来在运行时动态确定调用的函数,或者将函数作为参数传递给其他函数。
……

13、函数指针是什么

函数指针是指向函数的指针变量,它存储了函数的地址,可以用来调用该函数。在 C 语言中,函数名可以视为函数在内存中的地址,因此可以将函数名赋值给函数指针变量,从而实现通过函数指针来调用函数。

#include <stdio.h>
​
int getData(int a, int b) {
    return a + b;
}
​
int main() {
​
    int(*func)(int, int);
​
    func = getData;
    printf("%d\n", func(5, 8));
​
    return 0;
}
​

复议:指针函数

  • 指针函数是一个返回指针的函数。它的返回值是一个指针,指向某种数据类型的内存地址。

  • 指针函数通常用于动态内存分配、返回数组、返回字符串等场景。

int* create_array(int size) {
    int* arr = malloc(size * sizeof(int)); // 动态分配内存
    return arr;
}

14、声明和定义的区别

  • 声明告诉编译器,某个名称(如变量、函数、类等)存在,但不分配内存空间或提供实现细节。

  • 声明通常包括名称和类型信息,以及可能的参数列表。

  • 声明可以出现在函数或变量的定义之前,以便在使用之前提供有关名称的信息。

int add(int a, int b);
  • 定义不仅声明了名称的存在,还为其分配了内存空间或提供了实现细节。

  • 对于变量,定义会分配内存空间;对于函数,定义会提供函数体的实现。

  • 每个定义都是一个声明,但不是每个声明都是一个定义。

// 函数定义
int add(int a, int b) {
    return a + b;
}

15、extern关键字是干什么用

用来修饰全局变量,全局变量本身是全局可用的,但是由于文件是单个完成编译,并且编译是自上而下的,所以说,对于不是在本范围内定义的全局变量,要想使用必须用 extern 进行声明,如果不加上 extern ,就会造成重定义。

注意,经 extern 声明的变量,不可以再初始化。

16、位运算

#include <stdio.h>
#include <inttypes.h>
​
int main() {
    // 将变量a的第2位设置为1,其他位保持不变
    uint8_t a = 0b10110011; // 0xb3;
    a |= (1 << 2);          // 或者 x = x | (1 << 2);
    printf("%02x\n", a);    // b7,  10110111
​
    // 将变量b的第2位、第6位设置为1,其他位保持不变
    uint8_t b = 0b10110011; // 0xb3;
    b |= (1 << 2 | 1 << 6);
    printf("%02x\n", b);    // f7,11110111
​
    // 将变量c的第5位设置为0,其他位保持不变
    uint8_t c = 0b10110011;  // 0xb3;
    c &= ~(1 << 5);
    printf("%02x\n", c);    // 93,10010011
​
    // 将变量d的第0~3位设置为0,其他位保持不变
    uint8_t d = 0b11111111;  // 0xff;
    d &= ~(1 << 0 | 1 << 1 | 1 << 2 | 1 << 3);
    printf("%02x\n", d);    // f0,11110000
​
    // 将变量e的第2位取反,其他位保持不变
    uint8_t e = 0b10110011;  // 0xb3;
    e ^= (1 << 2);
    printf("%02x\n", e);    // b7,  10110111
​
    return 0;
}

17、说说什么是野指针,怎么产生的,如何避免

野指针是指向"垃圾"内存的指针,也就是说,它的值是不确定的。野指针通常由以下几种情况产生:
​
未初始化的指针:如果你声明了一个指针变量但没有给它赋值,那么它就是一个野指针。例如:int *ptr;。
已删除的指针:如果你使用delete或free删除了一个指针,但没有将它设置为NULL,那么它就成了一个野指针。例如:
超出作用域的指针:如果你返回了一个函数内部的局部变量的地址,那么这个地址在函数返回后就不再有效,因此返回的指针就是一个野指针。
​
​
初始化: ptr = NULL;
​

18、堆和栈有什么区别?

- 栈区(stack)
​
- - 栈是一种先进后出的内存结构,由编译器自动分配释放,存放函数的参数值、返回值、局部变量等。在程序运行过程中实时加载和释放,因此,局部变量的生存周期为申请到释放该段栈空间。
​
- 堆区(heap)
​
- - 堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。用于动态内存分配。堆在内存中位于BSS区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/576599.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员学CFA——数量分析方法(四)

数量分析方法&#xff08;四&#xff09; 常见概率分布基本概念离散型随机变量与连续型随机变量离散型随机变量连续型随机变量 分布函数概率密度函数&#xff08;PDF&#xff09;累积分布函数&#xff08;CDF&#xff09; 离散分布离散均匀分布伯努利分布二项分布定义股价二叉树…

Rabbitmq安装延迟插件rabbitmq_delayed_message_exchange失败

Docker里的Rabbitmq容器安装延迟插件rabbitmq_delayed_message_exchange失败 一启动插件Rabbitmq容器直接停止运行了 rabbitmq-plugins enable rabbitmq_delayed_message_exchange排除了版本问题和端口问题等&#xff0c;发现是虚拟机运行内存不够&#xff0c;增加虚拟机运行内…

python基础——正则表达式

&#x1f4dd;前言&#xff1a; 这篇文章主要想讲解一下python中的正则表达式&#xff1a; 1&#xff0c;什么是正则表达式 2&#xff0c;re模块三匹配 3&#xff0c;元字符匹配 4&#xff0c;具体示例 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&am…

Hybrid Homomorphic Encryption:SE + HE

参考文献&#xff1a; [NLV11] Naehrig M, Lauter K, Vaikuntanathan V. Can homomorphic encryption be practical?[C]//Proceedings of the 3rd ACM workshop on Cloud computing security workshop. 2011: 113-124.[MJS16] Maux P, Journault A, Standaert F X, et al. To…

【定制化体验:使用Spring Boot自动配置,打造个性化Starter】

项目结构 Pom <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4…

yml文件修改工具

导入一个 yml 配置文件 可以根据给定的 name 源文件内容 举例如下 - alterId: 0cipher: autoname: 链接1port: 11004server: dotu-hkv1.03ezhg0qsa.downloadskip-cert-verify: truetls: falsetype: tpyudp: trueuuid: ac1f3b35-1d03-3a85-beab-根据name 可以快速将源内容进行替…

系统启动之后创建的第一个窗口是什么?

com.android.settings TYPE_BASE_APPLICATION 1 &#xff1b; 启动时显示的窗口有&#xff1a; 系统窗口有: TYPE_STATUS_BAR TYPE_SEARCH_BAR TYPE_PHONE TYPE_SYSTEM_ALERT TYPE_KEYGUARD TYPE_TOAST TYPE_SYSTEM_OVERLAY TYPE_PRIORITY_PHONE TYPE_SYSTEM_DIALOG…

Synchronized关键字的深入分析

一、引言 在多线程编程中&#xff0c;正确地管理并发是确保程序正确运行的关键。Java提供了多种同步工具&#xff0c;其中synchronized关键字是最基本且最常用的同步机制之一。本文旨在深入解析synchronized的实现原理&#xff0c;探讨其在不同应用场景中的使用&#xff0c;并…

创新书荐|用《创新者的窘境》指导企业应对AI颠覆技术避免被颠覆

如何利用《创新者的窘境》应对AI的颠覆性技术时&#xff0c;了解并实施正确的战略对于确保企业在动荡的市场环境中保持增长和竞争力至关重要。我们分析了市场领导者和初创公司如何利用AI开辟新的增长路径&#xff0c;以及企业如何在技术革命中维持竞争优势。想要深入了解并实践…

CogVLM CogAgent模型部署

CogVLM & CogAgent 下载地址 CogVLM & CogAgent 的 Github 官方仓库&#xff1a;https://github.com/THUDM/CogVLM CogVLM & CogAge…

了解ASK模块STX883Pro和超外接收模块SRX883Pro的独特之处 STX883Pro模块具有以下特点:

高发射功率&#xff1a;STX883Pro具有较高的发射功率&#xff0c;可实现长距离的信号传输&#xff0c;适用于需要覆盖广泛区域的应用场景。 高频率稳定性&#xff1a;具备稳定的频率输出&#xff0c;确保信号传输的可靠性和一致性&#xff0c;避免频率漂移导致的通信故障。 大…

异常检测 | SVDD支持向量数据描述异常数据检测(Matlab)

异常检测 | SVDD支持向量数据描述异常数据检测&#xff08;Matlab&#xff09; 目录 异常检测 | SVDD支持向量数据描述异常数据检测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 用于一类或二元分类的 SVDD 模型 多种核函数&#xff08;…

基于模糊控制的电动汽车锂电池SOC主动均衡电路MATLAB仿真模型

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型简介 模型在 Matlab/Simulink仿真平台中搭建16节电芯锂电池电路模型&#xff0c;主要针对电动车锂电池组SOC差异性&#xff0c;采用模糊控制算法动态调节均衡电流&#xff0c;以减少均衡时间和能量损耗。…

换脸插件升级导致SDWebUI无法启动cannot import name ‘Undefined‘ from ‘pydantic.fields‘

今天在一台新的机器环境装了SDWEBUI&#xff0c;都使用最新的版本&#xff0c;升级了下换脸的插件&#xff0c;于是乎启动崩溃了。错误如下 Launching Web UI with arguments: --listen --skip-torch-cuda-test --disable-nan-check --skip-version-check --skip-python-versi…

SQL嵌套查询和集合查询

嵌套查询 先导概念 查询块&#xff1a;一个select语句为一个查询块 嵌套查询&#xff1a;将一个查询块嵌套在一个另一个查询块中where子句中的查询叫做嵌套查询。 嵌套查询的种类&#xff1a; 不相关子查询&#xff1a;子查询里的条件不依赖于父查询&#xff0c;从里到外依…

android布局

LinerLayout 权重分配的是剩余空间 RelativeLayout

Python脚本实现PC端大麦网自动购票(Selenium自动化测试工具)

文章目录 Selenium 简介Selenium webdriver 文档chromedriver&#xff08;谷歌浏览器驱动&#xff09;chromedriver 下载配置环境变量 大麦网购票脚本网页 dom 元素 启用远程调试&#xff08;操作已打开的窗口&#xff09; Selenium 简介 Selenium 是一个用于自动化测试的工具…

目标检测与追踪AI算法模型及边缘计算智能分析网关V4的算法应用

目标检测与追踪是计算机视觉领域中的一个重要任务&#xff0c;主要用于识别图像或视频中的目标&#xff0c;并跟踪它们的运动轨迹。针对这一任务&#xff0c;有许多先进的AI算法模型&#xff0c;例如&#xff1a; YOLO&#xff08;You Only Look Once&#xff09;&#xff1a;…

linux 设备树-of_address_to_resource

实例分析-reg 属性解析(基于ranges属性) /{#address-cells <0x01>;#size-cells <0x01>;soc {compatible "simple-bus";#address-cells <0x01>;#size-cells <0x01>;ranges <0x7e000000 0x3f000000 0x1000000 0x40000000 0x40000000…

怎么把图片转换为二维码?3个步骤轻松制作图片二维码

图片的二维码是怎么做成的呢&#xff1f;现在很多场景下的二维码&#xff0c;用手机扫码可以展现出对应的图片信息。通过这种方式来传递图片对于用户体验与很好的效果&#xff0c;而且也方便制作者通过这种方式来快速完成图片信息的传递&#xff0c;与传统方式相比成本更低&…
最新文章