1.字符串反转练习,给定一个字符串,让它反转输出,C语言版
include<stdio.h>
include<stdlib.h>
include<string.h>
int main()
{
char* source="script_wang";
int length=len(source);
char* des=(char*)malloc(length);//开辟一个内存空间
char* i=&source[length-1];//i指向字符串的最后一个字符
while(length!=0)
{
*des++=*i--;
length--;
}
*des=0;\\字符串的尾部以\0结尾
printf("%s",des);
free(des);\\释放
dest=NULL;\\防止产生野指针
}
//常见的错误写法
int main()
{
char a="hello";
char* str=&a;
strcpy(str,"hello");
printf(str);
return;
}
错误的原因在于:没有为 str 分配内存空间,将会发生异常
问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为
越界进行内在读写而导致程序崩溃。
Strcpy 的在库函数 string.h 中.程序的主要错误在于越界进行内存读写导致程序崩溃//
//正确的写法应该是
int main()
{
char* a="hello";//“hello”是字符串常量,所以a[0]='s'的赋值是不合法的
char* b=(char*)malloc(sizeof(a));
strcpy(b,a);
printf(b);
free(b);
b=NULL;\\防止产生野指针
}
/*
int a=3;
int *p;
p=&a;
*p=6;
printf("%d",*p);
int *b;
b=(int *)malloc(sizeof(int));
*b=5;
printf("%d",*b);
*/
为了能够理解指针,我也是煞费苦心,我的理解是:把指针*p当作是变量(知道是啥意思不?你怎么对待int buff;的就怎么对待他),而p当作是地址(认为是常量)。*为取值,&为取地址,然后你再去理解,是不是更容易一点呢?
上面的代码未经过测试!只是随便写一下。
说明:
char *src = "hello" 中的src是指向第一个字符‘h'的一个指针
char src[20] = "hello" 中数组名src也是执行数组第一个字符‘h’的指针
char a[]={ 'a ', 'b ', 'c '}; 'a ', 'b ', 'c ' 在栈里,可以去改变它 ,
char *a = "abc "; "abc "在静态存储区,不可以改变。
补充:
1.字符串的如何输入?
在C语言中没有字符串类型,用字符数组处理字符串
说明:
一维字符数组,用于存储和处理一个字符串 。二维字符数组,用于同时存储和处理多个字符串;
输入输出方法:逐个字符输入输出:%c 整个字符串输入输出:%s;
以字符串为单位处理时,直接使用数组名,无需&
输入字符串时,字符个数要小于数组的长度,例如输入5个字符,定义的字符数组至少应该有6个元素
输入字符串时,遇到回车或空格,输入结束,并且自动在串后面加上结束标志'\0'
输出字符串时,遇到字符串结束标志’\0',输出结束。
#include<stdio.h>
int main()
{
char ch[5];
scanf("%s", ch);
printf("%s", ch);//无需&
system("pause");
return 0;
}
用字符串处理函数输入和输出 在<string.h>头文件中
字符串输出函数puts
#include<string.h>
int main()
{
char str[10];
printf("请输入字符串");
gets(str);
printf("请输出字符串");
puts(str);
system("pause");
return 0;
}
2.若有 unsigned char *p1;
unsigned long *p2;
p1 = (unsigned char *)0x1000;
p2 = (unsigned long *)0x2000;
请问 p1+5=( ) p2+5=( )
答案:0x801005(相当于加上 5 位) 0x810014(相当于加上 20 位);
p1指向字符型,一次移动一个字符型,一次移动1个字节
p2指向长整型,一次移动一个长整型,一次移动4个字节
3.进程和线程的差别。
答:线程是指进程内的一个执行单元,也是进程内的可调度实体.
与进程的区别:
(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位
(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于
进程的资源.
(4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销
明显大于创建或撤消线程时的开销
其中:
首先只有在多线程中才有并发和并行的概念。
并行
并行是指两者同时执行,比如赛跑,两个人都在不停的往前跑;(资源够用,比如三个线程,四核的CPU )
并发
并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率。
区别:
并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
并发是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。
4.技术面面经
参考:http://www.sohu.com/a/234848072_690895
https://www.jianshu.com/p/60bb02e7c515
5.strlen与sizeof
sizeof函数是计算数据空间的字节数;
strlen函数是计算字符数组的字符数,以"\0"为结束判断,不包含结束字符'\0'。
总之,对于指针,sizeof操作符返回这个指针占的空间,一般是4个字节;而对于一个数组,sizeof返回这个数组所有元素占的总空间。
举例说明如下:
int a;
char b[]="abcd";
printf("%d", sizeof(a)); // 输出变量a所占的内存字节数,输出4
printf("%d", sizeof(b)); // 输出字符数组b所占的内存字节数,输出5(5=4+1,1为结束字符\0所占的内存)
printf("%d", strlen(b)); // 输出字符数组b中字符的个数,输出4(不含结束字符''\0)
char *str1="absde";
str1是一个指针,只是指向了字符串"absde"而已。所以sizeof(str1)不是字符串占的空间也不是字符数组占的空间,而是一个字符型指针占的空间。所以sizeof(str1)=sizeof(char*)=4,在C/C++中一个指针占4个字节
char str3[8]={'a',};
str3已经定义成了长度是8的数组,所以sizeof(str3)为8
参考:https://wenda.so.com/q/1387640751065741?src=9999&cid-pre=1000204
https://wenda.so.com/q/1371679689062635?src=150
5.static与extern
(1).修饰局部变量
(2).修饰全局变量
(3).修饰函数
改变函数的作用域
6.volate
7.列举几种进程的同步机制,并比较其优缺点。
标准答案:
答:
信号量机制及PV操作
自旋锁
管程,会合,分布式系统
看不懂的可以看下面的介绍blog:
1)我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。
首先应弄清PV操作的含义:PV操作由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:
P(S):①将信号量S的值减1,即S=S-1;
②如果S>=0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
V(S):①将信号量S的值加1,即S=S+1;
②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。
什么是信号量?信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。
执行一次P操作意味着请求分配一个单位资源;
而执行一个V操作意味着释放一个单位资源
利用信号量和PV操作实现进程同步
PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
使用PV操作实现进程同步时应该注意的是:
(1)分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
(2)信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
(3)同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。
【例1】生产者-消费者问题
在多道程序环境下,进程同步是一个十分重要又令人感兴趣的问题,而生产者-消费者问题是其中一个有代表性的进程同步问题。下面我们给出了各种情况下的生产者-消费者问题,深入地分析和透彻地理解这个例子,对于全面解决操作系统内的同步、互斥问题将有很大帮助。
(1)一个生产者,一个消费者,公用一个缓冲区。
定义两个同步信号量:
empty——表示缓冲区是否为空,初值为1。
full——表示缓冲区中是否为满,初值为0。
生产者进程
while(TRUE){
生产一个产品;
P(empty);
产品送往Buffer;
V(full);
}
消费者进程
while(True){
P(full);
从Buffer取出一个产品;
V(empty);
消费该产品;
}
2)管程
基本思想是将共享变量和对它们的操作集中在一个模块中,操作系统或并发程序就由这样的模块构成。
8.进程之间通信的途径
标准答案:
答 共享存储系统
消息传递系统
管道
9.堆栈的区别
程序的局部变量存在于(栈)中,全局变量存在于(静态区 )中,动态申请数据存在
于( 堆)中。
Heap 是堆,stack 是栈。
Stack 的空间由操作系统自动分配/释放,Heap 上的空间手动分配/释放。
Stack 空间有限,Heap 是很大的自由存储区
C 中的 malloc 函数分配的内存空间即在堆上,C++中对应的是 new 操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传
递也在栈上进行
10、队列和栈的区别
队列是先进先出,只能在一端插入另一端删除,可以从头或尾进行遍历(但不能同时遍历),
栈是先进后出,只能在同一端插入和删除,只能从头部取数据
11.strcpy的原型函数
//将源字符串加 const,表明其为输入参数,加 2 分
char * strcpy( char *strDest, const char *strSrc )
{
//对源地址和目的地址加非 0 断言,加 3 分
assert( (strDest != NULL) && (strSrc != NULL) );
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0’ );
return address;
}
strlen的原型函数
assert( strt != NULL ); //断言字符串地址非0
int strlen( const char *str ) //输入参数const
{
assert( strt != NULL ); //断言字符串地址非0
int len;
while( (*str++) != '\0' )
{
len++;
}
return len;
}
12.注意:数组名作为函数参数时,退化为指针,一个指针为 4 个字节
void Func ( char str[100] )
{
sizeof( str ) = ?
}
sizeof( str ) = 4
13.构造函数的作用?并把构造函数的定义格式写出来
构造函数的作用:初始化对象的数据成员。
class Counter
{
public:
// 类Counter的构造函数
// 特点:以类名作为函数名,无返回类型
Counter()
{
m_value = 0;
}
private:
// 数据成员
int m_value;
}
该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数->由构造函数完成成员的初始化工作
eg: Counter c1;
编译系统为对象c1的每个数据成员(m_value)分配内存空间,并调用构造函数Counter( )自动地初始化对象c1的m_value值设置为0。
深入了解的话:参考:
14.谈谈对多态的理解
多态:调用同一个函数名,可以根据需要但实现不同的功能。
编译时的多态性(函数重载);
运行时的多态性(虚函数),运行时的多态性是指在程序执行之前,根据函数名和参数无法确定应该调用哪一个函数。
15.虚函数和纯虚函数的区别
参考:
16.静态链接库和动态链接库的区别。
参考:
如何拿到offer:博客链接:
(只作参考,尽信书不如无书)
17.const放在函数的前中后分别有什么区别
Const:read only,const放在函数的前中后分别有什么区别
1)const char *p,char const *p,这两种修饰方法是一样的,此时的指针依旧可以指向其它的内存,但是通过指针修改它指向的值就是不可以的了
2) char * const p,它代表的是指针指向的地址不可以改变,而地址里面的内容是可以改变的
特别的,
3)char * p const: 一般这种定义都是硬件资源的定义,这些地址是不可以改变的。
const char * const p; //指针的指向和指向的内容都不可以被改变。这个一般使用在Rom空间中。
18.有没有用过网络通讯,多线程
在护理床的项目里面,设计APP利用TCP协议和底层控制版进行通信连接,实现一系列的姿态控制。由于APP是JAVA写的,我又是学习C语言的,出于兴趣,用了VS2010bian编写Socket实现TCP、UDP协议的交互,但他们都是单线程的,堵塞类型的,所以我又研究了的多线了并发服务器模型,多进程,多进程用的是fork函数,但是其因为开销比较大,所以不常使用,多线程主要是在Server端利用pthread_creat实现多线程,它是生成一个线程来完成和客户端的会话,而父进程则继续监听。
linux c编程实现多线程:
19.c与c++的区别
共同点:C++是C的超集,兼容大部分C的语法的结构;
不同点:
1)第一点就应该想到C是面向过程的语言,而C++是面向对象的语言
2)C和C++动态管理内存的方法不一样,C是使用malloc/free函数,而C++除此之外还有new/delete关键字
3)C中的struct是可以在C++中正常使用的,并且C++对struct进行了进一步的扩展,使struct在C++中可以和class一样当做类使用,而唯一和class不同的地方在于struct的成员默认访问修饰符是public,而class默认的是private
4)C++支持重载的依仗就在于C++的名字修饰与C不同,例如在C++中函数int fun(int ,int)经过名字修饰之后变为 _fun_int_int ,而C是 _fun,一般是这样的,所以C++才会支持不同的参数调用不同的函数;
5)C++中有引用,而C没有
6)C++全部变量的默认链接属性是外链接,而C是内连接
7)C 中用const修饰的变量不可以用在定义数组时的大小,但是C++用const修饰的变量可以
注:常见的主要是上面zhe'这些,进一步,如果有兴趣可以看:
20.来自blog友的一个分级的面试经历,必须严重对待!(2017年)
21.sizeof();测试变量所占地址的字节数
22.异步IO和同步IO区别
如果是同步IO:当一个IO操作执行时,应用程序必须等待,直到此IO执行完,在同步文件IO中,线程启动一个IO操作然后就立即进入等待状态,直到IO操作完成后才醒来继续执行;
异步IO:IO操作和应用程序可以同时运行,提高系统性能,提高IO流量,线程发送一个IO请求到内核,然后继续处理其他事情,内核完成IO请求后,将会通知线程IO操作完成了
23.中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。
具代表性的是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。
__interrupt void compute_area (void)
{
double area = PI * radius * radius;
printf(" Area = %f", area);
return area;
}
ISR不可能有参数和返回值的!
ISR尽量不要使用浮点数处理程序,浮点数的处理程序一般来说是不可重入的,而且是消耗大量CPU时间的!!
printf函数一般也是不可重入的,UART属于低速设备,printf函数同样面临大量消耗CPU时间的问题!
24.宏定义是在预编译阶段被处理的。
25.Norflash与Nandflash的区别
(1)、NAND闪存的容量比较大
(2)、由于NandFlash没有挂接在地址总线上,所以如果想用NandFlash作为系统的启动盘,就需要CPU具备特殊的功能,
如s3c2410在被选择为NandFlash启动方式时会在上电时自动读取NandFlash的4k数据到地址0的SRAM中。
(3)、NAND Flash一般地址线和数据线共用,对读写速度有一定影响。NOR Flash闪存数据线和地址线分开,
所以相对而言读写速度快一些。
25.SRAM:CPU的缓存就是SRAM,静态的随机存取存储器,加电情况下,不需要刷新,数据不会丢失
DRAM,动态随机存取存储器最为常见的系统内存,需要不断刷新,才能保存数据
SDRAM:同步动态随机存储器,即数据的读取需要时钟来同步。
26.编译和链接有什么不同?(如外部符号的处理)
编译生成的是目标文件(object *.o);
编译过程中对于外部符号不做任何解释和处理。外部符号对应的就是“符号”
链接生成的是可执行程序
链接将会解释和处理外部符号。外部符号对应的是地址
27.strcpy能把strSrc的内容复制到strDest,为什么还要char *类型的返回值?
为了实现链式表达式
28.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个
#define MIN(a, b) (a) <= (b) ? (a) : (b)
29.关键字static的作用是什么
static用来修饰一个局部的变量的时候,
生命域是全局的
作用域是局部的
static用来修饰一个模块内的(某一个C的源程序文件)全局变量的时候
生命域不变
作用域减小,只在本模块内有效
static用来修饰一个函数的时候
作用域减小,只在本模块内有效
30.说明关键字volatile有什么含意,并给出例子。
volatile表示被修饰的符号是易变的。告诉编译器不要随便优化我的代码!!
*一个硬件寄存器
*中断中用到的变量
*线程之间共享变量
31.什么是堆栈,简述为什么需要堆栈?
堆栈是计算机中最常用的一种数据结构,保存数据的一块连续内存;比如函数的调用是用堆栈实现的。
32.TCP通信建立和结束的过程?端口的作用
三次握手和四次挥手;端口是一个软件结构,被客户程序或服务进程用来发送和接收信息。一个端口对应一个16比特的数。服务进程通常使用一个固定的端口。
33.物理地址转换成IP地址的协议?反之?
地址解析协议(ARP)的作用是将IP地址转换成物理地址;反地址解析协议(RARP)则负责将物理地址转换成IP地址。
34.什么是平衡二叉树?
当且仅当两个子树的高度差不超过1时,这个树是平衡二叉树。
35.全局变量和局部变量的区别。
全局变量,储存在静态区.进入main函数之前就被创建.生命周期为整个源程序;
局部变量,在栈中分配.在函数被调用时才被创建.生命周期为函数内。
36.数组与链表的区别。
数组中的数据在内存中的按顺序存储的,而链表是随机存储的!
要访问数组中的元素可以按下标索引来访问,速度比较快,如果对他进行插入操作的话, 就得移动很多元素,所以对数组进行插入操作效率很低!由于连表是随机存储的,
链表在插入,删除操作上有很高的效率(相对数组),如果要访问链表中的某个元素的话,
那就得从链表的头逐个遍历,直到找到所需要的元素为止,
所以链表的随机访问的效率就比数组要低
37.死锁的四个条件及处理方法。
(1)互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
解决死锁的方法分为死锁的预防,避免,检测与恢复三种
38.进程调度策略。
先进先出算法,最短CPU运行期优先调度算法,轮转法,多级队列方法
39.时间换空间、空间换时间的例子。
冒泡排序 --- 时间换空间
快速排序,堆排序 --- 空间换时间
40.Linux驱动程序流程及功能。
设备驱动程序的功能:
对设备初始化和释放
把数据从内核传送到硬件和从硬件读取数据
读取应用程序传送给设备文件的数据和回送应用程序请求的数据
检测和处理设备出现的错误
50.关键字static的作用是什么?
*在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变(该变量存放在静态变量区)。
*在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。
它是一个本地的全局变量。
*在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。
那就是,这个函数被限制在声明它的模块的本地范围内使用。
51.局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用 ":: " 局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。
对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,
而那个局部变量的作用域就在那个循环体内。
52.答:可以,在不同的C文件中以static形式来声明同名全局变量。 可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错
53.static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
54.用两个栈实现一个队列的功能?要求给出算法和思路!
设2个栈为A,B, 一开始均为空.
入队: 将新元素push入栈A;
出队: (1)判断栈B是否为空;
(2)如果不为空,则将栈A中所有元素依次pop出并push到栈B;
(3)将栈B的栈顶元素pop出;
55..软件测试都有那些种类?
人工测试:个人复查、抽查和会审
机器测试:黑盒测试(针对系统功能的测试 )和白盒测试 (测试函数功能,各函数接口)
56.比较一下进程和线程的区别?
(1)、调度:线程是CPU调度和分派的基本单位
(2)、拥有资源:
* 进程是系统中程序执行和资源分配的基本单位
* 线程自己一般不拥有资源(除了必不可少的程序计数器,一组寄存器和栈),但他可以去访问其所属进程的资源,
如进程代码,数据段以及系统资源(已打开的文件,I/O设备等)。
(3)系统开销:
* 同一进程中的多个线程可以共享同一地址空间,因此它们之间的同步和通信的实现也比较简单
* 在进程切换的时候,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;
而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作,从而能更有效地使用系统资源和
提高系统吞吐量。
57.进程间通信方式:管道、命名管道、消息队列、共享内存、信号、信号量、套接字。
(1)、 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
进程的亲缘关系通常是指父子进程关系。
(2)、有名管道 (named pipe) :有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(3)、信号量( semophore ) :信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(4)、消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)、信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
(6)、共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,
这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,
如信号两,配合使用,来实现进程间的同步和通信。
(7)、套接字( socket ) : 套接字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
58.宏和函数的优缺点?
(1)、函数调用时,先求出实参表达式的值,然后带入形参。而使用带参数的宏只是进行简单的字符替换。
(2)、函数调用是在程序运行时处理的,分配临时的内存单元;而宏展开则是在编译时进行的,在展开时并不分配内存单元,
不进行值的传递处理,也没有“返回值”的概念。
(3)、对函数中的实参和形参都要定义类型,二者的类型要求一致,应进行类型转换;而宏不存在类型问题,宏名无类型,
它的参数也是无类型,只是一个符号代表,展开时带入指定的字符即可。宏定义时,字符串可以是任何类型的数据。
(4)、调用函数只可得到一个返回值,而宏定义可以设法得到几个结果。
(5)、使用宏次数多时,宏展开后源程序长,因为每次展开一次都使程序增长,而函数调用不使源程序变长。
(6)、宏替换不占运行时间,只占编译时间;而函数调用则占运行时间(分配单元、保留现场、值传递、返回)
59.C和c++的不同
c和c++的一些不同点(从语言本身的角度):
1)c++源于c,c++最重要的特性就是引入了面向对象机制,class关键字。
2)c++中,变量可以再任何地方声明;c中,局部变量只能在函数开头声明。
3)c++中,const型常量是编译时常量;c中,const常量只是只读的变量。
4)c++有&引用;c没有
5)c++的struct声明自动将结构类型名typedef;c中struct的名字只在结构标签名字空间中,不是作为一种类型出现
6)c语言的main函数可以递归调用;c++中则不可以
7)c中,void *可以隐式转换成其他指针类型;c++中要求现实转换,否则编译通不过
60.由C/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack): 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap): 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(static): 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,
未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后有系统释放 。
4、文字常量区: 常量字符串就是放在这里的, 程序结束后由系统释放。
进一步参考:
60.编写内核程序中申请内存和编写应用程序时申请内存有什么区别
应用程序使用C函数库中的内存分配函数malloc()申请内存,内核会为进程使用的代码和数据空间维护一个当前位置的值brk,这个值保存在每个进程的数据结构中。它指出了进程代码和数据(包括动态分配的数据空间)在进程地址空间中的末端位置。当malloc()函数为程序分配内存时,它会通过系统调用brk()把程序要求新增的空间长度通知内核,
内核代码从而可以根据malloc()所提供的信息来更新brk的值,但此时并不为新申请的空间映射物理内存页面。
只有当程序寻址到某个不存在对应物理页面的地址时,内核才会进行相关物理内存页面的映射操作。
当用户使用内存释放函数free()动态释放已申请的内存块时,c库中的内存管理函数就会把所释放的内存块标记为空闲,
以备程序再次申请内存时使用。在这个过程中内核为该进程所分配的这个物理页面并不会被释放掉。
只有当进程最终结束时内核才会全面收回已分配和映射到该进程地址空间范围内的所有物理内存页面。
61.tcp/udp是属于哪一层?tcp/udp有何优缺点?
tcp /udp属于运输层
TCP 服务提供了数据流传输、可靠性、有效流控制、全双工操作和多路复用技术等。
与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比 TCP 负载消耗少。
tcp: 提供稳定的传输服务,有流量控制,缺点是包头大,冗余性不好
udp: 不提供稳定的服务,包头小,开销小
62.应用程序ping发出的是ICMP请求报文
63.#error 预处理指令的作用是,编译程序时,只要遇到#error 就会生成一个编译错误提示消息,并停止编译
64.中断活动的全过程大致为:
1、中断请求:中断事件一旦发生或者中断条件一旦构成,中断源提交“申请报告”,
与请求CPU暂时放下目前的工作而转为中断源作为专项服务
2、中断屏蔽:虽然中断源提交了“申请报告”,但是,是否得到CPU的响应,
还要取决于“申请报告”是否能够通过2道或者3道“关卡”(中断屏蔽)送达CPU
(相应的中断屏蔽位等于1,为关卡放行;反之相应的中断屏蔽位等于0,为关卡禁止通行);
3、中断响应:如果一路放行,则CPU响应中断后,将被打断的工作断点记录下来
(把断点地址保护到堆栈),挂起“不再受理其他申请报告牌”
(清除全局中断标志位GIE=0),跳转到中断服务子程序
4、保护现场:在处理新任务时可能破坏原有的工作现场,所以需要对工作现场和工作环境进行适当保护;
5、调查中断源:检查“申请报告”是由哪个中断源提交的,以便作出有针对性的服务;
6、中断处理:开始对查明的中断源进行有针对性的中断服务;
7、清除标志:在处理完毕相应的任务之后,需要进行撤消登记(清除中断标志),以避免造成重复响应;
8、恢复现场:恢复前面曾经被保护起来的工作现场,以便继续执行被中断的工作;
9、中断返回:将被打断的工作断点找回来(从堆栈中恢复断点地址),
65.中断活动的全过程大致为:
1、中断请求:中断事件一旦发生或者中断条件一旦构成,中断源提交“申请报告”,
与请求CPU暂时放下目前的工作而转为中断源作为专项服务
2、中断屏蔽:虽然中断源提交了“申请报告”,但是,是否得到CPU的响应,
还要取决于“申请报告”是否能够通过2道或者3道“关卡”(中断屏蔽)送达CPU
(相应的中断屏蔽位等于1,为关卡放行;反之相应的中断屏蔽位等于0,为关卡禁止通行);
3、中断响应:如果一路放行,则CPU响应中断后,将被打断的工作断点记录下来
(把断点地址保护到堆栈),挂起“不再受理其他申请报告牌”
(清除全局中断标志位GIE=0),跳转到中断服务子程序
4、保护现场:在处理新任务时可能破坏原有的工作现场,所以需要对工作现场和工作环境进行适当保护;
5、调查中断源:检查“申请报告”是由哪个中断源提交的,以便作出有针对性的服务;
6、中断处理:开始对查明的中断源进行有针对性的中断服务;
7、清除标志:在处理完毕相应的任务之后,需要进行撤消登记(清除中断标志),以避免造成重复响应;
8、恢复现场:恢复前面曾经被保护起来的工作现场,以便继续执行被中断的工作;
9、中断返回:将被打断的工作断点找回来(从堆栈中恢复断点地址),
并摘下“不再受理其他申请报告牌”(GIE=1),继续执行原先被打断的工作。
有些题目参考的是:
66.linux上进程有几种状态?
linux上进程有5种状态:
1. 运行(正在运行或在运行队列中等待)
2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)
3. 不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
4. 僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)
5. 停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)
进一步有兴趣的话:
67.静态成员变量与非静态成员变量区别
68.C new和malloc的区别
69.memset函数的作用,有哪些参数
就是这个函数常用来在malloc后,将这段内存空间清空(如置0),以防在使用时(尤其是字符串)读出内存的随机值。
void *memset(void *s,int ch,size_t n);
函数解释:将 s 中前 n 个字节用 ch 替换并返回 s 。
memcpy函数的作用
参考:写的非常好了
memcpy与strcpy之间的区别:(原型函数参考这个就可以了)
函数原型:void *memcpy(void*dest, const void *src, size_t n);
用法:#include<string.h>
功能:从源src所指的内存地址的起始位置开始,拷贝n个字节的数据到目标dest所指的内存地址的起始位置中。
void *memcpy(void *dst,void *src,size_t size)
{
unsigned char *dst1=(unsigned char *)dst;
unsigned char *src1=(unsigned char *)src;
while(size--)
{
*dst1=*src1;
dst++;
src++;
}
if(dst==NULL && src=NULL)
return NULL;
}
70.Linux下C程序的存储空间布局
71.sizeof用法使用
sizeof的结果等于对象或者类型所 占的内存字节数
注意:结构体的字节对齐
标签:信号量,题目,函数,中断,常见,char,面试,内存,进程 From: https://blog.51cto.com/u_12740336/7527782