C语言基础

递归问题

1、递归函数定义没有问题,递归深层次后易引发什么问题?
(1)影响执行效率

(2)栈溢出。

因为每一次调用函数是,栈区都要给函数分配空间,而且上一次调用并没有结束,调用的次数太多,栈区的内存不够分配了,便会出现栈溢出的情况。

函数指针与指针函数

函数指针:一个指针,指向一个函数
使用函数指针的好处:

可以将实现同一功能的多个模块统一起来标识,更容易进行后期维护
指针函数

指针函数指的是函数的返回值是一个指针

比如:int *p(int a,int b);

堆与栈区别

2、堆与栈的区别?
(1)栈的空间是系统自动分配和回收,堆的空间是用户手动分配回收(malloc,calloc,realloc,free)

(2)栈的空间较小,堆的空间较大

(3)栈的地址空间往地址向下增长,堆的地址空间是由低地址到高地址

(4)栈的存储效率更高

内存分区 栈-堆-静态常量-常量-代码

在这里插入图片描述

malloc()与calloc分配空间有什么不一样?

(1)malloc申请后空间的值是随机的,并没有进行初始化;而calloc却在申请后,对空间逐一进行初始化,并设置值为0;

(2)malloc要申请的空间大小,需要我们手动的去计算;calloc并不需要人为的计算空间的大小。

malloc和new的区别

(1)属性
new是C++关键字,需要编译器支持;malloc是库函数,需要头文件支持。

(2)内存区域
new操作符从自由存储区上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。

【自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。】

(3)参数
使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。

(4)返回类型
new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。

(5)分配失败
new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。

goto

局限

循环控制条件关键字goto被经常使用,goto会破坏程序的栈逻辑。

使用场景

循环控制条件关键字goto的使用场景有哪些?
(1)常用来跳出死循坏;

(2)打印错误;

(3)goto被经常使用,只是使用场合受到局限,因为他会破坏程序的栈逻辑。

字节对齐

什么是字节对齐?
字节对齐主要是针对结构体而言的,通常编译器会自动对其成员变量进行对齐,以提高数据存取的效率;

常见数据字节数

sizeof(int*)=sizeof(char*)=8
主要看64位编译器
在这里插入图片描述

字节对齐的两种方式 -默认对齐-指定对齐

默认对齐方式、指定对齐方式;

(1)默认对齐方式内存分配满足以下三个条件:

    1.结构体第一个成员的地址和结构体的首地址相同;

    2.结构体每个成员地址相对于结构体首地址的偏移量(offset)是该成员大小的整数倍,如果不是则编译器会在成员之间添加填充字节;

    3.结构体总的大小要是其成员中最大size的整数倍,如果不是编译器会在其末尾添加填充字节。

    如char是1字节,short是2字节,int是4字节...

(2)指定对齐方式使用以下方式声明:

//注:通过#pragma pack(n)改变C编译器的字节对齐方式

#pragma pack(4) //安装4字节的对齐方式
指定对齐方式内存分配满足以下几个条件:

局部变量和全局变量可以重名

(1)能,局部变量会屏蔽全局变量。C++中要用全局变量,需要使用 “::”(域解析符) 。C语言中局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。

(2)对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。

UNIX系统中fsync函数的作用?

fsync()负责将参数fd 所指的文件数据, 由系统缓冲区写回磁盘, 以确保数据同步。

头文件:#include

定义函数:int fsync(int fd);

函数说明:fsync()负责将参数fd 所指的文件数据, 由系统缓冲区写回磁盘, 以确保数据同步.

返回值:成功则返回0, 失败返回-1, errno 为错误代码。

预处理指令

文件包含 include

• #include:用于将另一个源代码文件的内容插入当前文件进行编译。
 
#include <stdio.h> // 包含系统头文件
#include "myheader.h" // 包含用户自定义头文件

宏 defind

#define:用于定义宏,可以是对象型宏(简单文本替换)或函数型宏(带参数的宏)。
 只替换,不计算。
#define CONSTANT_NAME value
#define MACRO(param1, param2) expression
 
• #undef:用于取消已经定义过的宏。

条件编译 #if # endif

