笔试训练2

1. 系统调用与库函数的区别?

系统调用(英语system call),指运行在用户空间应用程序操作系统内核请求某些服务的调用过程。 系统调用提供了用户程序与操作系统之间的接口。一般来说,系统调用都在内核态执行。由于系统调用不考虑平台差异性,由内核直接提供,因而移植性较差(几乎无移植性)。

库函数(library function),是由用户或组织自己开发的,具有一定功能的函数集合,一般具有较好平台移植性,通过库文件(静态库或动态库)向程序员提供功能性调用。程序员无需关心平台差异,由库来屏蔽平台差异性。

 一般而言,跟内核功能与操作系统特性紧密相关的服务,由系统调用提供;

具有共通特性的功能一般需要较好的平台移植性,故而由库函数提供。

 

库函数与系统调用在功能上相互补充,如进程间通信资源的管理,进程控制等功能与平台特性和内核息息相关,必须由系统调用来实现。

 

文件 I/O操作等各平台都具有的共通功能一般采用库函数,也便于跨平台移植。

某些情况下,库函数与系统调用也有交集,

 库函数中的I/O操作的内部实现依然需要调用系统的I/O方能实现。

 

2. Sizeof 与 strlen 的区别?

 sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。

    它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。

    由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组所占的空间,返回值跟对象、结构、数组所存储的内容没有关系。

    具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:

    数组——编译时分配的数组空间大小;

    指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4);

    类型——该类型所占的空间大小;

    对象——对象的实际占用空间大小;

函数——函数的返回类型所占的空间大小。函数的返回类型不能是void。

 

strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。

    它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。

 

char arr[10] = "What?";

              int len_one = strlen(arr);

              int len_two = sizeof(arr);

              cout << len_one << " and " << len_two << endl;

    输出结果为:5 and 10

    点评:sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。strlen只关心存储的数据内容,不关心空间的大小和类型。

 

char * parr = new char[10];

              int len_one = strlen(parr);

              int len_two = sizeof(parr);

              int len_three = sizeof(*parr);

              cout << len_one << " and " << len_two << " and " << len_three << endl;

    输出结果:23 and 4 and 1

    点评:第一个输出结果23实际上每次运行可能不一样,这取决于parr里面存了什么(从parr[0]开始知道遇到第一个NULL结束);第二个结果实际上本意是想计算parr所指向的动态内存空间的大小,但是事与愿违,sizeof认为parr是个字符指针,因此返回的是该指针所占的空间(指针的存储用的是长整型,所以为4);第三个结果,由于*parr所代表的是parr所指的地址空间存放的字符,所以长度为1。

 

数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,

如:

fun(char [8])

fun(char [])

都等价于 fun(char *)

C++里参数传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小

如果想在函数内知道数组的大小, 需要这样做:

进入函数后用memcpy拷贝出来,长度由另一个形参传进去

fun(unsiged char *p1, int len)

{

unsigned char* buf = new unsigned char[len+1]

memcpy(buf, p1, len);

}

我们能常在用到 sizeof 和 strlen 的时候,通常是计算字符串数组的长度

看了上面的详细解释,发现两者的使用还是有区别的,从这个例子可以看得很清楚:

char str[20]="0123456789";

int a=strlen(str); //a=10; >>>> strlen 计算字符串的长度,以结束符 0x00 为字符串结束。

int b=sizeof(str); //而b=20; >>>> sizeof 计算的则是分配的数组 str[20] 所占的内存空间的大小,不受里面存储的内容改变。

上面是对静态数组处理的结果,如果是对指针,结果就不一样了

char* ss = "0123456789";

sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,应该是

长整型的,所以是4

sizeof(*ss) 结果 1 ===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,是char类

型的,占了 1 位

strlen(ss)= 10 >>>> 如果要获得这个字符串的长度,则一定要使用 strlen

 

3. C语言分配内存的方式有哪些?C语言中常见的内存错误有哪些?

 内存分配方式有三种:

1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量

  2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。   局部变量,函数参数

3、从堆上分配,亦称动态内存分配。程序在运行的时候用mallocnew申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

 

常见的内存错误:

    1:内存分配未成功

     使用p==NULL来判断是否为空可以避免这个问题或者使用异常处理语句来处理错误

    分配未成功可能是堆内存不够用(内存肯定是够用的,所以这个问题很少出现),最大的可能就是在此malloc之前的malloc分配的内存访问出现了越界

 

     2:分配成功但是没有初始化

     全局变量和静态变量以及数组会自动初始化为0,但是其他类型的数据就是随机系统初始化的,时刻保持一种习惯,创建变量的同时就赋空或者0

 

     3:内存分配成功,但是操作越界,比如在排序算法循环中,经常没有控制好循环控制变量就很容易出现越界

 

     4:忘记了释放内存或者释放了部分内存,造成内存泄漏。开始的时候觉得没有什么,当多次出现这个情况就会出现oom

      动态分配的内存 malloc和free配对,new delete配对,java中比如各种流打开也要配对关闭,不要太指望gc会自己处理,他只是个机器。

 

 

     5:释放了内存却还在继续使用

      常见的为函数返回指向“内存”的指针或者是引用,它使局部作用的变量,函数结束就会自动释放了

 

     6:释放了内存,但是没有重新空,产生野指针

     free只是释放了该指针指向的内存,但是它作为一个独立的变量还是会存在的,不给他赋值他就乱指形成野指针。

 

     7:误以为动态分配的内存会自动释放(很容易忽略!)

  void funTest(){

    char *p=(char *)malloc(100);

  }

  调用该函数后分配的指针变量p为局部变量会自动释放,但是他指向的内存并不会释放

 

4. 什么是野指针?如何避免野指针?

何为野指针?野指针就是,没有被初始化的指针,会由系统默认一个随机地址的指针。如果不小心使用的野指针,易造成内存泄漏的段错误。给我们的程序造成一定的破坏。

那么,我们该如何避免野指针呢?

首先,我们该养成一些良好的编程习惯。

1、当指针没有指向的地址空间是,初始化为空。这样可以引起程序员调试时的注意程度。

2、当往指针指向的空间赋值时,一定要检查是否有给这个指针分配空间。如果没有,就用malloc函数进行分配空间。

如:char *ptr = (char *) malloc (sizeof(char) * 100);

malloc函数返回的是分配的空间的地址。

3、malloc 分配空间后,一定要进行检查 指针是否为空。

如:

if(ptr == NULL)

{

    printf("malloc error!\n");//分配空间失败

    exit(1);

}

4、对空间进行清空,“清扫”掉一些垃圾数据。

如:memset( ptr, '\0', sizeof(char) *100;

5、空间使用完了还要还给系统,所以我们要进行释放内存空间。

如:free (ptr);

6、 最后一步,将刚刚使用的指针置空。

如:ptr= NULL;

 

5.分别写出bool, int, float, 指针类型的变量a与“零”的比较语句?

BOOL :  if ( !a ) or if(a)  

int :   if ( a == 0)  

float : const EXPRESSION EXP = 0.000001  

  <span style="white-space:pre">  </span>if ( a < EXP&& a >-EXP)  

pointer : if ( a != NULL) or if(a == NULL) 

 

不可将浮点变量用==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值