每日一练day_2

本文介绍了C语言中系统调用与库函数的区别,强调了系统调用的非移植性和库函数的平台移植性。接着详细阐述了sizeof和strlen的区别,前者在编译时计算,后者在运行时计算字符串长度。同时讨论了C语言内存分配的三种方式及常见的内存错误类型,包括内存未分配使用、引用未初始化指针、越界操作和内存泄漏等问题。最后提到了野指针的概念,并给出避免野指针的编程建议。
摘要由CSDN通过智能技术生成

1.    系统函数与库函数的区别:

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

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

2.

 

2.sizeof和strlen的区别

1)对于指针,sizeof操作符返回这个指针占的空间,一般是4个字节;而对于一个数组,sizeof返回这个数组所有元素占的总空间。char*与char[]容易混淆,一定要分清,而且char*="aaa"的写法现在不被提倡,应予以避免

而strlen不区分是数组还是指针,就读到\0为止返回长度。而且strlen是不把\0计入字符串的长度的。

2)一、sizeof

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

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

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

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

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

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

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

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

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

**************

二、strlen

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

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

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

1)内存分配方式有三种:

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

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

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

2)类型 1:内存未分配成功,却使用了它。

方   法:在使用之前检查指针是否为NULL。

             1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。

             2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。

类型 2:引用了尚未初始化的指针

原   因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。

              1)没有初始化的观念。

              2)内存的缺省值是未定义,即垃圾值。

类型 3:越界操作内存

原   因:内存分配成功且初始了,但越界操作是不允许的。

例   如:在使用数组时经常发生下标“多1”或“少1”,特别是在for循环语句时。

类型 4:忘记释放内存,造成内存泄漏。

原   因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。

类型 5:释放了内存却继续使用它

原   因:对应的情况有2种

              1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。

              2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。

使用规则

      为了保证代码的健壮和安全,可以参考如下的规则:

规则1:使用malloc申请的内存时,必须要立即检查相对应的指针是否为NULL。

规则2:初始化数组和动态内存。

规则3:避免数组或指针下标越界。

规则4:动态内存的申请和释放必须相配对,防止内存泄漏。

规则5:free释放某块内存之后,要立即将指针设置为NULL,防止产生野指针。

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

1)野指针:指向不确定地址的指针变量。(即没有初始化)使用野指针易因内存泄露出现段错误。而造成内存泄露的原因有两个:

1.访问了没有权限的内存(平时我们正确使用指针的时候,系统应经将相应的内存分配给用户,但是如果指向没有分配的内存,系统会判定我们没有权限)

2.访问了已经释放了的内存。

2)因为野指针主要是因为我们平时编程习惯造成的,因此我们只能避免野指针的出现,而不能杜绝。(请注意用词)我们在编程时,做到以下几点可以有效地避免野指针的出现。

 

第一,当一个指针没有指向时,我们一般默认指向NULL。(NULL代表内存的0地址,并且NULL是不允许做任何操作的)

 

第二,使用malloc分配内存。(在堆空间里分配内存)

#difine  MAX_SIZE  1024;

char *ptr = (char *) maollc  (sizeof (char) *MAX_SIZE);

 

请认真研究这样的表达式的优点,这个表达式在代码的维护性,扩展性都大大提高了。这方面是我们平时写代码时所应该提高的。

 

使用malloc也是有讲究的,我们应该依照下面的流程:

1.分配内存。(分配成功,返回内存的首地址;分配不成功,返回NULL)。

2.检查是否分配成功(若失败,则  exit(1) 退出程序)。

3.清空内存中的数据 (malloc分配的空间里可能存在垃圾值,因此我们需要清空,可以用到memset或bzero 函数)。

4.使用内存。

5.释放内存(free,这时ptr又变成野指针)。

6.写成NULL。

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

分别写出BOOL,int,float,指针类型的变量a 与“零”的比较语句。

答案:

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

 

int :     if ( a == 0)

 

float :   const EXPRESSION EXP = 0.000001

         if ( a < EXP && a >-EXP)

 

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





 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值