C语言面试题汇总(持续更)「建议收藏」

C语言面试题汇总(持续更)「建议收藏」笔者最近在找工作,因此对应聘C/C++嵌入式开发工程师容易被问到,或者经常搞不清楚的问题做一个汇总,也希望能对找工作的小伙伴起到帮助参考的作用。本篇集中于C语言方面的面试题目。因为是自己总结的,可能会存在错误,还烦请各位读者批评指正。一、变量内存分配1.一个由C/C++编译的程序占用的内存分为以下几个部分:①栈区——局部变量——向低地址生长——自动释放——其操作方式类似于数据结构中的栈。②堆区——向高地址生长——手动分配、释放的存储区——malloc,fr..

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

笔者最近在找工作,因此对应聘C/C++嵌入式开发工程师容易被问到,或者经常搞不清楚的问题做一个汇总,也希望能对找工作的小伙伴起到帮助参考的作用。本篇集中于C语言方面的面试题目。

因为是自己总结的,可能会存在错误,还烦请各位读者批评指正。


一、变量内存分配

1. 一个由C/C++编译的程序占用的内存分为以下几个部分:

①栈区 —— 局部变量 —— 向低地址生长 —— 自动释放 —— 其操作方式类似于数据结构中的栈。

②堆区 —— 向高地址生长 —— 手动分配、释放的存储区 —— malloc,free —— 它与数据结构中的堆是两回事,分配方式倒是类似于链表

③全局/静态存储区static —— 全局变量,静态变量,程序运行结束后自动释放

④常量存储区const —— 常量字符串储存在这里。储存在常量区的只读不可写。程序运行结束后自动释放

⑤代码区 —— 存放函数体的二进制代码。

 

  • 静态内存分配:编译时分配,包括:全局、静态全局、静态局部
  • 动态内存分配:运行时分配:包括:栈(局部变量),堆(C语言常用到的变量被动态地分配到内存当中:malloc,calloc,realloc,free函数)

——> const修饰的全局变量也储存在常量区

——> const修饰的局部变量依然在上。

int a = 0; //全局初始化区 
char *p1; //全局未初始化区 
main() 
{ 
int b; //栈 
char s[] = "abc"; //栈 
char *p2; //栈 
char *p3 = "123456"; //123456\0在常量区,p3在栈上。 
static int c =0; //全局(静态)初始化区 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。 
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 
}

 

2. 存储类(内存管理):

①栈:局部变量,函数调用传参的过程。
②堆:动态存储区,需要程序员去申请释放
③数据段(data段):显式初始化仅非零的全局变量

 

3.static修饰的变量

(1)static修饰局部变量(静态局部变量)与普通局部变量相比:
① 静态局部变量作用域与连接属性,和普通局部变量一样
② 存储类:静态局部变量分配在data/bss段普通局部变量在栈上
③ 生命周期:因为存储类的不同,静态局部变量生命周期变长了,直到程序结束

——所以当静态局部变量离开作用域后,并没有销毁,而是仍然驻留在内存当中,只不过我们不能够再对它进行访问,直到该函数被再次调用,并且值不变。

(2)static修饰的全局变量or函数与普通的相比:
① 存储类、生命周期、作用域都一样
② 差别在于:
static修饰的全局变量的连接属性是内连接,普通的是外连接
即:static修饰的全局变量不能给文件调用——这也是静态变量和全局变量的区别。

 

对于局部变量来说,声明存储类型的作用是指定变量存储的区域(静态存储区或动态存储区)以及由此产生的生存期的问题

对于全局变量来说,由于都是在编译时分配内存,都存放在静态存储区,声明存储类型的作用是变量作用域的扩展问题。

 

 

 

4. 其他

1. 变量类型:是对数据分配存储单元的安排,包括存储单元的长度,及数据的存储形式

 

2. 内部函数:只能被本文件中的其他函数调用。定义内部函数时,在函数名、函数类型前加static。

外部函数:可供其他文件调用。定义外部函数时,在函数首部左端加上extern。若定义函数时省略extern,则默认为外部函数。

 

3. 因为A、B、C是外部变量

所以调用max函数时用不到参数传递,即在max函数中可以直接使用外部变量A、B、C的值

(这一点与局部变量有个实参传给形参的过程不同)

 

二、堆和栈有什么区别?(为什么又是这个)

1、堆栈空间分配区别

栈(操作系统):由操作系统(编译器)自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

2、堆栈缓存方式区别

栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放。

堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。

3、堆栈数据结构区别

堆(数据结构):堆可以被看成是一棵树,如:堆排序。

栈(数据结构):一种先进后出的数据结构。

 

三、数据结构集中问题

1. 串值的存储空间可在程序执行过程中动态分配而得。

2. 根结点是没有双亲的,所以我们约定根结点的位置域为-1.