• #if、#elif、#else、#endif:构成条件编译结构,根据条件决定是否编译特定部分的代码。
 
#if defined(MACRO)
  // 当MACRO被定义时,编译这部分代码
#elif (expression)
  // 如果上述条件不满足且expression为真,则编译这部分代码
#else
  // 上述所有条件都不满足时,编译这部分代码
#endif
 
• #ifdef 和 #ifndef:简化了对某个标识符是否定义的检查。
 
#ifdef MACRO
  // 如果MACRO已定义,则编译这部分
#ifndef MACRO
  // 如果MACRO未定义,则编译这部分
#endif

关键字

volatile

此关键字用于修饰变量,告知编译器该变量的值可能在程序执行过程中由硬件、中断服务程序或其他并发线程修改,因此编译器不能对此变量进行优化(例如删除看似冗余的读写操作)。
每次读写都是从内存中取值,不是从缓存器中取。

const

修饰变量
只能访问不能修改变量
const的 常规用法,在变量初次定义时赋初,并用关键字const修饰,使变量只可访问,不能重新赋值修改变量。
修饰指针
指针变量指向的位置不能被修改
(1)int *const p;限制指针变量修饰:指针变量指向的位置不能被修改。定义时,被 const 修饰的指针变量指针只能在定义时初始化,不能定义之后重新指向新的数据。

(2)const int *p ;限制指针变量指向的数据修饰【指针的解引用】:修饰的指针变量指向的变量的值不能被修改,但是该指针可以指向其它空间。

(3)const int *const p;同时限制指针变量和指针变量指向的变量的值修饰:指针变量指向的位置不能被修改,并且指针变量指向变量的值也不能被修改。

(4)修饰函数形参【指针】:函数形参可以利用const关键字进行限制,来防止在函数内部修改指针指向的数据

static 静态XX

作用于局部变量时:叫静态局部变量,在函数调用时,只有在该函数第一次调用时才对其分配空间和初始化。在函数调用结束时,不对该变量的内存进行释放。
在这里插入图片描述

作用于全局变量时:叫静态全局变量。表示该变量是私有的,只能在该文件使用。不能通过extern关键字对其引用。

作用于函数时:叫静态函数,表示该函数是私有的,只能在本文件中使用,不能通过extern关键字对其引用

typedef

该关键字用于为已存在的数据类型创建一个新的名称,即给数据类型取别名。

//将unsigned int 重命名为uint_32, 所以uint_32也是一个类型名
typedef unsigned int uint_32;
int main()
{
    //观察num1和num2,这两个变量的类型是一样的
    unsigned int num1 = 0;
    uint_32 num2 = 0;
    return 0;
}

extern 声明

对本文件来说,下面定义的全局变量在上面使用,需要extern声明;对其他文件定义的全局变量本文件使用,也是extern声明

union联合体和struct结构体

区别:
结构体
内存分配:结构体中的每个成员都分配独立的内存区域,结构体的大小是所有成员大小之和(可能还会有填充字节)。
数据存取:结构体的每个成员都可以独立地存取和修改。
2.联合体
内存分配:联合体中的所有成员共享同一块内存,联合体的大小等于最大成员的大小。
数据存取:同一时间只能访问一个成员,修改一个成员会覆盖其他成员的数据。

sizeof()与strlen()的区别?

定义 功能 参数 生效阶段

(1)sizeof是运算符,计算数据类型占内存的大小,参数可以是数组、指针、类型、对象、函数等;sizeof在编译时就计算出了sizeof的结果

(2)strlen是函数,功能是返回字符串的长度,参数必须是字符型指针(char*)。strlen函数必须在运行时才能计算出来。

内存泄漏和内存溢出是什么?

(1)内存溢出:指程序申请内存时,没有足够的内存供申请者使用。或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错Out Of Memory,即所谓的内存溢出。

(2)内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间。一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就是内存溢出。

定义一个指针赋值字符串与定义一个数组赋值字符串

(1)指针赋值字符串是指向一定内存的指针,只不过是指向字符串常量的指针,指针中的数据不能修改。

(2)数组赋值字符串是一片char型的数组,可以理解为缓冲区,只不过是赋值为了字符串。

