Linux基础与C语言总结

发布于:2024-10-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

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文本编辑器的常用操作?

三大模式/模式切换

  1. 普通模式(Normal Mode)

    • 启动 Vim 时的默认模式,可以进行文本浏览、删除、复制、粘贴等操作。

    • 在此模式下,按 Esc 键可以确保你在普通模式中。

  2. 插入模式(Insert Mode)

    • 在此模式下,可以输入和编辑文本。

    • 从普通模式进入插入模式:

      • i 插入字符在光标之前。

      • I 插入字符在行首。

      • a 在光标之后插入字符。

      • A 在行尾插入字符。

      • o 插入新的一行(在光标下面)。

      • O 插入新的一行(在光标上面)。

    • 从插入模式返回普通模式:按 Esc 键。

  3. 命令模式(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代码是如何变成可执行文件的?

  1. 预处理

  2. 编译

  3. 汇编

  4. 链接

5.long字节数\char\short的取值范围

long    4\8(根据操作系统位数决定)
​
char    -128~127    0~255
​
short   -32768~32767    0~65535

6.int\float\指针\bool类型数据的"零值"比较判断

int:    if(0==num)
​
float:  if(0.000001>f&&-0.000001<f)
​
bool:   if(false==flag) / if(!flag)
​
指针:     if(NULL==*p)

7.C语言有哪些类型限定符?分别有什么功能?

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
const int* p;   //保护指向的值不能修改
int const *p;   //保护指向的值不能修改
int* const p;   //保护指针的指向不能修改
const int* const p; //指向的值和指向都不能修改
int const* const p; //指向的值和指向都不能修改
6.数组指针与指针数组
  • 数组指针(本质上是指针): 专门用于指向数组的指针

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.结构指针
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所占
用的字节数和成员布局为?
 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服务器采用大端系统, 大端数据模式称为网络字节序

如何判断大小端?

  • 使用联合判断

  • union Data
    {
        char ch;
        int num;
    }
    union Data d;
    d.num=0x01020304;//01高位-04低位
    if(d.ch==0x04)	 //ch低位地址
        小端
    else
        大端

11.预处理指令有哪些?功能?

#include <>/""
#define 定义宏(宏函数/宏常量)
  • 二义性:当使用宏的环境,参数等发生变化时,宏的运算规则也可能随之变化,这种现象称为二义性

  • 解决方法:通过给宏的每个参数和宏整体都加括号来避免二义性

  • #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函数

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;
}