3. 链表翻转(迭代法)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* reverseList(struct ListNode* head){
    if (head == NULL || head->next == NULL)
        return head;
    
    struct ListNode *pre = head;
    struct ListNode *cur = head->next;
    struct ListNode *tmp = head->next->next;
    
    while(cur)
    {
        tmp = cur->next; //当前位置的下一个的值给tmp先存着
        cur->next = pre; //把上一个位置的值给下一个
        pre = cur;//把当前位置的值给上一个
        cur = tmp;//把之前下一个的值给当前位置
    }
    head->next = NULL;
    
    return pre;

}

 

四、指针

 

1. *在不同的场景下有不同的作用

*可以用在指针变量的定义中,表明这是一个指针变量,以和普通变量区分开;

*也可以在使用指针变量时,在变量前面加上,表示获取指针指向的数据,或者说表示的是指针指向的数据本身。

也就是说,定义指针变量时的*使用指针变量时的*意义完全不同。以下面的语句为

  1. int *p = &a;
    *p = 100;

     

第1行代码中*用来指明 p 是一个指针变量,第2行代码中*用来获取指针指向的数据。

需要注意的是,给指针变量本身赋值时不能加*。修改上面的语句:

int *p;
p = &a;
*p = 100;

第2行代码中的 p 前面就不能加*

指针变量也可以出现在普通变量能出现的任何表达式中,例如:

int x, y, *px = &x, *py = &y;
y = *px + 5;  //表示把x的内容加5并赋给y,*px+5相当于(*px)+5
y = ++*px;  //px的内容加上1之后赋给y,++*px相当于++(*px)
y = *px++;  //相当于y=(*px)++
py = px;  //把一个指针的值赋给另一个指针

 

2. 如果已执行“p=&a;”,即指针变量p指向了整型变量a,则:

printf("%d",*p);

其作用是:以整数形式输出指针变量p所指向的变量的值,即变量a的值。

 

3. 当数组作为函数的参数传递时,数组就自动退化为同类型指针。

 

 

五、杂项

1. const和define的区别

1.数据类型:const修饰的变量有明确的类型,而宏没有明确的数据类型

2.安全方面:const修饰的变量会被编译器检查,而宏没有安全检查

3.内存分配:const修饰的变量只会在第一次赋值时分配内存,而宏是直接替换,每次替换后的变量都会分配内存

4.作用场所:const修饰的变量作用在编译、运行的过程中,而宏作用在预编译中

5.代码调试:const方便调试,而宏在预编译中进行所以没有办法进行调试。

—— const关键字的作用:

1. const 是定义只读变量的关键字,或者说 const 是定义常变量的关键字。
说 const 定义的是变量,但又相当于常量;说它定义的是常量,但又有变量的属性,所以叫常变量。用 const 定义常变量的方法很简单,就在通常定义变量时前面加 const 即可,如:

const  int  a = 10;

const 和变量类型 int 可以互换位置,二者是等价的,即上条语句等价于:

int  const  a = 10;

那么用 const 修饰后和未修饰前有什么区别呢?它们不都等于 10 吗?、

  • 用 const 定义的变量的值是不允许改变的,即不允许给它重新赋值,即使是赋相同的值也不可以。所以说它定义的是只读变量。这也就意味着必须在定义的时候就给它赋出值。
  • 如果定义的时候未初始化,我们知道,对于未初始化的局部变量,程序在执行的时候会自动把一个很小的负数存放进去。这样后面再给它赋出值的话就是“改变它的值”了,即发生语法错误。

 

2. 

const int * p1 = &i; //p1指向的值不能改变

int * const p2 =&j; //p2本身的值(即指向的值的地址)不能改变

上面定义了两个指针p1和p2。

在定义1中const限定的是*p1,即其指向空间的值不可改变,若改变其指向空间的值如*p1=20,则程序会报错;但p1的值是可以改变的,对p1重新赋值如p1=&k是没有任何问题的。

在定义2中const限定的是指针p2,若改变p2的值如p2=&k,程序将会报错;但*p2,即其所指向的值可以改变,如*p2=80是没有问题的,程序正常执行。

 

const常量会在内存中分配??

 

2. ifndef – endif 的作用:避免重定义

 

3. 参数传递:

三种参数传递的方式:传值、传指针、传引用

形参的存储空间是函数被调用时才分配的

  • 引用是别名,指针是地址(实体)

引用一旦与某个对象绑定后就不再改变了

string str1 = "a";
string str3 = "b";
string &str2 = str1; //str2指向str1的地址
str2 = str3;

 

4.    malloc和calloc

 malloc:分配n个字节    calloc:分配n*size个字节

5. 进程和线程的区别?

进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。

线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。

一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务。

 

6. #include <> 和 #include” “

老生常谈的问题。

#include <> :到保存系统标准头文件的位置查找头文件。

#include” “:查找当前目录是否有指定名称的头文件,然后再从标准头文件目录中查找。

 

7.递归

每个递归必须至少有一个条件,其满足时递归便不再运行,即:此时不再引用自身,而是返回值退出。

for (i=2;i<40;i++)
     a[i]=a[i-1]+a[i-2];

int Fbi(int i){
    return Fbi(i-1)+Fbi(i-2);
}

 

