C语言--基础面试真题

news/2024/5/20 7:58:29

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 Aprintf("这是大写操作\n");
#elseprintf("这是小写操作\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.mrgr.cn/p/42088084

相关文章

学习Rust第14天:HashMaps

今天我们来看看Rust中的hashmaps&#xff0c;在 std::collections crate中可用&#xff0c;是存储键值对的有效数据结构。本文介绍了创建、插入、访问、更新和迭代散列表等基本操作。通过一个计算单词出现次数的实际例子&#xff0c;我们展示了它们在现实世界中的实用性。Hashm…

基于harris角点和RANSAC算法的图像拼接matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ....................................................................... I1_harris fu…

对EKS(AWS云k8s)启用AMP(AWS云Prometheus)监控+AMG(AWS云 grafana)

问题 需要在针对已有的EKS k8s集群启用Prometheus指标监控。而且&#xff0c;这里使用AMP即AWS云的Prometheus托管服务。好像这个服务&#xff0c;只有AWS国际云才有&#xff0c;AWS中国云没得这个托管服务。下面&#xff0c;我们就来尝试在已有的EKS集群上面启用AMP监控。 步…

IP地址定位:揭秘精准定位的技术与应用

在数字化时代&#xff0c;IP地址已成为连接互联网世界的关键标识之一。但是&#xff0c;很多人对于IP地址的精准定位能力存在疑虑。本文将深入探讨IP地址定位的技术原理以及其在实际应用中的精确度。 IP地址查询&#xff1a;IP数据云 - 免费IP地址查询 - 全球IP地址定位平台 …

运行游戏提示dll文件丢失,分享多种有效的解决方法

在我们日常频繁地利用电脑进行娱乐活动&#xff0c;特别是畅玩各类精彩纷呈的电子游戏时&#xff0c;常常会遭遇一个令人困扰的问题。当我们满怀期待地双击图标启动心仪的游戏程序&#xff0c;准备全身心投入虚拟世界时&#xff0c;屏幕上却赫然弹出一条醒目的错误提示信息&…

xgp加速器免费 微软商店xgp用什么加速器

2001年11月14日深夜&#xff0c;比尔盖茨亲自来到时代广场&#xff0c;在午夜时分将第一台Xbox交给了来自新泽西的20岁年轻人爱德华格拉克曼&#xff0c;后者在回忆中说&#xff1a;“比尔盖茨就是上帝。”性能超越顶级PC的Xbox让他们趋之若鹜。2000年3月10日&#xff0c;微软宣…

链游:未来游戏发展的新风向

链游&#xff0c;即区块链游戏的一种&#xff0c;是一种将区块链技术与游戏玩法相结合的创新型游戏。它利用区块链技术的特性&#xff0c;如去中心化、可追溯性和安全性&#xff0c;为玩家提供了一种全新的游戏体验。链游通常采用智能合约来实现游戏的规则和交易系统&#xff0…

Oracle delete删除数据是否为逻辑删除、新插入数据占用的数据块位置实验

假设一&#xff1a;数据库delete删除为直接删除 假设二&#xff1a;数据库delete删除为逻辑删除&#xff0c;在数据块标记出来&#xff0c;但是实际并没有删除。 方式一&#xff1a;通过dump数据块的方式来实现 我们先用小数据量&#xff0c;通过dump数据块的方式来实现 -- 数…

图搜索算法详解:广度优先搜索与深度优先搜索的探索之旅

图搜索算法详解&#xff1a;广度优先搜索与深度优先搜索的探索之旅 1. 广度优先搜索&#xff08;BFS&#xff09;1.1 伪代码1.2 C语言实现 2. 深度优先搜索&#xff08;DFS&#xff09;2.1 伪代码2.2 C语言实现 3. 总结 图搜索算法是计算机科学中用于在图结构中查找路径的算法。…

Python打怪升级(4)

在计算机领域常常有说"合法"和"非法"指的是:是否合理&#xff0c;是否有效&#xff0c;并不是指触犯了法律。 random.randint(begin,end) 详细讲解一下这个random是指模板&#xff0c;也就是别人写好的代码直接来用&#xff0c;在Python当中&#xff0c;…

