1.预处理命令#define
#define SECONDS_PER_YEAR (60*60*24*365)UL
(因为数值超过65535,产生溢出,因此需要用到长整型,而且不会是负数,所以使用无符号整型UL)
2.死循环的方案(3种)
a:while(1){循环体}
b:for(;;){循环体}
c:Loop:循环体 goto Loop
3.变量定义
a:一个整型
b:一个指向整型的指针
c:一个指向指针的指针
d:一个指向10个整型数的数组
e:一个指向有10个整型指针的数组
f:一个指向有10个整型数数组的指针
g:一个指向函数的指针,该函数有一个整型参数并返回一个整型数
h:一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
答案:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 a) int a; 2 b) int *a; 3 c) int **a; 4 d) int a[10]; 5 e) int *a[10]; 6 f) int (*a)[10]; 7 g) int (*a)(int); 8 h) int (*a[10])(int);
4.关键字static的三个明显作用
a:在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
b:在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
c:在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
5.关键字const的含义:意味着该变量是一个“只读”变量,别说是常数
a:Const int a; a是一个常整型数
b:int const a; a是一个常整型数
c:const int *a; a是一个指向常整型数的指针(整型数是不可修改的,但指针可以)
d:int * const a; a是一个指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的)
e:int const * a const; a是一个指向常整型数的常指针(指针指向的整型数是不可修改的,同时指针也是不可修改的)
6.关键字volatile
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
一个参数既可以是const还可以是volatile,一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它
7.对变量或者对寄存器进行位操作:
写两段代码:第一段代码进行置位操作:(寄存器)的bit3,第二段代码进行清位操作:(寄存器)的bit3
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #define BIT3 (0x1<<3) 2 static int a; 3 void set_bit3(void) 4 { 5 a |= BIT3; 6 } 7 void clear_bit3(void) 8 { 9 a &= ~BIT3; 10 }
8.设置一绝对地址为0x67a9的整型变量的值为0xaa66,编译器是一个纯粹的ANSI编译器
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int *ptr; 2 ptr = (int *)0x67a9; 3 *ptr = 0xaa55;
9.关键字_interrupt
中断是嵌入式系统中重要的组成部分,ISP(中断服务子程序) 注意点:
a:ISR 不能返回一个值
b:ISR 不能传递参数
c:在许多的处理器/编译器中,浮点一般都是不可重入的,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
d:与第三点一脉相承,printf()经常有重入和性能上的问题
10.C语言中的整数自动转换原则
当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Void foo(void) 2 { 3 unsigned int a = 6; 4 int b = -20; 5 (a+b > 6) puts("> 6") : puts("<= 6"); 6 }
11.注意
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 unsigned int zero = 0; 2 unsigned int compzero = 0xFFFF; 3 /*1's complement of zero */ 4 5 对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下: 6 7 unsigned int compzero = ~0;
12.分析
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Char *ptr; 2 if ((ptr = (char *)malloc(0)) == NULL) 3 puts(“Got a null pointer”); 4 else 5 puts(“Got a valid pointer”); 6 7 代码的输出是“Got a valid pointer
13.typedef和define在C语言中频繁用以声明一个已经存在的数据类型的同义字(别名)
假设目的要定义dPS 和 tPS 都是一个指向结构s指针
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #define dPS struct s * 2 typedef struct s * tPS; 3 4 dPS p1,p2; 5 tPS p3,p4; 6 7 第一个扩展为: 8 struct s * p1, p2;
上面的代码定义p1为一个指向结构的指针,p2为一个实际的结构,显然错误了。第二个例子正确地定义了p3 和p4 两个指针。
14.编程风格问题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 Int a = 5, b = 7, c; 2 c = a+++b;
实际为:c = a++ + b
程序运行后结果为:a = 6、b = 7、c = 12
15.static有什么用途
16.引用与指针有什么区别
1) 引用必须被初始化,指针不必。
2) 引用初始化以后不能被改变,指针可以改变所指的对象。
3) 不存在指向空值的引用,但是存在指向空值的指针。
17.描述实时系统的基本特征
在特定时间内完成特定的任务,实时性与可靠性
18.全局变量和局部变量在内存中有什么区别
19.什么是平衡二叉树
20.冒泡排序的时间复杂度
O(n^2)
21.写出float x 与 “零值” 比较的if语句
if(x>-0.000001 && x<0.000001)
22.Internet采用哪种网络协议?该协议的主要层次结构
TCP/IP:应用层/传输层/网络层/数据链路层/物理层
23.Internet物理地址和IP地址转换采用什么协议
ARP协议(Address Resolution Protocol):地址解析协议
24.IP地址的编码分为哪两部分
网络号和主机号
25.局部变量能否和全局变量重名
26.如何引用一个已经定义过的全局变量
在变量前面加上 extern
27.语句for(;1;)有什么问题?它是什么意思
while(1)
28.static函数/全局变量/局部变量 与 普通的函数/全局变量/局部变量有什么区别
29.程序的局部变量存在于(堆栈)中,全局变量存在于(静态区 )中,动态申请数据存在于( 堆)中
30.队列和栈的区别
队列:先进先出 栈:后进先出
堆栈溢出一般原因:1.没有回收垃圾资源 2.层次太深的递归调用
31.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现
C语言:宏定义
C++:inline(内联函数):必须定义在头文件中
32.进程和线程的差别
线程:是进程内的一个执行单元,也是进程内的可调度实体
33.测试方法
人工测试:个人复查、抽查和会审
机器测试:黑盒测试/白盒测试
黑盒测试和白盒测试,二者最大的区别应该是测试时关注的对象不同
黑盒测试:主要针对的是程序展现给用户的功能(测试功能)
白盒测试:主要针对的是程序的代码逻辑(测试后台程序)
34.Heap与stack的差别
heap:堆 手动分配空间/释放空间 空间较大
stack:栈 系统自动分配空间/释放空间 空间有限
35.用宏定义写出swap(x,y)
#define swap(x, y) (x=x+y;y=x-y;x=x-y;)
36.数组a[N],存放了1至N-1个数,其中某个数重复一次。写一个函数,找出被重复的数字.时间复杂度必须为o(N)函数原型
37.一语句实现x是否为2的若干次幂的判断
(x&(x-1))? flase:true
38.sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小
39.一个32位的机器,该机器的指针是多少字节
指针是多少字节,只要看该机器的数据总线的位数,若为32位数据总线,则指针就为4字节
40.c和c++中的struct有什么不同
C中的struct不可以含有成员函数
C++中权限权限 struct(public)和class(private)
41.已知一个数组table,用一个宏定义,求出数据的元素个数
#define KST (sizeof(table)/sizeof(table[0]))
42.线程与进程的区别和联系? 线程是否具有相同的堆栈? dll是否有独立的堆栈?
43.写一个“标准”宏,这个宏输入两个参数并返回较小的一个
#define Min(X, Y) ((X)>(Y)?(Y):(X)) // 结尾没有;
44.写一个标准的宏定义:返回两个数中较小的一个
#define MIN(A, B) ((A) <= (B)?(A): (B))) // 参数要用括号括起来
45. sizeof和strlen的区别
sizeof()是运算符,编译时就已经计算好了,而strlen()是函数,要在运行时才能计算
46.PWM:脉冲宽度调制
47.STM32F107的集成A/D的特性输入:输入范围:VREF-≤VIN≤VREF+
48.程序的局部变量存在于哪里,全局变量存在于哪里,动态申请数据存在于哪里。
程序的局部变量存在于栈区;
全局变量存在于静态区;
动态申请数据存在于堆区。
49.进程之间通信的途径有哪些
1.无名管道
2.高级管道
3.有名管道
4.消息队列
5.信息量
6.信号
7.共享内存
8.套接字
50.死锁:多个并发进程因争夺系统资源而产生相互等待的现象
本质原因:1.系统资源有限 2.进程推进顺序不合理
51.进程与线程
18.进程和线程有什么区别?
答:进程是并发执行的程序在执行过程中分配和管理资源的基本单位。线程是进程的一个执行单元,是比进程还要小的独立运行的基本单位。一个程序至少有一个进程,一个进程至少有一个线程。两者的区别主要有以下几个方面:
1. 进程是资源分配的最小单位。
2. 线程是程序执行的最小单位,也是处理器调度的基本单位,但进程不是,两者均可并发执行。
3. 进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据,使用相同的地址空间,因此,CPU切换一个线程的花费远比进程小很多,同时创建一个线程的开销也比进程小很多。
4. 线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也跟着死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。
5. 进程切换时,消耗的资源大,效率低。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
6. 执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
优缺点:
线程执行开销小,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。
进程执行开销大,但是能够很好的进行资源管理和保护,可以跨机器迁移。
何时使用多进程,何时使用多线程?
对资源的管理和保护要求高,不限制开销和效率时,使用多进程。
要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
52.TCP和UDP的区别
答:TCP和UDP是OSI模型中的运输层中的协议。TCP提供可靠的通信传输,而UDP则常被用于广播和细节控制交给应用的通信传输,两者主要的不同体现在一下几个方面:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。它通过校验和,丢包时的重传控制,序号标识,滑动窗口、确认应答,次序乱掉的分包进行顺序控制实现可靠传输。即通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达; UDP尽最大努力交付,即不保证可靠交付。
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高要求的通信或广播通信场景。
4、每一条TCP连接只能是点到点的; UDP支持一对一,一对多,多对一和多对多的交互通信方式。
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
UDP有时比TCP更有优势:
UDP以其简单、传输快的优势,在越来越多场景下取代了TCP, 如实时游戏。
(1)网速的提升给UDP的稳定性提供可靠网络保障,丢包率很低,如果使用应用层重传,能够确保传输的可靠性。
(2)TCP为了实现网络通信的可靠性,使用了复杂的拥塞控制算法,建立了繁琐的握手过程,由于TCP在内置的系统协议栈中,极难对其进行改进。
采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大。
基于UDP对实时性要求较为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题造成的影响。
53.线程是否具有相同的堆栈
答:真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。
每个线程有自己的堆栈。
54..h头文件中的#ifndef/#define/endif
防止该头文件被重复引用
55.#include<stdio.h>和#include"stdio.h"的区别
前者是从Standard Library(标准库)的路径寻找和引用stdio.h, 后者是从当前用户的工作路径搜索并引用stdio.h
56.程序的内存分配:
1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区):(static)全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静 态变量在相邻的另一块区域。程序结束后由系统释放。
4、文字常量区:常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区:存放函数体的二进制代码
57.联合体union所占内存的计算方式
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 union U 2 { 3 char s[9]; 4 int n; 5 double d; 6 };
系统采用覆盖技术
,共用体变量中起作用的成员
是最后一次存放的成员
,在存入一个新的成员后原有的成员就失去作用
s占9字节,n占4字节,d占8字节,因此其至少需9字节的空间。
然而其实际大小并不是9,用运算符sizeof测试其大小为16.
这是因为这里存在字节对齐的问题,9既不能被4整除,也不能被8整除。因此补充字节到16,这样就符合所有成员的自身对齐了。
从这里可以看出联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:
1)大小足够容纳最宽的成员;
2)大小能被其包含的所有基本数据类型的大小所整除。
58.32位、64位编译器各类型大小和字节对齐
编译器 | 32位 | 64位 |
char | 1字节 | 1字节 |
char* void*(指针都一样) | 4字节 | 8字节 |
short int | 2字节 | 2字节 |
int | 4字节 | 4字节 |
unsigned int | 4字节 | 4字节 |
float | 4字节 | 4字节 |
double | 8字节 | 8字节 |
long | 4字节 | 8字节 |
longlong | 8字节 | 8字节 |
unsigned long | 4字节 | 8字节 |
59.ifndef/define/endif的作用
主要用于防止头文件的重复包含和编译
60.一个数组名代表的含义是数组中第一个元素的位置,即地址
61.静态变量和全局变量的区别
静态变量:静态存储区,被static关键字修饰过的变量具有文件作用域,只可以用于定义它的函数或者文件中
全局变量:静态存储区,可以被文件外的extern关键字调用
局部变量:栈
62.函数的定义和声明
定义:是为变量分配存储空间,还可以为变量指定初始值 需要申请存储空间
声明:是为程序表明变量的类型和名字 不需要申请存储空间
63.面向对象的基本特征:封装、继承、多态
封装:封装是指将客观事物抽象成类,每个类对自身的数据和方法进行保护。类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏,C++中,类是一种封装手段,采用类来描述客观事物的过程就是封装,本质上是对客观事物的抽象。
继承:继承是指可以使用现有类的所有功能,而不需要重新编写原来的类,它的目的是为了进行代码复用和支持多态。它一般有3种形式:实现继承、可视继承、接口继承。
多态:多态是指同一个实体同时具有多种形式,它主要体现在类的继承体系中,它是将父对象设置成为和一个或更多的它的子对象相等的技术,赋值以后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作,简单的说:就是允许将子对象的指针赋值给父类类型的指针,在运行时根据具体指向对象的类型来调用对应类。