1.malloc函数进行动态、静态内存分配是在什么阶段?
程序占用三种类型的内存:静态内存、栈内存、堆内存。
静态内存:用来保存局部static、类static数据成员以及定义在任何函数之外的变量。
栈内存:定义函数内的非static对象。
分配在静态内存或者栈内存的对象由编译器自动创建和销毁。栈对象,只有定义的程序块运行时才存在。static静态内存在使用之前分配,在程序结束的时候销毁。
堆内存,在程序运行时分配,动态对象的生存周期由程序控制。
答:运行阶段和装载阶段。
2.未定义行为:
未定义行为(Undefined Behavior)是指C语言标准未做规定的行为。同时,标准也从没要求编译器判断未定义行为,所以这些行为有编译器自行处理,在不同的编译器可能会产生不同的结果,又或者如果程序调用未定义的行为,可能会成功编译,甚至一开始运行时没有错误,只会在另一个系统上,甚至是在另一个日期运行失败。当一个未定义行为的实例发生时,正如语言标准所说,“什么事情都可能发生”,也许什么都没有发生。一句话,未定义行为就是运行结果不确定
1.变量即是左边结果,又是右边的操作数,如a+=a++,a %= b ^= a ^= b ^= a
2.使用越界数组也是C的一个“未定义行为”
3.允许一个随便指的指针的读写。
4.使用未初始化的变量
int i=0; i=(i++);
char *p="hello"; p[1]='E';
char *p="hello"; char ch=*p++;
int i=0; printf("%d %d\n",i++,i--);
A-不知道编译器如何选择自增和幅值的顺序.
B.hello属于字符串常量,通过指针去修改这个常量,是错误行为。
C.虽然也是字符串常量,但是没有用指针去修改这个字符串常量。
D.i++和i--谁先运行由编译器决定.所以选C
3.普通的变量,不管是否声明为auto,都是自动型变量
简单介绍一下register变量:它是把变量存储在cpu中的寄存器中,当一个变量需要反复读写时,不需要反复的访问内存,而直接可以使用它,并且,register是一个建议型的关键字,编译器可能会因为变量不满足一定条件而放弃使用寄存器变量。一般情况下将局部自动变量和函数形参作为寄存器变量。
4.
16位平台,int 2个字节,指针2个字节
平常float 4个字节 double 8 个字节。
long 4个字节。
5.
int b[3][5];
int (*p)[5]=b;
定义一个指针,指向int类型的数组(5个元素) 让他等于数组名,数组名就是首行的首地址,正好5个元素。
int *p[2]={b[0],b[1],b[2]};
定义一个指针数组,数组里面存放的是指针,格式是没有错的,但是P的大小为2,存放了3个。
6.
extern "C" {
void foo(int) { }
}
extern "C"指令中的C,表示的一种编译和连接规约,而不是一种语言。C表示符合C语言的编译和连接规约的任何语言,如Fortran、assembler等。
7.
空指针是指可以确保没有指向任何一个对象的指针。通常使用宏定义NULL来表示空指针常量值。NULL就代表系统的0地址单元
空指针确保它和任何非空指针进行比较都不会相等,因此经常作为函数发生异常时的返回值使用。
8.
计算二进制的一的个数,这个算法叫做平行算法。
int BitCount(unsigned int n)
{
n = (n &0x55555555) + ((n >>1) &0x55555555) ;
n = (n &0x33333333) + ((n >>2) &0x33333333) ;
n = (n &0x0f0f0f0f) + ((n >>4) &0x0f0f0f0f) ;
n = (n &0x00ff00ff) + ((n >>8) &0x00ff00ff) ;
n = (n &0x0000ffff) + ((n >>16) &0x0000ffff) ;
return n ;
}
速度不一定最快,但是想法绝对巧妙。 说一下其中奥妙,其实很简单,先将n写成二进制形式,然后相邻位相加,重复这个过程,直到只剩下一位。
9.
1> malloc,作用是开辟一个给定字节大小的堆区域空间,并且返回该内存空间的首地址。
void *malloc(unsigned int size);因此A项正确。
2> calloc,作用是分配n个size⼤⼩的空间,并且把该内存上的所有字节清零。
void *calloc(unsigned n,unsigned size);
3> realloc,作用是按给定的地址以及给定的⼤小重新分配。
void *realloc(void *, unsigned newSize);
分配时有两种情况:
1.如果原有空间地址后面还有足够的空闲空间用来分配,则将先前空间释放,然后以先前地址为开始地址按newSize大小重新分配。因此B项正确。
2.如果原有空间地址后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize⼤小的内存,并把先前内存空间中的数据复制到新的newSize⼤小的空间中,然后将之前空间释放。因此C项正确。
4> free函数,作用是释放内存,内存释放是标记删除, 只会修改当前空间的所属状态,并不会清除空间内容。free函数并不会清除空间内容。因此D项描述错误。
10.
对于inline 和宏的比较:内联函数比宏更安全,前者会有类型检查,后者只是代码的简单替换;
inline:在编译时,把函数代码直接插入到目标代码中,通过空间换取时间来提高执行效率;不存在普通函数的调用开销(现场的保护,数据的保存)。
11.重载是编译时确定的,虚函数是运行时绑定的;
12.
#include<stdio.h>
struct str_t{
long long len;
char data[32];
};
struct data1_t{
long long len;
int data[2];
};
struct data2_t{
long long len;
char *data[1];
};
struct data3_t{
long long len;
void *data[];
};
int main(void)
{
struct str_t str;
memset((void*)&str,0,sizeof(struct str_t));
str.len=sizeof(struct str_t)-sizeof(int);
snprintf(str.data,str.len,"hello");//VS下为_snprintf
____________________________________;
____________________________________;
return 0;
}
struct data3_t *pData = (struct data3_t*) &str;
printf("data:%s%s\n", str.data, (char*) (&(pData->data[0])));
struct data2_t *pData = (struct data2_t*) &str;
printf("data:%s%s\n", str.data, (char*) (pData->data[0]));
struct data1_t *pData = (struct data1_t*) &str;
printf("data:%s%s\n", str.data, (char*) (pData->data));
struct str_t *pData = (struct str_t*) &str;
printf("data:%s%s\n", str.data, (char*) (pData->data));
此时pData->data[0]不是数组的地址,而是数组的第一个元素。而我们如果想要打印这个字符串,必须需要得到h的地址。
13.
定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数。则下面定义正确的是()
int (*(*F)(int, int))(int)
int (*F)(int, int)
int (*(*F)(int, int))
*(*F)(int, int)(int)
针对A. 先看优先级最高的,即内部括号(*F),看出F是一个指针,然后再看右边(int , int),说明它是一个函数指针,(int,int)为此函数的形参列表.(* (*F)(int, int) ) .再往外看, (*F)(int, int) 括号外面* 表示这又是一个指针,而且去掉这一部分剩下
int (*)(int)
这是一个典型的函数指针, 参数int ,返回值int. 那就是说 函数指针F 指向的函数(函数1) 有两个int,然后这个函数(函数1) 返回值 又是一个函数指针,这个函数指针的原型函数(函数2)是int fun(int).
其实本质就是函数指针 指向 一个 返回函数指针的函数
14.表达式(short)10/10.2*2运算后结果类型是()double 编译器默认浮点型为double而不是float
15.
由printf输出的数据都隐含左对齐 ----左对齐
scanf和printf是C语言提供的输入和输出语句 ----是库函数而不是输入输出语句
赋值语句是一种执行语句,必须放在函数的可执行部分或全局区域----函数头大括号函数体三部分,函数体是可执行部分。
由printf输出的数据的实际精度是由格式控制中的域宽和小数的域宽来完全决定的----还取决于数据在内存中存储精度的影响。
16.
void GetMemory(char *p) { p = (char *)malloc(100); }
void Test(void) {
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
GetMemory里,P是形参,没有办法把malloc的指针返回给主函数,此时str仍然是NULL
执行strcpy(str,'hello world') 就会出错。
17.csh:调用 C shell。
Tcsh是csh的增强版,并且完全兼容csh。它不但具有csh的全部功能,还具有命令行编辑、拼写校正、可编程字符集、历史纪录、 作业控制 等功能,以及C语言风格的语法结构。
AWK 是一种优良的文本处理工具, Linux 及 Unix 环境中现有的功能最强大的数据处理引擎之一, AWK 提供了极其强大的功能:可以进行样式装入、 流控制 、数学 运算符 、进程 控制语句 甚至于内置的变量和函数。
SED: Stream EDitor AWK具有很多C语言功能,又称为过滤器.
18.鼠标-双击即点击左键两下,第一次触发LBUTTONDOWN和LBUTTONUP,第二次点击时触发双击事件LBUTTONDBLCLK(doubleclick),放掉再触发LBUTTONUP
19.
#include<stdio.h>
void main() {
char s[] = "\\123456\123456\t";
printf("%d\n", strlen(s));
}
strlen() 函数用于获取字符串的长度(即字符串中字符的个数,不包括\0)。\\、\123、\t是转义字符。所以长度是 12。
\\ 表示单个字符\
\123 表示八进制的ASCII码值为123对应的字符
\t 表示制表符
数字的0-9对应ASCII码的48-57
大写字母的A-Z对应ASCII码的65-90
小写字母的a-z对应ASCII码的97-122
20.
除了类属关系运算符"."、成员指针运算符".*"、作用域运算符"::"、sizeof运算符和三目运算符"?:"以外,C++中的所有运算符都可以重载
但是=、()、[]、->这四个不能重载为类的友元函数。
21.在定义char* s="AAA";时,表示定义了一个指针s,其指向的地址是常量区"AAA"的地址,此时如果想修改*s就是在试图修改常量"AAA",显然这是违法的;如果定义成char s[]="AAA";此时相当于创建了一个副本,其值为"AAA",不再是常量,可以通过s[i] = ***;修改"AAA"的值。
22.
int k, a, b;
unsigned int w = 5;
double x = 1.42;
x%3
w+=-20
k=(a=200,b=300)
a+=a-=a=9
A的错误:取余必须两边都是整数。
B.没错等于W=W+-20.unsigned int 没有负数会出错么?
C.括号中逗号表达式的值为最后一个表达式的值.
D.+=和-=和=都是同一优先级,都是右结合的.可以等效为a+=(a-=(a=9)) 输出为0
23.引用的格式int &q = x; 引用就是别名,代表x但是它与X有一点不同,x作为变量它的地址是可以修改的,而对引用q++是非法的.
24.
内存对齐规定:结构体的总大小为结构体最宽基本类型成员大小的整数倍
可见最宽的是float是4.,数组的形式只是多个数据放在一起而已。
联合体里面总共是5个字节,要为4的倍数所以为8个字节,
所以为8+8+4=20
若int 占 2 个字节, char 占 1 个字节, float 占 4 个字节, sizeof(xc) 大小是:
复制代码
struct stu {
union{
char bj[5];
int bh[2];
} _class;
char xm[8];
float cj;
}xc;
24.
union dt {
int a;
char b;
double c;
} data;
程序段:data.a=5;printf("%f\n",data.c);输出结果为5.000000
执行“data.a=5;printf(“%f\n”,data.C);”printf函数只是将内存中的数据以不同的类型输出,而不能将内存中的整型数据自动转换为等值的浮点数,故C是错误的。
在内存中,实数与整数的存放形式完全不一样,共用体的成员共用的是同一块内存,而不是同一个数值,因此选项C是错误的。
25.
std::vector<char> v{'1', '2', '3', '4'};
// A
v.push_back('5');
// B
预先分配的capacity是4.push_back会调整vector数组大小。如果size超过了预先分配的capacity会重新分配一块增大了的内存(可能是原先的一半)把数据复制到新地址,释放旧地址,所以起点可能会不一样
26.
通过指针调用函数的两种形式:
1、ret = (*p)();
2、ret = p();
对函数指针赋值的两种形式:
1、pf = &func;
2、pf = func;
char fun(char *);
main() { char *s = "one", a[5] = {0}, (*f1)(char *) = fun, ch; }
*f1(&a);
f1(*s);
f1(&ch);
ch = *f1(s);要改成(*f1)(s)才正确
B是错误的,因为函数fun需要的是char *的参数,而*s传进去的是字符串char类型,而不是char*类型。(指针),所以我们需要传入外层的一个char的地址,或者应该写成f1(s);就对了
按照前面函数指针的调用方式,CD是对的。
1.
进程同步
进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。
比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图所示。
进程互斥
进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图所示。
进程同步
进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。
比如说进程A需要从缓冲区读取进程B产生的信息,当缓冲区为空时,进程B因为读取不到信息而被阻塞。而当进程A产生信息放入缓冲区时,进程B才会被唤醒。概念如图所示。
进程互斥
进程互斥是进程之间的间接制约关系。当一个进程进入临界区使用临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
比如进程B需要访问打印机,但此时进程A占有了打印机,进程B会被阻塞,直到进程A释放了打印机资源,进程B才可以继续执行。概念如图所示。
直接制约-进程同步-进程B需要的就是进程A能给.
间接制约-进程互斥-进程B需要的不是进程A能给,而是某些临界资源。
2.分时系统的特征:同时性、独立性、及时性、交互作用性。
3.多个进程怎样共享一个监听端口?
使用fork共享
每个进程都使用SO_REUSEADDR选项,然后绑定同一个端口---SO_REUSEADDR是setsockopt的参数,使端口被释放后立即可以再使用。
4.作业管理主要是是CPU利用最大化。
虚拟存储虚拟存储器. 实际上是一种逻辑存储器,实质是对物理存储设备进行逻辑化的处理,并将统一的逻辑视图呈现给用户。
文件系统是对文件存储器的存储空间进行组织,分配和回收,负责文件的存储,检索,共享和保护。
5.linux文件系统将文件索引节点号和文件名同时保存在目录中。 所以,目录只是将文件的名称和它的索引节点号结合在一起的一张表,目录中每一对文件名称和索引节点号称为一个连接。对于一个文件来说有唯一的索引节点号与之对应,对于一个索引节点号,却可以有多个文件名与之对应。因此,在磁盘上的同一个文件可以通过不同的路径去访问它。
6.
链接文件不适合随机存取。链式存储结构,又叫链接存储结构。在计算机中用一组任意的 存储单元 存储线性表的 数据元素 (这组存储单元可以是连续的 , 也可以是不连续的 ). 它不要求逻辑上相邻的元素在物理位置上也相邻 . 因此它没有 顺序存储结构 所具有的弱点, 但也同时失去了 顺序表 可 随机存取 的优点.
举个栗子: 数组在内存中是按顺序存放的,可以通过下标直接定位到某一个元素,这是随机存到
链表在内存中不是按顺序存放的,而是通过指针连在一起,为了访问某一元素,必须从链头开始顺着指针才能找到某一个元素,是顺序存取
D.对于软链接。链接文件其实是路径信息, 而不是索引节点。对于硬链接,链接文件应该也是文件,索引节点只不过指向这个文件而已。
个人观点,欢迎指正。
7."位示图"可用于管理页式存储管理中的主存空间、磁盘空间的分配和回收。
8.计算机工作运行原理:CPU分为控制器和运算器。控制器又有:指令寄存器,指令译码器,操作控制器
控制器根据用户预先编好的程序,依次从存储器中取出各条指令,放在指令寄存器IR中,通过指令译码(分析)确定应该进行什么操作,然后通过操作控制器OC按确定的时序,向相应的部件发出微操作控制信号。
- CPU,是一个集成多功能的部件。控制器仅可以作为其中的一部分,也可以安装于CPU外部。而一般集成CPU除了控制器还兼顾运算器(算术、逻辑,以及移位循环)等其他功能,功能范围比较广,与题目中的“总是处于...”不相符。所以B不符合。
- 指令存储器,仅存放正在执行的指令。所以C错误。
- 指令译码器,仅分析指令的操作码是什么,以决定操作的性质和方法,然后控制计算机其他各部件协同完成指令表达的功能。所以D错误。
9.在 UNIX 中,文件系统和设备驱动程序之间的接口是( )设备开关表
10.
进程具有以下特性:
1结构性 每个进程有一个控制块 PCB。
2.动态性 进程的实质是进程实体的一次执行过程。动态性是进程的最基本的特征。
3.并发性 可以与其它进程一道在宏观上同时向前推进。动态性是进程的重要特征。
4.独立性 进程是一个能独立运行 独立分配资源和独立调度的基本单位。
5.异步性 每个进程都以其相对独立、不可预知的速度向前推进。
11.进程被抢占时需要保存:所有CPU寄存器、页表、程序计数器。每一个进程都有一个属于自己的页表。页表里含有存放逻辑页和物理页的对应关系。