接口测试和Mock学习路线(上)

一、接口测试和Mock学习路线-第一阶段&#xff1a; 掌握接口测试的知识体系与学习路线掌握面试常见知识点之 HTTP 协议掌握常用接口测试工具 Postman掌握常用抓包工具 Charles 与 Fiddler结合知名产品实现 mock 测试与接口测试实战练习 1.接口协议&#xff1a; 需要先了解 O…

探秘MySQL主从复制的多种实现方式

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 探秘MySQL主从复制的多种实现方式 前言基于语句的复制原理实现方法应用场景及优缺点应用场景优点缺点 基于行的复制原理实现方法优势和适用性优势适用性 基于混合模式的复制混合模式复制的工作原理混合…

数值分析复习:Richardson外推和Romberg算法

文章目录 Richardson外推Romberg&#xff08;龙贝格&#xff09;算法 本篇文章适合个人复习翻阅&#xff0c;不建议新手入门使用 本专栏&#xff1a;数值分析复习 的前置知识主要有&#xff1a;数学分析、高等代数、泛函分析 本节继续考虑数值积分问题 Richardson外推 命题&a…

WindowsPE重装Windows系统详细介绍

本文详细介绍了WindowsPE、UEFI BIOS、如何制作WindowsPE、网络唤醒WOL、如何格式化硬盘及分区 、GHost还原数据、驱动程序分类相关知识目录目录理论知识 什么是WindowsPE? 什么是UEFI BIOS?(简)实操 如何制作WindowsPE? 如何进入BIOS? 常用项介绍 设置U盘启动 网络…

02_c/c++开源库ZeroMQ

1.安装 C库 libzmq sudo apt install libzmq3-dev 实例: https://zeromq.org/get-started/?languagec&librarylibzmq# 编译依赖: pkg-config --cflags --libs libzmq or cat /usr/lib/x86_64-linux-gnu/pkgconfig/libzmq.pc -isystem /usr/include/mit-krb5 -I/usr/in…

dwc3控制器是怎么处理otg

概念 在OTG中&#xff0c;初始主机设备称为A设备&#xff0c;外设称为B设备。可用电缆的连接方式来决定初始角色。两用设备使用新型Mini-AB插座&#xff0c;从而使Mini-A插头、Mini-B插头和Mini-AB插座增添了第5个引脚&#xff08;ID&#xff09;&#xff0c;以用于识别不同的…

存储器数据恢复相关知识

讲述硬盘基本结构及其储存理论,介绍如何恢复常用存储器数据。目录目录理论知识 硬盘如何储存数据? 磁道和扇区简介 盘面号 磁道 柱面 扇区 硬盘如何读写数据? 数据删除原理 数据如何丢失的? 人为原因造成的数据丢失: 自然灾害造成的数据丢失: 软件原因造成…

ARM学习(26)链接库的依赖查看

笔者今天来聊一下查看链接库的依赖。 通常情况下&#xff0c;运行一个可执行文件的时候&#xff0c;可能会出现找不到依赖库的情况&#xff0c;比如图下这种情况&#xff0c;可以看到是缺少了license.dll或者libtest.so&#xff0c;所以无法运行。怎么知道它到底缺少什么dll呢&…

构建RAG应用-day05: 如何评估 LLM 应用 评估并优化生成部分 评估并优化检索部分

评估 LLM 应用 1.一般评估思路 首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效。 随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 Prompt 或者算法解决。 最终,你会将足够多的这些例子添加到你逐步扩大的开发集中…

android脱壳第二发:grpc-dumpdex加修复

上一篇我写的dex脱壳&#xff0c;写到银行类型的app的dex修复问题&#xff0c;因为dex中被抽取出来的函数的code_item_off 的偏移所在的内存&#xff0c;不在dex文件范围内&#xff0c;所以需要进行一定的修复&#xff0c;然后就停止了。本来不打算接着搞得&#xff0c;但是写了…