一、循环
1、问: for\while\do-while 区别?
for循环就是一种让代码反复执行的方法,一般使用一个变量来引导循环的执行
while相当于for的精简版本,和for循环在使用时的区别是是否知道循环次数
do-while先执行循环体,再判断循环条件,和之前两个循环的区别在于该循环体至少执行一次
二、堆内存和栈内存
1、堆内存与栈内存的区别?
栈内存是存放局部变量和块变量的地方,由操作系统来管理,其栈地址是向下增长的,这种先进后出的特殊模式,使用起来安全、方便;优点是系统会自动申请、释放内存,使用简单;缺点是大小有限,不适合存储大量数据;当函数结束时栈内存就会被释放, 不适合长期存储数据。
堆内存是进程的一个内存段(text\data\bss\heap\stack),由程序员手动管理,其栈地址是向上增长的;当程序变得复杂,数据量变多,其它内存段的申请释放不受控制时,就可以使用堆内存,其申请释放受控制,可以适时地节约内存;但他的安全性差;在使用过程中可能会造成内存泄漏、产生内存碎片等问题;优点是存储空间够大,适合长期保存数据;缺点是需要手动申请释放,使用麻烦。
2、使用堆内存越界的后果
1、超过分配的33页产生段错误
2、破坏了malloc的维护信息,再次使用malloc、free会出错
3、脏数据
3、什么是内存泄漏? 你是如何定位内存泄漏的?
由于业务逻辑出错或者粗心大意导致使用完毕的堆内存没有正常释放,当再次需要时又要重新申请,又没有释放,
长时间积累下导致可以用的内存越来越少,系统就会越来越慢甚至系统崩溃,这种就叫做内存泄漏
1、windows 查看任务管理器 Linux ps -aux命令 GDB查看进程中的内存分布情况
2、借助mtrace(代码分析工具)查看漏写了free
3、封装malloc和free函数,记录申请和释放内存信息到日志中
三、宏函数
定义一个宏函数表示100年总共有多少秒
#define SEC (3600*24*365*100u)
#define 与 typedef 的区别?
#define INT int
typedef int INT;
INT num;
如果是普通类型,他们功能上没有任何区别
#define INTP int*
typedef int* INTPP;
INTP p1,p2,p3; //p1 是int* p2 p3 是int
INTPP p1,p2,p3; //p1 p2 p3 都是int*
int* p1,p2,p3;
宏函数与普通函数的区别?
它们是什么?
宏函数:带参数的宏替换,只是代码替换,只是使用像函数而已,不是真正的函数
函数:是一段具有某项功能的代码集合,会被翻译成二进制指令存储代码段,函数名就是它的首地址,有独立的栈内存、命名空间
有什么不一样:
函数: 返回值 类型检查 安全 内存申请、释放 速度慢 函数跳转
宏函数: 运算结果 通用 危险 替换 速度快 代码冗余
注意:调用频繁、内容简单的功能时候写成宏函数
在定义常量时const与#define有什么区别?
四、数据结构中的栈
1、顺序栈和链式栈的区别
顺序栈是事先确定好大小的,是一块连续的存储空间
链栈是动态的,是不连续的存储空间
顺序栈和链栈更像是运算受限制的数组和链表
五、
1、判断出栈顺序是否为真
1 2 3 4 5 入栈
1 2 3 4 5 对
3 2 1 4 5 对
3 1 2 5 4 错
2、两个栈模拟一个队列
从栈1到栈2必须一个不留
栈2不空,栈1不能到栈2
/* 两个栈模拟队列 */
typedef struct Queue
{
ArrayStack* S1;
ArrayStack* S2;
}Queue;
// 创建队列
Queue* create_queue(size_t cal)
{
Queue* queue = malloc(sizeof(Queue));
queue->S1 = create_array_stack(cal);
queue->S2 = create_array_stack(cal);
return queue;
}
// 队满
bool full_queue(Queue* queue)
{
return full_array_stack(queue->S1) && full_array_stack(queue->S2);
}
// 队空
bool empty_queue(Queue* queue)
{
return empty_array_stack(queue->S1) && empty_array_stack(queue->S2);
}
// 入队
bool push_queue(Queue* queue,TYPE val)
{
if(full_array_stack(queue->S1))
{
if(!empty_array_stack(queue->S2)) return false;
while(!empty_array_stack(queue->S1))
{
TYPE top = 0;
top_array_stack(queue->S1,&top);
pop_array_stack(queue->S1);
push_array_stack(queue->S2,top);
}
}
printf("tail:%d\n",val); // 测试
return push_array_stack(queue->S1,val);
}
// 出队
bool pop_queue(Queue* queue)
{
if(empty_array_stack(queue->S2))
{
if(empty_array_stack(queue->S1)) return false;
while(!empty_array_stack(queue->S1))
{
TYPE top = 0;
top_array_stack(queue->S1,&top);
pop_array_stack(queue->S1);
push_array_stack(queue->S2,top);
}
}
TYPE top = 0;
top_array_stack(queue->S2,&top);
printf("top:%d\n",top); // 测试
return pop_array_stack(queue->S2);
}
int main(int argc,const char* argv[])
{
Queue* queue = create_queue(10);
for(int i=0; i<10; i++)
{
push_queue(queue,i);
}
while(!empty_queue(queue))
{
pop_queue(queue);
}
}