1、指针函数和函数指针
函数指针:指向一个函数的指针
指针函数:一个函数的返回值是一个指针的函数
2、指针的大小
char* int* float*
指针的大小和编译器的位数 有关,在32bit(x86) 的系统下指针的大小是4个字节 ,在64bit(x64) 的系统下指针是8个字节
指针的大小是固定的和指针的类型没有关系
3、sizeof和strlen的区别
sizeof:运算符,关键字。计算数据类型/变量所占存储空间的大小(字节数)。
strlen:函数。计算字符串长度。
(1)sizeof是一个运算符,strlen是一个函数,包含string.h
(2)sizeof计算的是所占内存的大小(/0需要计算),strlen计算的是字符串的长度(字符串以/0结尾,/0是不需要计算长度的)
(3)strlen一般用于字符串的长度,sizeof可以计算int float类型的大小
(4)计算时间:sizeof在编译期,strlen在运行期
4、c语言内存分配的方式
(1)静态存储器分配,例如全局变量,静态变量
(2)栈上分配(函数中定义出的局部变量)
(3)堆上分配(malloc,new)
5、数组指针和指针数组
(1)数组指针:指的是指向数组的指针,本质是一个指针
int (*p)[10];//数组指针的声明
(2)指针数组:本质是一个数组,里面的每一个元素都是指针
int* a,a1,a2;
int* p1[10]={a,a1,a2};//指针数值
6、struct结构体和union联合体区别
union 联合体:所有成员共享一块地址。
大小计算:共用体大小 = 成员中占内存最大的成员的大小。
struct 结构体:不同的成员放在不同的地址中。
大小计算:结构体大小 = 所有成员大小之和(字节对齐)。
7、野指针
野指针:指向不可用内存的指针
为什么会导致野指针:
(1)当指针被创建的时候,没有赋值这个时候指针就成为了野指针
char* p;
(2)当指针被free或delete后,如果没有把指针赋值为NULL,这个时候指针也是野指针
#include <malloc.h>
char* p1 = malloc(10);
free(pl);
(3)当指针越界的时候也是野指针(经常出现在数组里面)
8、数组和链表的区别
(1)数组的地址空间是连续的,链表的地址空间是不连续的
(2)数组的访问速度比较快,数组直接通过下标访问,访问链表的时候需要遍历链表
(3)链表增删查改的速度比数组快
9、宏函数注意点
写一个宏,这个宏返回输入参数比较小的一个
#define MIN(a,b) ((a)<=(b) ? (a):(b))//每个参数都要加一个括号
10、#include<>和#include""的区别
(1)#include<>:编译器会从标准库的路径里面去搜索,对于搜索标准库的文件速度会比较快
(2)#include"":编译器会从用户的工作路径里面去搜索,对于自己定义的文件使用""的速度会比较快
11、全局变量和局部变量的区别
(1)作用域:全局变量的作用域为程序块,局部变量的作用域是当前函数内部
(2)生命周期:全局变量的生命周期是整个程序,局部变量的生命周期是当前的函数
(3)存储方式:局部变量存储在栈里面的,全局变量存储在全局数据区中
(4)使用方式:全局变量在程序的各个部分都可以使用到,局部变量只能在函数的内部区使用
12、#define和typedef的区别
(1)define是一个预处理指令,typedef是关键字
(2)define不会做正确性检查,直接进行替换,typedef会做正确性检查
(3)define没有作用域的限制,typedef是有作用域的限制
(4)对指针的操作不同,一般使用typedef对指针进行重命名
13、static的作用
用来定义一个静态变量或者是静态函数
(1)在函数体中使用static去定义变量,那么这个变量只会被初始化一次
void fun(void)
{
static int a=0;//只会被执行一次
a++;
}
(2)定义的静态函数或者是静态变量只能在当前文件中使用(作用域的限制)
(3)在函数内部定义的静态变量无法被其他函数使用
14、内存泄漏
内存泄漏指的是在程序运行的时候,动态分配的空间没有被回收或者是正确释放,导致了这个内存空间仍然占据着系统的资源
15、内存对齐
内存对齐是在存储数据时,将数据按照一定的规则放置在内存中的过程
typedef struct
{
char a;//1
short c;//2
int d;//4
double b;//8
}STU;
以最大的变量所占据的内存来进行分配内存空间
16、数组名和指针的区别
(1)数组名就是数组首元素的地址,也可以看作一个常量指针,这个指针是不能修改指向的,内存访问为4个字节
(2)使用指针访问数组的时候需要使用到解引用使用*,使用指针访问数组是间接访问,使用数组名访问数组是直接访问
(3)使用sizeof对指针和数组名进行计算的时候也是不同的,指针的大小和编译器的位数有关 ,使用sizeof计算数组名是整个数组的大小
17、指针常量和常量指针
常量指针:指向一个常量的指针,这个指针无法修改所指向的数据 ,但是可以修改指向
int a =5;
int b =6;
const int *p = &a;
p=&b;
指针常量:指针是一个常量,指针所指向的地址是固定的 ,但是可以修改地址中的值
int* const pl = &a;
*pl = 5;
18、堆和栈的区别
(1)创建方式不同:
栈是系统自动创建(栈主要用于保存局部变量),当函数执行完成,栈被销毁
堆是程序员手动进行创建和释放的,malloc进行创建,free进行释放
(2)空间大小的区别:
栈的空间是比较小的
堆的空间是比较大的
(3)访问速度:
栈的访问速度是比堆要快的
(4)生命周期
栈当使用完成后就会自动被销毁
堆是要靠程序员自己进行手动销毁
19、malloc和new的区别
(1)malloc是C语言中的标准库函数,new是C++中的操作符
(2)malloc分配内存后返回的是void*类型的指针 ,new分配内存后返回的是对应对象类型的指针
(3)使用malloc分配内存的时候需要进行指定内存的大小,使用new进行内存分配时不需要指定
(4)使用malloc分配内存的时候不会调用到构造函数,使用new分配内存时会调用到构造函数
20、struct和class在C++中的区别
(1)struct成员默认是共有的,class默认的成员是私有的
(2)继承方面:struct默认的是共有继承,class默认的是私有继承
(3)使用场景:struct一般是用于做简单的数据结构(在c语言中一般是类型重命名),class一般用于封装和继承
21、C++中的类有几个访问权限
在C++中分别有三个访问权限:共有的、私有的、受保护的
(1)共有的(public):当成员声明为public时就可以在类的外部进行访问
class fun
{
public:
int a;
fun(void)
{
}
};
int main(void)
{
fun b;
b.a; //成员a被声明为public类型,可以在类的外部进行访问
return 0;
}
(2)私有的(private):当成员声明为private时只能在类的内部进行访问
class fun
{
private:
int a;
fun(void)//构造函数
{
a = 10; //可以在构造函数里面使用private类型
}
};
int main(void)
{
fun b;
// b.a; //成员a被声明为private类型,不可以在类的外部进行访问
return 0;
}
(3)受保护的(protected) :当成员声明为protected时只能在类的内部或者子类中进行访问
22、什么是内联函数,为什么要有内联函数
内联函数:是一种特殊的函数声明方式,通过在函数前面加上inline关键字 ,来指示编译器在调用这个函数的时候将他展开,而不是进行调用
inline int add(int a,int b)
{
return a+b;
}
int add main(void)
{
add(1,2);//不是进行普通的调用,直接将上面的函数替换到这里
return 0;
}
为什么要有内联函数:减少函数调用的开销
提高执行的效率
允许编译器进行优化进一步提高性能
23、使用C语言实现strcpy字符串拷贝函数
strcpy函数:实现字符串的拷贝,需要明确参数和返回值
cpp
char* mystrcpy(char* dest,char* src)
{
char* temp = dest;//指针指向目的地址
while((*dest++ =*src++));//循环到/0结束循环
return temp;
}
24、程序分为几段
(1)代码段:用于存储程序的可执行指令,一般是只读的,防止被修改
(2)数据段(Data):用于存储已经初始化的全局变量和静态变量
(3)BSS段:存储没有初始化的全局变量和静态变量(一般初始值为0)
(4)堆:malloc和free进行管理的
(5)栈:存储局部变量,栈的申请和释放是由操作系统来决定的
25、队列和栈的区别
(1)访问方式:栈是先进后出 ,队列是先进先出
(2)操作方式:栈只能栈顶 进行操作,队列在队尾 进行插入 ,队首 进行删除
(3)应用场景:栈主要用于函数调用 和表达式求值 ,队列用于任务调度、广度优先搜索
26、一个.c文件怎么转换为可执行程序
(1)预处理:将头文件宏定义进行展开,生成没有注释的源代码 生成**.i**结尾的文件
(2)编译:将预处理得到的源代码转换为汇编代码 生成**.s**结尾的文件
(3)汇编:将汇编的代码转换为机器码生成对应的目标文件 生成**.o**结尾的文件
(4)链接:将全部的.o文件链接成一个可执行程序
27、SPI和IIC寻址的区别
(1)SPI寻址方式:
MISO:主入从出
MOSI:主出从入
SCLK:时钟线
CS:片选引脚,选择对应的设备进行通信
(2)IIC寻址方式:
SDA:数据线
SCL:时钟线
通过丛机地址来进行寻址(7位,10位)
28、交叉编译
交叉编译:在一个平台上编译出另一个平台的可执行程序
ARM开发板 .c
ubuntu 使用交叉编译工具链 .c->可执行程序
29、UART、IIC、SPI的区别
(1)通信方式 :UART:异步通信的方式,没有时钟线
IIC和SPI都是同步通信,SCL SCLK
(2)接线的区别:UART:TX,RX
SPI:SCLK(时钟线)、CS(片选引脚)、MISO(主机输入丛机输出)、 MOSI(主机输出丛机输入)
IIC:SDA(数据线)、SCL(时钟线)
(3)设备数量:UART:一对一通信
IIC:支持多主机多丛机之间的通信
SPI:一主机多丛机
(4)传输速度:UART:115200 9600(由波特率决定的)
IIC:标准模式(100kbps)、快速模式(400kbps)、高速模式(3.4Mbps)
SPI:比IIC快
(5)工作模式:UART:全双工、半双工
IIC:半双工
SPI:全双工
30、SPI有几个线,可以去除哪些线
(1)SPI有四根线
SCLK:时钟线,用于同步数据传输时的时序控制
MOSI:主设备输出,从设备输入线
MISO:主设备输入,从设备输出线
CS:片选线,用于选择对应的丛机设备
(2)可以去除哪些线
不需要进行双向通信时,可以去除MOSI、MISO其中一根线
只进行一对一通信的时候,可以去除CS线
31、TCP和UDP的区别
(1)数据的可靠性:TCP提供的是可靠性的数据传输,三次握手
UDP无连接的,提供不可靠的数据通信
(2)通信方式:TCP是面向连接的通信方式
UDP是不需要进行连接
(3)数据传输的效率:UDP的通信速率比TCP快,UDP丢包概率比较大
(4)应用场景:TCP一般用于邮件,文件传输(FTP)
UDP:视频、在线游戏、直播
32、进程和线程的区别
(1)定义:进程是资源分配的基本单位
线程是进程中的执行单元,CPU调度和执行的基本单位 进程>线程
(2)资源占用:每一个进程都有自己独立的地址空间
线程是共享进程的地址空间
(3)容错性:当一个进程出现问题不会影响到其他的进程执行
线程出现问题可能会导致整个程序崩溃从而影响到其他的线程
(4)调度和切换:进程是一个独立的单位,由调度器进行调度和切换,需要恢复的上下文的内容 就比较多,消耗的资源就比较多
线程在进程当中,线程消耗的资源是比较小的
33、进程间通信有几种方式,哪几种需要借助内核
(1)进程间通信有几种方式:
管道
命名管道
共享内存(mmap)
信号量
消息队列
套接字(socket)
信号
(2)哪几种需要借助内核
管道、 共享内存(在内核空间创建的共享内存)、信号量、信息队列、套接字