1.常用的Linux命令
常用:cd ls clear man sudo size time strace
文件:touch cat/more/head/tail(查看文件) cp mv rm umask chmod
目录:mkdir rmdir rm -rf cp -frp
网络:ping ifconfig ssh/telent/ftp
其他:ps -aux find grep reboot tar
2.vim文本编辑器的常用操作?
三大模式/模式切换
-
普通模式(Normal Mode)
-
启动 Vim 时的默认模式,可以进行文本浏览、删除、复制、粘贴等操作。
-
在此模式下,按
Esc
键可以确保你在普通模式中。
-
-
插入模式(Insert Mode)
-
在此模式下,可以输入和编辑文本。
-
从普通模式进入插入模式:
-
按
i
插入字符在光标之前。 -
按
I
插入字符在行首。 -
按
a
在光标之后插入字符。 -
按
A
在行尾插入字符。 -
按
o
插入新的一行(在光标下面)。 -
按
O
插入新的一行(在光标上面)。
-
-
从插入模式返回普通模式:按
Esc
键。
-
-
命令模式(Command Mode)
-
在此模式下,可以执行命令,如保存、退出、搜索等。
-
从普通模式进入命令模式:按
:
键。 -
键入命令后按
Enter
执行。
-
行底模式: 替换(:%s/xxx/xxx/g) 查找(:/xxx) 多行缩进(:<n 向左缩进n行)
自动补全: 插入模式下Ctrl+p
自定义功能: 通过配置vimrc配置文件, 自定义了快速保存退出, 快速保存并编译运行, 快速自动添加头文件, main函数, 新文件自动生成头文件卫士
3.gcc编译器常用的编译参数
-E 预处理
-S 编译
-c 只编译不连接
-o 指定编译结果名字
-l 指定库名
-L 指定库文件加载路径
-I 指定头文件加载路径
-Wall 尽可能多的产生警告
-Werror 把警告当错误处理
-std 指定编译语法标准
-fpic 生成与位置无关的文件 .so
-static 优先使用静态库
-D 编译时定义宏名
-shared 生成共享库参数
-g 添加生成调试信息 以此可以进入GDB调试
4.C代码是如何变成可执行文件的?
-
预处理
-
编译
-
汇编
-
链接
5.long字节数\char\short的取值范围
cpp
long 4\8(根据操作系统位数决定)
char -128~127 0~255
short -32768~32767 0~65535
6.int\float\指针\bool类型数据的"零值"比较判断
cpp
int: if(0==num)
float: if(0.000001>f&&-0.000001<f)
bool: if(false==flag) / if(!flag)
指针: if(NULL==*p)
7.C语言有哪些类型限定符?分别有什么功能?
cpp
auto 用于定义自动申请\自动释放变量(局部变量)
const 保护变量不被"显示"修改
static
改变局部变量的存储位置(stack->bss/data(是否初始化))
延长局部变量生命周期(程序开始->程序结束)
限制全局变量\函数的作用域(本文件内使用)
volatile
取消编译器对变量的"取值优化"
if(num==num) //默认情况下永远为真
if(num==num) //num被volatile修饰 可能为假
register
申请把变量存储到寄存器中,可能会失败
extern
声明外部变量,帮助通过编译,如果链接时也找不到定义语句会报错
typedef
类型重定义
8.指针的知识点有哪些?
1.什么是指针?
是数据类型 定义指针变量 是整数 代表内存编号(地址) 每个地址对应一个字节的内存,指针变量可以通过解引用运算符来访问他指向的内存数据,访问的字节数取决于指针的类型(char/short/int...)
2.什么情况下使用指针?
-
函数之间共享变量(返回多个值)
-
提高函数的传参效率(与const紧密配合)
-
与堆内存配合管理内存
3.使用指针时需要注意哪些问题?
-
空指针:解引用会产生段错误(解决方法:使用来历不明的指针之前先判断是否为NULL)
- 初始化/作为函数错误值返回
-
野指针:指向未知内存地址的指针
-
解引用: 可能一切正常/脏数据/段错误
-
危害比空指针更大(因为无法通过代码判断野指针)
-
避免产生野指针(一定要初始化)
-
4.指针的运算
-
指针+n
-
指针-n
注意:相+-的是n*字节数, 结果是一个临时地址,指针本身指向没有改变
- 指针-指针(类型相同):结果为两个指针之间间隔的元素个数(所有要类型相同)
5.指针与const
cpp
const int* p; //保护指向的值不能修改
int const *p; //保护指向的值不能修改
int* const p; //保护指针的指向不能修改
const int* const p; //指向的值和指向都不能修改
int const* const p; //指向的值和指向都不能修改
6.数组指针与指针数组
- 数组指针(本质上是指针): 专门用于指向数组的指针
cpp
int (*arr)[5] = malloc(sizeof(int)*5*10)//10行5列
指针数组(本质上是数组): 由同类型指针变量组成的数组
int* arr[10]={}//10行5列
for(int i=0;i<10;i++)
{
arr[i]=malloc(sizeof(int)*5);
}
7.void指针的作用
void* 能与任意类型的指针自动转换
当一个函数的参数/返回值可以是任意类型时,那么定义为void*
例子:malloc() qsort();
C++通过模板技术和引用来替代void*
8.二级指针
指向指针的指针,专门用于存储普通指针变量的地址
什么时候使用二级指针: 当需要跨函数共享普通指针变量时,使用二级指针传递
9.函数指针
-
用于指向函数首地址的指针
-
函数会被编译成二进制指令存储在代码段(text段)中,调用函数时编译器会跳转到该函数所在代码段中的位置执行
-
函数名就是该函数在代码段中的首地址
-
函数指针可以存储函数的首地址,通过函数名赋值,像调用函数一样使用函数指针
-
函数指针可以实现回调模式
-
qsort() \ pthread_create() \ signal \ at_exit() \ on_exit()
-
在main函数执行之前能否执行其他函数?(不可以,但是C++允许调用构造函数)
10.结构指针
cpp
Student* stu=malloc(sizeof(Student));
-
申请堆内存存储结构
-
提高传参效率
-
->访问成员
11.结构中成员指针
-
一般不建议使用
-
先给结构分配内存,然后还要给成员指针分配内存
-
结束时要先释放结构成员指针,再释放结构内存
-
要进行深拷贝
12.指针与数组名的相同点与不同点
指针: 数据类型 变量 指向关系
数组名: 常量 与数组首地址映射关系(一对一,不能赋值)
相同点:都可以代表内存地址,使用时 [] 和 *互通使用
9.结构\联合的对齐补齐
编译器为了更快地访问结构\联合的成员,会在成员之间,结构末尾填充一些空白字节
-
对齐: 在结构中,假设第一个成员使用的是0地址,那么每个成员所使用的内存地址必须是他类型字节数的整数倍,如果不是则填充空白字节,直到满足位置.
-
补齐: 在结构和联合中,总字节数必须是最大成员字节数的整数倍,如果不是,则在末尾填充空白字节
**注意:**在Linux系统中,在计算对齐补齐时,超过4\8字节(32位\64位),按照4\8字节计算
在Windows系统中,成员是多少字节就按多少字节计算
#pragma pack(n) 可以手动设置对齐,补齐的最大字节数,Linux中只能设置为1,2,4
例题:
在32位IBM-PC机上使用C语言,以下结构体的总字节数成员布局为?若有如下定义: 则变量a所占
用的字节数和成员布局为?
cpp
struct A
{
char c; //C 0
//X 1
short s[2]; //SS 23
//SS 45
//XX 67
int i; //IIII 8~11
};
//C:char,S:short,I:int,X:填充字节
A、 9, CSSSSIIII
B、 10, CXSSSSIIII
C、 12, CXSSSSXXIIII
D、 12, CXXXSSSSIIII
选C
0 1 2 3 4 5 6 7 8 9 10 11
C X S S S S X X I I I I
10.如何判断系统大小端?
-
小端系统:高位地址存储高位数据,低位地址存储低位数据
个人PC:Windows Linux等都是采用小端系统, 小端数据模式也称为本地字节序
-
大端系统:高位地址存储地位数据,低位地址存储高位数据
网络设备,UNIX服务器采用大端系统, 大端数据模式称为网络字节序
如何判断大小端?
-
使用联合判断
cpp
union Data
{
char ch;
int num;
}
union Data d;
d.num=0x01020304;//01高位-04低位
if(d.ch==0x04) //ch低位地址
小端
else
大端
11.预处理指令有哪些?功能?
#include <>/""
#define 定义宏(宏函数/宏常量)
-
二义性:当使用宏的环境,参数等发生变化时,宏的运算规则也可能随之变化,这种现象称为二义性
-
解决方法:通过给宏的每个参数和宏整体都加括号来避免二义性
cpp
#define和typedef的区别:
替换 重定义
#define INT int
typedef int INT;
INT num;//普通类型使用时没有任何区别
#define INTP1 int*
INTP1 p1,p2,p3; //p1是指针,p2,p3不是
typedef int* INTP2;
INTP2 p1,p2,p3; //p1,p2,p3都是指针
-
宏函数与内联函数的优缺点,区别?
-
宏函数与普通函数区别\优缺点?
-
宏常量与const修饰全局变量的区别?
-
存储位置: 宏常量\const修饰过且初始化后的全局变量 存储在代码段(text段)(都不能修改)
const修饰过的未初始化的全局变量 存储在BSS段(可以)
-
全局变量会被局部变量屏蔽 宏常量不会
-
#ifndef \#define \#endif
-
头文件的相互包含问题:XXX未定义
-
原因是A.h中有B.h的内容, 但是B.h中也有A.h中的内容
-
解决方法:提取相互使用到的内容到C.h 让A.h B.h导入C.h
-
-
条件编译与分支语句对比的好处?
12.堆内存与栈内存的优缺点?
-
堆内存:是进程的heap内存段,由程序员手动申请和释放
-
优点:可以动态调整内存,能申请足够大的内存,理论上能达到物理内存上限
-
缺点:使用麻烦,较危险,容易产生内存碎片和内存泄漏
-
-
栈内存:是进程的stack内存段,有操作系统自动分配和释放内存
-
优点:使用方便,速度快,不易产生内存碎片和内存泄漏
-
缺点:内存空间有限,无法动态调整
-
13.二进制文件与文本文件的区别?
-
二进制文件:把内存中数据的补码直接存储到文件中
- 直接存储, 直接读取, 方便快捷,无法通过文本编辑器直接阅读查看
-
文本文件:把数据转换成字符串,再把字符串的对应ASCII的二进制存储到文件中
- 数据需要先转换后写入,读取时要解析字符串,可以通过文本编辑器阅读
-
Windows中文本文件的写入'\n' 实际上写入的是'\r\n'
读取时遇到'\r\n'实际读取成'\n'
-
Windows文本文件和二进制文件都应该遵循对应的打开方式
-
Linux无论文本文件还是二进制文件'\n'都是正常读写
14.原码,反码,补码的概念和转换?
15.什么是内存泄漏?如何定位内存泄漏?
-
内存泄漏:由于程序员粗心大意或者业务逻辑问题导致申请了的内存未释放
-
定位内存泄漏:
-
Windows查看任务管理器,Linux通过ps -aux命令,通过GDB查看内存使用情况
-
借助mtrace代码分析工具分析malloc,free的使用情况
-
封装malloc,free记录调用情况到日志文件
-
16.什么是内存碎片?如何减少内存碎片?
-
内存碎片:已经释放但是也无法使用的内存,由于申请,释放的时间, 大小不协调导致
-
内存碎片无法杜绝只能减少
-
解决方法:
-
使用栈内存
-
申请大块的堆内存
-
不要频繁申请 释放内存
-
17.什么是IO缓冲区?需要注意什么问题?
为了减少读取和写入次数,提高读写速度
-
输出缓冲区:
-
遇到'\n'会刷新
-
遇到输入语句都会立刻被刷新
-
当缓冲区满的时候
-
程序正常结束
-
fflush(stdout)
-
-
输入缓冲区:
-
需要输入整数\浮点数,如果输入字符型,该数据会残留在输入缓冲区,不会被正常读取,并且会继续影响接下来的数据读取
-
fgets(str,20)输入超出部分会残留在输入缓冲区,影响接下来的输入
-
先输入整数\浮点数,然后再输入字符\字符串,前面输入的'\n'或者是空格会残留并被后面的字符\字符串接收scanf("%d %c")
-
19.strlen, strcpy, strcat, stcmp函数
cpp
size_t strlen(const char* str)
{
const char* tmp=str;
while(*tmp++);
return tmp-str-1;
}
char* strcpy(char* dest,const char* src)
{
char * tmp=dest;
while(*tmp++=*src++);
return dest;
}
char* strcat(char* dest,const char* src)
{
char* tmp=dest;
while(*++tmp);
while(*tmp++=*src++);
return *dest;
}
int strcmp(const char* s1,const char* s2)
{
while(*s1==*s2&& *s1)
{
s1++;
s2++;
}
return *s1-*s2;
}