8. 输入逗号

使用 scanf(“%d%d%d”,&a,&b,&c); 从键盘中获得任意 3 个数。在输入数据时,在两个数据之间以一个或多个空格间隔,也可以用 Enter 健、Tab 键,不能用逗号作为两个数据间的分隔符。 

如果用格式输入函数 scanf(“%d,%d,%d”,&a,&b,&c) 输入数据,两个数据之间要用“,”做间隔。

 

9. 各种数据类型的长度

1. signed char取值范围bai是 -128 到 127         ——一个字节,2的8次方
unsigned char 取值范围是 0 到 255         

2. 一个int占4个字节,sizeof就是4。在32位系统上,对任意指针求sizeof得到的结果都是4.??

 

 

 

10. 输出

 

printf("x1=%7.2f\nx2=%7.2f\n",x1,x2);

x1=%7.2f

7.2是指:宽度占7个,精确到小数点后两位(输出数据占7列,其中小数占2列)

x1=  -1.00
x2=  -2.00

 

NULL==ptr

free()

FreeRTOS任务调度方式

二分 哈希

 

pa、pb、pc 每次加 1,它们的地址分别增加 4、8、1,正好是 int、double、char 类型的长度;减 2 时,地址分别减少 8、16、2,正好是 int、double、char 类型长度的 2 倍。
 

 

 

887

1.左边界:只需要考虑相邻右元素是否存在坑

2.右边界:只需要考虑相邻左元素是否存在坑

3.中间:考虑相邻两边元素是否存在坑

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/174837.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • vue与jquery的区别_vue 3

    vue与jquery的区别_vue 31.jquery介绍:想必大家都用过jquery吧,这个曾经也是现在依然最流行的web前端js库,可是现在无论是国内还是国外他的使用率正在渐渐被其他的js库所代替,随着浏览器厂商对HTML5规范统一遵循以及ECMA6在浏览器端的实现,jquery的使用率将会越来越低2.vue介绍:vue是一个兴起的前端js库,是一个精简的MVVM。从技术角度讲,Vue.js专注于MVVM模型的ViewM…

    2022年10月16日
  • DAC904硬件电路「建议收藏」

    DAC904硬件电路「建议收藏」DAC904一、DAC904特性二、电路原理图一、DAC904特性●单电源供电+5V或+3V●高SFDR(无杂散动态范围):在100MSPS64dBc时20MHz输出●低干扰:3PV-S●低功耗:170MW(+5V时)DAC904是一款高速数模转换器,14位分辨率,引脚兼容DAC908、DAC900、DAC902,分别提供8-,10-,12-位分辨率选择。该系列DAC…

  • mysql 自动当前时间_Mysql 自动获取当前时间[通俗易懂]

    mysql 自动当前时间_Mysql 自动获取当前时间[通俗易懂]实现方式:1、将字段类型设为TIMESTAMP2、将默认值设为CURRENT_TIMESTAMP举例应用:1、MySQL脚本实现用例–添加CreateTime设置默认时间CURRENT_TIMESTAMPALTERTABLE`table_name`ADDCOLUMN`CreateTime`datetimeNULLDEFAULTCURRENT_TIMESTAMPC…

  • Java 多线程(超详细)

    Java 多线程(超详细)多线程学习思路:为什么学习线程?为了解决CPU利用率问题,提高CPU利用率。=》什么是进程?什么是线程?=》怎么创建线程?有哪几种方式?有什么特点?=》分别怎么启动线程?=》多线程带来了数据安全问题,该怎么解决?=》怎么使用synchronized(同步)决解?=》使用同步可能会产生死锁,该怎么决解?=》线程之间是如何通信的?=》线程有返回值吗?该如何拿到?=》怎么才能一次性启动几百上千个的线程?线程的概念什么是进程进程是操作系统中正在执行的不同的应用程序,例如:我

  • 二级菜单导航栏(左侧)「建议收藏」

    二级菜单导航栏(左侧)「建议收藏」目标:实现左侧的二级导航栏效果图:项目演示:点击跳转到演示地址代码:<!DOCTYPEhtml><html> <head> <metacharset=”utf-8″> <title>左侧导航栏</title> </head> <style> body{ margin:0; padding:0; min-width:1200px; min-he

  • mysql数据库旅游管理系统_JSP+MySQL基于ssm的旅游管理系统[通俗易懂]

    mysql数据库旅游管理系统_JSP+MySQL基于ssm的旅游管理系统[通俗易懂]本旅游管理系统主要包括系统用户管理模块、景点信息管理模块、变幻图管理、旅游线路管理、登录模块、和退出模块等多个模块。它帮助旅游管理实现了信息化、网络化,通过测试,实现了系统设计目标,相比传统的管理模式,本系统合理的利用了旅游管理数据资源,有效的减少了旅游管理的经济投入,大大提高了旅游管理的效率。SSM旅游网站前台部分界面SSM旅游网站后台部分界面系统功能结构图本系统主要包含了等系统用户管理、景点信…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号