编译器的作用?

编译器就是将一种语言(通常为高级语言)翻译为另一种语言(通常为低级语言)的程序。一个现代编译器的主要工作流程:源代码(.c)→ 预处理器(.i) → 编译器 (.s)→ 目标代码 (.o)→ 链接器 → 可执行程序 。

预处理的作用是什么?

1.展开头文件2.宏替换3.去掉注释行

C语言编译流程

预处理-编译-汇编-链接

预处理:插入头文件,展开宏定义
编译:包括词法分析、语法分析、词义分析、代码优化和中间代码产生等,产生汇编文件
汇编:将汇编文件转化为二进制目标文件
链接:调用静态库(编译时加载)或者动态库(运行时加载),产生可执行文件
在这里插入图片描述

.ELF文件是什么?

.ELF是C语言在linux中的可执行文件。

大小端模式

大端模式:是指数据的高字节保存在内存的低地址中;
小端模式:是指数据的高字节保存在内存的高地址中;

strcpy和memcpy区别

1.复制的内容不同 字符串-任意

strcpy只能复制字符串,

memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2.复制的方法不同 不定长-定长

strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,如果空间不够,就会引起踩内存。

memcpy则是根据其第3个参数决定复制的长度。

3.用途不同

通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy,由于字符串是以“\0”结尾的,所以对于在数据中包含“\0”的数据只能用memcpy。

断言 assert

assert(src != NULL);//断言 括号内部成立上面事情不发生,否则报错

头文件:#include<assert.h>

作用: 解决预防性编程的问题,例如参数传入一个指针为NULL时,程序就会奔溃时,我们可以增加assert来防御这种问题。

const和define区别

在这里插入图片描述

静态 动态链接

静态链接是在编译链接时直接将需要的执行代码拷贝到调⽤用处;

优点: 在于程序在发布时不需要依赖库,可以独立执行,

缺点: 在于程序的体积会相对较大,⽽而且如果静态库更更新之后,所有可执行文件需要重新链接;

31.2动态链接
动态链接是在编译时不直接拷贝执行代码,而是通过记录一系列符号和参数,在程序运⾏行行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行行到指定代码时,在共享执行内存中寻找已经加载的动态库可执⾏代码,实现运行时链接;

优点:在于多个程序可以共享同一个动态库,节省资源;

缺点:在于由于运行时加载,可能影响程序的前期执行性能

进程通信

无名管道(Pipe):管道是一种单向通信机制,可以通过创建一个内核缓冲区来实现父子进程间的通信。
有名管道(Named Pipe):类似于管道,但允许无关的进程进行通信,且可以通过文件系统进行通信。
信号(Semaphore):信号用于控制对共享资源的并发访问,在多个进程之间进行同步。
共享内存(Shared Memory):共享内存是一种将一块内存区域映射到多个进程的地址空间,从而实现进程间的数据共享。
消息队列(Message Queue):消息队列是一种通过消息传递方式进行进程间通信的机制,允许多个进程发送和接收消息。
信号灯集(Signal):信号是一种用于进程间通知和处理异步事件的机制,一个进程可以发送信号给另一个进程来触发相应的处理动作。
套接字(Socket):套接字可以用于在网络上不同计算机的进程之间进行通信,实现分布式进程间通信。

TCP UDP

三次握手
TCP为啥握手三次
三次握手同时是可以检查通信双方的 发送能力 以及 接收能力 是否是正常的。
TCP滑动窗口和拥塞控制
区别
TCP:有连接,可靠传输,面向字节流,全双工

UDP:无连接,不可靠,面向数据报,全双工

HTTP HTTPS

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

多线程

在操作系统中进程和线程的区别:

进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1–n个线程。(进程是资源分配的最小单位)

线程:同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换开销小。(线程是cpu调度的最小单位)
线程和进程一样分为五个阶段:创建、就绪、运行、阻塞、终止。

多进程是指操作系统能同时运行多个任务(程序)。

多线程是指在同一程序中有多个顺序流在执行。

在java中要想实现多线程,有两种手段,一种是继承Thread类,另外一种是实现Runable接口,并与Future、线程池结合使用
java多线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值