既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
4、C语言关键字static得作用是什么?
①隐藏作用, 可以在不同的文件中定义同名变量和同名函数。
②对于变量来说, 保持变量持久, 静态数据区的变量会在程序刚刚运行时就完成
初始化, 也是唯一一次初始化; 储存在静态数据区, 静态存储区只有两种变量(全
局变量和 static 静态变量) 。
③默认初始化为 0x00,和全局变量一样的属性, 减少程序员的工作量。
5、分别说明一下三个变量声明得含义:
int const \*p;
int \* const p;
int const \*p const;
int const*p=const int *p; const修饰的是指针 p,表示指针p的值不能改变,而p(即地址)是可以改变的;
int * const p; const修饰的是p(即地址)是常量,不可改变,但是*p的值可以改变。
int const *p const ; 上面两种情况兼得,表示只读,其地址以及地址中的值都不可改变
6、简述TCP/IP镞包含哪些分段,每一层有哪些常用协议?
应用层:http dns telnet ftp TFTP 。。。。
传输层:tcp udp
网络层:ip ICMP ARP rarp
数据链路层:ethnet ethnet2 802.3 ppp fr x.25 hdlc
物理层:比特流
7、从在浏览器地址栏中输入www.baidu.com到看到百度首页,这个过程中间经历了什么?都涉及到哪些网络协议?
按照时间顺序:
1.客户端浏览器获取用户在地址栏输入的域名。
2.客户端浏览器将域名发送给DNS域名系统,请求解析。
3.DNS解析域名得到相应的IP,返回给客户端浏览器。
4.客户端浏览器根据IP向服务器发起TCP三次握手,建立TCP连接。
5.客户端浏览器向服务器发送HTTP请求,请求百度首页。
6.服务器通过HTTP响应向客户端浏览器返回百度首页文件。
7.释放TCP连接。
8.客户端浏览器解析HTML文件,根据文件内容获取CSS、JS等资源文件,将页面渲染展示给用户。
TCP/IP五层模型中网络层及以上用到的协议:
1.应用层:HTTP、DNS、HTTPS
2.传输层:TCP、UDP
3.网络层:IP、ARP
8、编写strcat函数
2.strcat函数原型
char \*my\_strcat(char \*dest,const char \*src) //将源字符串加const,表明其为输入参数
{
char \*strDest=dest;
assert(dest!=NULL && src!=NULL); //对源地址和目的地址加非0断言
//若使用while(\*Dest++),则会出错,指向'\0'之后,会出现dest++,则指向了个'\0'的下一个位置,
while(\*dest !='\0')
{
dest++; //循环体内的++可以使指向字符串结束标志'\0'
}
while((\*dest++=\*src++)!='\0');
return strDest;
}
之后会问为什么要char *的返回值:
主要是为了实现链式表达式。
如 strcpy(buf, strcat(dest, src) );
9、使用C语言中的#define来定义一个常量来表示一年有多少秒?
#define SECONDS_PER_YEAR (606024*365)UL
一定要加括号,宏定义只是替换,不加括号会出错。。。。
10、实现把字符串转化成整数
int my\_atoi(char \*str)
{
int sum=0,status=1;
if(str == NULL)
{
return 0;
}
if(\*str == '-')
{
status = -1;
str++;
}
while((\*str)!='\0')
{
sum=sum\*10+ ((\*str)-'0');
str++;
}
return sum\*status;
}
11、写一个程序验证系统的大小端存储格式
/\*方法1\*/
typedef union {
int i;
char c;
}my_union;
int checkSystem1(void)
{
my_union u;
u.i = 1;
return (u.i == u.c);
}
/\*方法2\*/
int checkSystem2(void)
{
int i = 0x12345678;
char \*c = &i;
return ((c[0] == 0x78) && (c[1] == 0x56) && (c[2] == 0x34) && (c[3] == 0x12));
}
12、如何判断一个byte数据中有多少bit为1?
int select(unsigned char data)
{
int count=0,i=1;
while(data!=0)
{
count += (data & i);
data >>= 1;
}
return count;
}
13、 C语言中关键字volatile的含义
volatile 的意思是“易失的,易改变的”。这个限定词的含义是向编译器指明变量的内容可能会由于其他程序的修改而变化。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份
一般说来,volatile用在如下的几个地方:
1、中断服务程序中修改的供其它程序检测的变量需要加volatile;
2、多任务环境下各任务间共享的标志应该加volatile;
3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;
一个参数既可以是const还可以是volatile吗?解释为什么。
是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
14、进程间通信的方式有哪些?
1.无名管道( pipe ): 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2.有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
3.消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
4.信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
5.信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
6.共享内存( shared memory ) : 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
7.套接字( socket ) : 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
15、堆和栈的区别
①、申请方式不同:栈由系统自动分配,堆是由人为自行开辟(malloc,new)
② 、申请的大小不同:栈是从高地址像低地址分配的,分配空间较小,堆是由地址向高地分配的,空间较大
③ 、申请效率不同:栈由系统分配,分配速度较快,堆一般较慢
④ 、栈是连续的地址空间,堆不是连续的地址空间,很容易产生内存碎片,浪费内存。
16、分别给出bool,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)
Bool: if(!var)
Int : if(var==0)
Float: const float val=0.00000001
If((var >= -val) && (var <= val))
17、 进程和线程的区别
进程和线程的根本区别是进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。另外区别还有资源开销、包含关系、内存分配、影响关系、执行过程等。
- 资源开销:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。
- 包含关系:如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
- 内存分配:同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的。
- 影响关系:一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
- 执行过程:每个独立的进程有程序运行的入口、顺序执行序列和程序出口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行。
进程和线程的根本区别是进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
18.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
#define MIN(A, B) ((A) <= (B)? (A) : (B))
这个测试是为下面的目的而设的:
(1)标识#define在宏中应用的基本知识。这是很重要的,因为直到嵌入(inline)操作符 变为标准C的一部分,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为 了能达到要求的性能,嵌入代码经常是必须的方法。
(2)三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if -then-else更优化的代码,了解这个用法是很重要的。
(3)懂得在宏中小心地把参数用括号括起来。
(4)我也用这个问题开始讨论宏的副作用,例如:当你写下面的代码时会发生什么事?
least = MIN(*p++, b);
宏定义#define MIN(A, B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:
((*p++) <= (b) ? (*p++) : (b))这个表达式会产生副作用,指针p会作两次++自增操作。
19.预处理器标识#error的目的是什么?
这问题对区分一个正常的伙计和一个书呆子是很有用的。只有书呆子才会读C语言课本的附录去找出象这种问题的答案。当然如果你不是在找一个书呆子,那么应试者最好希望自己不要知道答案。
编译程序时,只要遇到 #error 就会跳出一个编译错误当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:
#ifdef XXX
#error “XXX has been defined”
#else
…
#endif
这样,如果编译时出现错误,输出了XXX has been defined,表明宏XXX已经被定义了。
20. 嵌入式系统中经常要用到无限循环,你怎么样用C编写死循环呢?
这个问题用几个解决方案。我首选的方案是:
while(1)
{
}
一些程序员更喜欢如下方案:
for(;;)
{
}
这个实现方式让我为难,因为这个语法没有确切表达到底怎么回事。如果一个应试者给出这个作为方案,我将用这个作为一个机会去探究他们这样做的基本原理。如果他们的基本答案是:“我被教着这样做,但从没有想到过为什么。”这会给我留下一个坏印象。
第三个方案是用 goto
Loop:
![img](https://img-blog.csdnimg.cn/img_convert/24da65a761fa881a715546954f23eb58.png)
![img](https://img-blog.csdnimg.cn/img_convert/430f47230b6d0404ad9abf4396c9db53.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
第三个方案是用 goto
Loop:
[外链图片转存中…(img-4HTPaBuG-1715717179955)]
[外链图片转存中…(img-nQ7eqd17-1715717179956)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新