Linux C 基础简答题 1

(1)系统调用和库函数的区别?
库函数是语言本身的一部分,而系统函数是内核提供给应用程序的接口,属于系统的一部分。
函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一部分。

用户应用程序访问并使用内核所提供的各种服务的途径即是系统调用。在内核和用户应用程序相交界的地方,内核提供了一组系统调用接口,通过这组接口,应用程序可以访问系统硬件和各种操作系统资源。 
1.系统调用是为了方便应用使用操作系统的接口,而库函数是为了方便人们编写应用程序而引出的,比如你自己编写一个函数其实也可以说就是一个库函数。
2.系统调用可以理解为内核提供给我们在用户态用的接口函数,可以认为是某种内核的库函数。
3.read就是系统调用,而fread就是C标准库函数.

(2)sizeof和strlen的区别?
1、 本质不同
sizeof是运算符。
Strlen是函数。

2、 处理的阶段不同
Sizeof在编译时就已经完成了计算。
Stelen是在运行时进行计算。

3、 计算的内容不同
sizeof可以计算一个字符串的长度也可以计算一个数据变量所占内存的大小。
Strlen只能计算字符串的长度。

4、 对\0的处理方式不同
Sizeof会把\0也计算在内。
Strlen遇到\0停止,但是不会把\0计算在内。

5、 对于指针的处理不同
Sizeof是求这个指针的的大小
Strlen是求这个指针所指向的内容的大小

6、 对括号的要求不同
Sizeof求数据类型所占内存大小时可以不加括号;求变量的长度时必须加括号
Strlen必须加括号


(3)什么是野指针?如何避免野指针?
野指针:指向不确定地址的指针变量。(即没有初始化) (随机指向一块内存的指针)
使用野指针易因内存泄露出现段错误。因为它随机指向的地址可能被分配了内存,不一定每次都产生段错误.

而造成内存泄露的原因有两个:
1.访问了没有权限的内存(平时我们正确使用指针的时候,系统应经将相应的内存分配给用户,但是如果指向没有分配的内存,系统会判定我们没有权限)
2.访问了已经释放了的内存。
 
如何解决野指针,养成一下编码习惯:
1,当一个指针没有指向时,置为NULL(空),
NULL宏:#define NULL(void * )0,0地址对应的空间不允许进行任何操作。
2,当往一个指针赋值的时候,一定要给指针分配空间,
int *p = malloc(100);返回首地址,int *p = malloc(sizeof(int)):提高代码的移植性。
3,当给一个指针分配空间,一定压迫检查是否分配成功。
if(p == NULL)
{
printf("malloc error!\n");
exit(1);
}
4,分配空间成功之后,要先初始化,
memset(p,0,sizeof(int));
5,释放 free(p);
6,再次置空:p = NULL;

因为野指针主要是因为我们平时编程习惯造成的,因此我们只能避免野指针的出现,而不能杜绝。(请注意用词)我们在编程时,做到以下几点可以有效地避免野指针的出现。
 
第一,当一个指针没有指向时,我们一般默认指向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。


(4)C语言分配内存的方式有哪些?常见的内存错误有哪些?
分配方式有三种:
  1、从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
  2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  3、从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。

常见的错误      

关于内存的一些知识已在内存分配中提及,现记录与分享常见的内存错误与对策。
类型 1:内存未分配成功,却使用了它。
方   法:在使用之前检查指针是否为NULL。
             1)当指针p是函数的参数时,在函数入口处用语句assert(p!=NULL)进行断言检查。
             2)当使用malloc或new来申请内存时,应该用if(p != NULL)进行防错检查。
类型 2:引用了尚未初始化的指针
原   因:内存的缺省初始值究竟是什么并没有统一的标准,在使用之前都进行初始化。
              1)没有初始化的观念。
              2)内存的缺省值是未定义,即垃圾值。
类型 3:越界操作内存
原   因:内存分配成功且初始了,但越界操作是不允许的。
类型 4:忘记释放内存,造成内存泄漏。
原   因:含有这种类型错误的函数,每被调用一次,就丢失一块内存。当内存充足时看不到这种错误带来的影响,当内存耗尽时系统提示:“内存耗尽”。因此,动态内存的申请与释放必须配对,程序中malloc与free的使用次数要相同。
类型 5:释放了内存却继续使用它
原   因:对应的情况有2种
              1)返回了“栈内存的指针或引用”,因为堆栈中的变量在函数结束后自动销毁。
              2)某块内存被free后,没有将指向该内存的指针设置为NULL,导致产生“野指针”。


(5)bool,int,float,指针类型和零的比较语句?
bool   if(!flag) if(flag)
int      if(a == 0)     if(a != 0)
float   if(i > -0.00001 && i <0.000001)
指针   if(a == NULL)          if(a !=NULL)

(6)什么是内存泄漏和内存空洞,内存溢出?
内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。所以每次使用类似malloc这样的函数都要free或者delete。

内存溢出通俗来讲就是内存不够用了,通常在运行大型软件或游戏时,软件或游戏所需要的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。

内存空洞的例子,是使用结构体时因为结构体有字节补齐的情况,如
struct student
{
 char name[20];
 int    age;
 int    test;
 char  sex;
};
其中char是1个字节,int 是4个字节,但是总体不是10个字节,按照1,结构体总体大小是最长成员整数倍;2,每个成员补充自己的的整数倍。所以char一个字节补齐为2个,int就是4个,最后结果是12.其中补齐的那一段就造成了内存空洞。




猜你喜欢

转载自blog.csdn.net/rocky_56x/article/details/79218717