笔试训练(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hu_junhua/article/details/79221601

1.linux中 文件属性以 l、b、c、d。开头的都是什么文件?

l是链接,相当于windows的快捷方式
d是目录,相当于windows的文件夹
c是字符设备文件,给你说你不懂,鼠标,键盘算是
b是块设备,硬盘就是一个例子

2.哪一个文件定义了网络服务的端口?

/etc/services : 定义网络服务的端口

3.linux中 UID PID PPID 分别是什么?

UID是用户ID,
PID是进程ID,
PPID是父进程ID。

4.程序kill -9与kill -15的区别

在Linux/unix下,中止一个Java进程有两种方式,一种是kill -9 pid,一种是kill -15 pill(默认)。
两种方式的区别是:
SIGNKILL(9) 的效果是立即杀死进程. 该信号不能被阻塞, 处理和忽略。
SIGNTERM(15) 的效果是正常退出进程,退出前可以被阻塞或回调处理。并且它是Linux缺省的程序中断信号。

5.内存分配方式有几种?

静态存储区,,栈 ,堆的内存分配
从静态存储区域分配内存。(全局变量 static)程序编译的时候内存已经分配好了,并且在程序的整个运行期间都存在,例如全局变量。
在栈上创建。在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数结束时这些存储单元自动被释放。
处理器的指定集中有关于栈内存的分配运算,因此效率比较高,但是分配的内存容量有限。
在堆上分配内存,亦称动态内存分配,程序在运行的时候用malloc函数或new运算符申请任意大小的内存,程序员要用free函数或delete运算符释放内存。动态内存使用非常灵活,但问题也很多。

常见的错误
类型 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,导致产生“野指针”

6.野指针
概念:“野指针”不是NULL指针,是指指向“垃圾”内存的指针。即指针指向的内容是不确定的。
指向不确定地址的指针变量
访问了没有权限的内存
访问了已经释放了的内存
产生的原因:1)指针变量没有初始化。因此,创建指针变量时,该变量要被置为NULL或者指向合法的内存单元。
2)指针p被free之后,没有置为NULL,让人误以为p是个合法的指针。
3)指针跨越合法范围操作。不要返回指向栈内存的指针或引用
例子1-1:引用尚未初始化的指针
[cpp] view plain copy
char *p;
*p = ‘A’;//error,p指向未定义
例子1-2:return语句返回指向“栈内存”的指针
[cpp] view plain copy
char *GetString1(void)
{
char p[] = “hello world!”;
//p在栈区,常量字符串在常量字符区

return p;//error,返回栈内存的地址  

}
例子1-3:使用了被释放的内存
[cpp] view plain copy
char pstr = (char )malloc(sizeof(char)*100);
free(pstr); //pstr所指的内存被释放
if (NULL !=pstr)//没起到作用
{
strcpy(pstr,”string!”);//error,有时候程序不会提示有误,但还是不允许
}
注意:free()释放的是指针指向的内存!不是指针变量!这点非常非常重要!指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,前面我已经说过了,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用。
对比下面的例子,加深理解
例子1-4:函数返回值传递动态内存
[cpp] view plain copy
char* GetMemory(int num)
{
char p = (char )malloc(sizeof(char) * num);
return p ;//ok,返回堆区的地址值
}
例子1-5:
[cpp] view plain copy
char *GetString(void)
{
char *p = “hello world!”;
//指针变量p在栈区,指向文字常量区的字符

return p;//ok,返回字符串的地址  

}

避免的方法:
1.使用前对其初始化(置为null;用malloc分配内存,访问合法内存)
2.指针用完后记得释放内存(置为null, 用malloc的用free , 用memset清零内存)

7.写bool , float, 指针变量 与“零值”比较的if语句。
布尔变量与零值比较
不可将布尔变量直接与TRUE、FALSE或者1、0进行比较。
根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE的值究竟是什么并没有统一的标准。例如Visual C++ 将TRUE定义为1,而Visual Basic则将TRUE定义为-1。
假设布尔变量名字为flag,它与零值比较的标准if语句如下:
if (flag) // 表示flag为真
if (!flag) // 表示flag为假
其它的用法都属于不良风格,例如:
if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)

整型变量与零值比较
l 【规则4-3-2】应当将整型变量用“==”或“!=”直接与0比较。
假设整型变量的名字为value,它与零值比较的标准if语句如下:
if (value == 0)
if (value != 0)
不可模仿布尔变量的风格而写成
if (value) // 会让人误解 value是布尔变量
if (!value)

浮点变量与零值比较
l 【规则4-3-3】不可将浮点变量用“==”或“!=”与任何数字比较。
千万要留意,无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“> =”或“ <=”形式。
假设浮点变量的名字为x,应当将
if (x == 0.0) // 隐含错误的比较
转化为
if ((x> =-EPSINON) && (x <=EPSINON))
其中EPSINON是允许的误差(即精度)。
例如精度为:const float EPSINON = 0.00001;

指针变量与零值比较
l 【规则4-3-4】应当将指针变量用“==”或“!=”与NULL比较。
指针变量的零值是“空”(记为NULL)。尽管NULL的值与0相同,但是两者意义不同。假设指针变量的名字为p,它与零值比较的标准if语句如下:
if (p == NULL) // p与NULL显式比较,强调p是指针变量
if (p != NULL)
不要写成
if (p == 0) // 容易让人误解p是整型变量
if (p != 0)
或者
if (p) // 容易让人误解p是布尔变量
if (!p)

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

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

猜你喜欢

转载自blog.csdn.net/hu_junhua/article/details/79221601