您的位置:首页 > 运维架构 > Linux

西邮linux兴趣小组2015纳新试题之我的解读

2015-05-02 15:01 92 查看
PS:事先申明,博主今年大一,还算是个初学者吧,要是有什么错误欢迎各位看官指正,谢谢!

西邮Linux兴趣小组 2015纳新试题

*注:1.本试题仅作为面试时的有限参考 2.为节省版面空间,省去所有的#include指令 3.环境假设为x86架构32位操作系统下 4.题目难度与序号无关

15.

1. 解释下面程序的输出结果:
int main(int argc, char *argv[])

{

int c;

memcpy(&c, "linux", 4);

printf("%d\n", c);

return 0;

}
在ubuntu 14.10 gcc version 4.9.1系统运行结果为:
1970170220
我想了一下,把linu的ascii码转成二进制,存到c的地址中,组成32位二进制码,但是计算出的整数值是18188488885。

其实这道题博主也没搞明白,本以为结果是一些ASCII码来着,要是有大神知道这道题的答案,博主将非常欢迎你的分享。

2.解释下面程序的运行结果,并总结 static 的用法
int *func()

{

static int a = 1;

a++;

return &a;

}

int main(int argc, char *argv[])

{

int *b;

b = func();

printf("%d\n", *b);

b = func();

printf("%d\n", *b);

return 0;

}

运行结果为:
2
3

首先在main函数中,定义了int型指针b,在func函数中,a为static整型变量,初值为1,自增后将其地址返回给main函数中的b,此时*b=2,再次进入func函数,由于a是
static型变量,所以其值为2,再次自增后将地址返回给main函数中的b,此时*b=3.

static用法小结(摘自网络)

static关键字是C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种只指在C语言中使用, 第三种在C++中使用

(1)局部静态变量

(2)外部静态变量/函数

(3)静态数据成员/成员函数

一、局部静态变量

在C/C++中, 局部变量按照存储形式可分为三种auto, static, register

1. static分配在静态存储区, 在程序整个运行期间都不释放.

2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次

3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符.

特点: static局部变量的”记忆性”与生存期的”全局性”

所谓“记忆性”是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值.

应用:利用"记忆性”, 记录函数调用的次数;利用生存期的”全局性”, 延长变量的生存期.

注意事项:

1. “记忆性”, 程序运行很重要的一点就是可重复性, 而static变量的”记忆性”破坏了这种可重复性, 造成不同时刻至运行的结果可能不同.

2. “生存期”全局性和唯一性. 普通的本地变量的存储空间分配在stack上, 因此每次调用函数时, 分配的空间都可能不一样, 而static具有全局唯一性的特点, 每次调用时, 都指向同一块内存, 这就造成一个很重要的问题 ---- 不可重入性!!!

二、外部静态变量/函数

在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。,但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.

使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。

3.解释程序的运行结果:
void func(char *a)
{
printf("%lu\n", sizeof(a));

printf("%lu\n", strlen(a));

}
int main(int argc, char *argv[])
{
char a[] = "hello world";

func(a);

printf("%lu\n", sizeof(a));

printf("%lu\n", strlen(a));

return 0;

}
运行结果为:
4
11
12
11

在main函数中定义了字符数组a,将a的地址传给func函数,在func函数中a为字符型指针,sizeof(a)表示字符型指针a的大小,在32bit系统中为4bytes,strlen(a)则表示字
符串a的长度,即为11(不包括’\0’),返回main函数,sizeof(a)表示字符数组a的大小,为12bytes(包括’\0’),strlen(a)表示字符串a的长度,同func函数。

4.解释该函数的输出结果:
void func(void)

{

unsigned int a = 6 ;

int b = -20 ;

(a+b>6) ? puts(“>6”) : puts(“<6”);

}

运行结果为:
>6

在32bit系统中
unsignedint大小为4bytes,int为4bytes,
6以二进制无符号整数表示为
0000…00000110
-20以二进制有符号整数表示为
1111…11101100
由于unsignedint变量与int变量进行运算时,会将int变量转换为unsignedint变量,所以1111…11101100将表示一个非常大的整数,所以a+b>6.

5.请解释什么是预编译,何时需要进行预编译。

预编译又称为预处理,是做些代码文本的替换工作。

处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等。

就是为编译做的预备工作的阶段,主要处理#开始的预编译指令。

6.阅读以下代码:
int main(int argc, char *argv[])
{
int a[3][4];
printf("%p%p%p%p%p%p\n", &a[0][0], a[0],
a, a[0]+1, a+1, a[1]);
return 0;
}
若 a[0][0]的地址为 0x00000000,求程序输出的结果:

理论运行结果为:
0x00000000
0x00000000
0x00000000
0x00000004
0x00000010
0x00000010

&a[0][0],a[0]和a的地址相同,为二维数组a第一行第一列元素的地址,a[0]+1指的是第一行第二列的元素,所以增加了4bytes(1个int元素),a+1指a以一行为单位+1,
即指的是第二行第一列元素的地址,所以增加了12bytes(3个int元素),a[1]则直接指的是第二行第一列元素的地址。

7.下列结构体在内存中所占空间大小分别是多少?
struct node

{

int x;
char y;
double z;
};
struct node

{
int x ;

double y ;

char z ;

};

暂时将第一个结构体重命名为node1,第二个为node2。
根据内存边界对其规则,每个特定平台上的编译器都有自己的默认“对其系数”,可以通过#pragmapack(n),n=1,2,4,8,16改变这一系数。
在我的电脑上(Ubuntu14.10 64bit,gccversion 4.9.1)这一系数的值为8,所以node1中,int和char实际共占8bytes,double占8bytes,所以一共为16bytes,在node2
中,int实际占8bytes,double占8bytes,char实际占8bytes,所以一共为24字节。
8.解释程序的运行结果:

#define f(a,b) a##b

#define g(a) #a

#define h(a) g(a)

int main(int argc, char *argv[])

{

printf( "%s\n", h(f(1,2)) );

printf( "%s\n", g(f(1,2)) );

return 0;

}
运行结果为:
12
f(1,2)

#definef(a,b) a##b
中,##将左右两边的参数做整体的字符串拼接替换,#defineg(a) #a
中,#将右边的参数做整体的字符串替换。
对于h(f(1,2)),由于h(a)是非#或##的普通宏,需要先宏展开其参数a,即展开f(1,2)为12,则h(a)宏替换为h(12),进而宏替换为g(12),进而宏替换为12。
对于g(f(1,2)),在#defineg(a)
#a中,#的参数即便是另一个宏,也不展开,仍然作为字符串字面信息输出,所以为f(1,2)。

9. 请解释当 i 的值分为为 1,2 和 3 时,程序的运
行结果
switch( i )
{
case 1:
printf(“I’m case1\n”);
break ;
default:
printf(“I’m default\n”);
case 2:
printf(“I’m case2\n”);
}
当i=1,执行case1,打印I’mcase1,遇到break后直接跳出switch语句;当i=2,执行case2,打印I’mcase2,之后没有语句可以执行,便退出switch;当i=3,执行
default,打印I’mdefault,由于没有break,程序继续执行,打印I’mcase2后退出switch。

10.这三个指针有什么区别?
int a = 3;
const int *p1;
int const *p2;
int * const p3 = &a;
对于inta = 3,声明一个int型变量a,其地址所指的内存中存放一个3。
对于constint *p1和intconst
*p2,其指针所指向的对象是只读的。
对于int* const p3 = &a,取a的地址后赋给p3,p3是只读的指针。

11.要求不更改以下代码语句的顺序,修改程序使其通过编译能够运行。

void func()
{
printf("a = %d\n", a);
}
int a=10;
int main()
{
func();
return 0;
}
更改后为:

voidfunc(int a)
{
Printf(“a= %d\n”, a);
}
inta = 10;
intmain()
{
func(a);
return0;
}

12.解释程序的运行结果:
int main(int argc, char *argv[])
{
int a[5]={1, 2, 3, 4, 5};
int *ptr=(int *)(&a+1);
printf("%d,%d", *(a+1), *(ptr-1));
return 0;
}

运行结果为:
2,5
(&a+1)取数组a的地址(即第一个元素的地址),以整个数组为单位+1,即元素a[5]后的地址(此处与(*a+1)不同),并将其赋给ptr,(ptr-1)则为指向数组最后一个元素的地址,所以*(ptr-1)=
5;*(a+1)
中,a为数组第一个元素的地址,a+1为第二个元素的地址,所以*(a+1)=
2。

13. 解释程序的运行结果:
int main(int argc, char *argv[])
{
char *str1 = "WelcomeTo\0XiyouLinux\n";
char str2[] = "WelcomeTo\0XiyouLinux\n";
printf("%d\n", printf("%s", str1));
printf("%d,%d\n", strlen(str1), strlen(str2));
printf("%d,%d\n", sizeof(str1), sizeof(str2));
return 0 ;
}
运行结果为:
WelcomeTo
9,9
4,22

printf打印字符串str1,遇‘\0’结束,strlen将str1和str2以字符串形式处理,并遇‘\0’结束,所以strlen(str1)=strlen(str2)=9,str1为char*变量,在32bit
系统中大小为4bytes,所以sizeof(str1)= 4,str2为数组
指针,所以sizeof(str2)=22(包括‘\0’,‘\n’和结尾的‘\0’)。

14. 实现一个函数,该函数将字符串中的字符'*'移到串的前部分,前面的非'*'字符后移,但不能改变非'*'字符的先后顺序。函数返回串中'*'的数量。如:输入串:ab**cd**e*12,输出串:*****abcde12,函数返回值为 5。

intpartitionStar(char a[],int len)
{

intcount = 0;

int i = len-1;

int j = len-1;

while (i >=0) {

if (a[i] != '*') {

swap(a[i--], a[j--]);

}else {

i--;

count++;

}

}

return count;

}

15.请编写 my_strcpy 函数,实现与库函数 strcpy类似的功能,不能使用任何库函数

char* strcpy( char *strDest, const char *strSrc )

{

if (strDest== strSrc) {

returnstrDest;
}

assert( (strDest != NULL) && (strSrc != NULL) );

char *address = strDest;

while( (*strDest++ = * strSrc++) !='/0' );

return address;

}
16.你知道下面的语句吗?它们做了什么?
#ifndef
_MY_FILE

#define _MY_FILE

你还知道哪些类似的语句?

如果未定义_MY_FILE
那么就定义_MY_FILE
#ifndef指令可以与#else,#endif指令一起使用,#ifndef判断后面的标识符是否为未定义的,通常用来定义此前未定义的常量

#ifdef指令,如果预处理器已经定义了后面的标识符,那么执行所有指令并编译C代码,直到下一个#else或#endif出现为止(无论#else和#endif谁先出现)。
#if和#elif指令
#if指令更像常规C中的if,#if后跟常量整数表达式,可以使用#elif指令扩展序列(类似ifelse)。

17.下面的程序有什么问题?
int main(int argc, char *argv[])
{
FILE *fp = fopen(“a.txt”, “r”);
char buffer[4096] ;
fgets(buffer, sizeof(buffer), fp);
fprintf(fp, “%s”, buffer);
return 0 ;
}

未检查fopen是否返回NULL;
“r”为只读模式,应该使用“a+”或“r+”;
使用sizeof(buffer)代表字符数会将4096个字符读入buffer,然而没有剩余空间储存“\0”,这时buffer不会是字符串,fprintf中“%s”则不能使用;
未使用fclose关闭文件,并检查文件是否成功关闭。

18.下面的程序在做什么?

int COMPARE(int middle, int key)
{
if(0 > middle–key) {
return -1 ;
}
else if(0 < middle–key) {
return 1 ;
}
else {
return 0 ;
}
}
int binarySearch(const int list[], int key, int length)
{
int left = 0, right = length-1, middle;
while( left <= right )
{
middle = (right–left) / 2 + left ;
switch( COMPARE(list[middle], key))
{
case -1: left = middle +1; break ;
case 0: return middle;
case 1: right = middle-1;

}

}
return -1 ;

}

二分法检索,只有当数组中的元素从小到大有序排列才能使用
19.下面这段程序有错吗?如果有错请指出并改正:
void func(char *p)
{
p = (char*)malloc( sizeof(char) );
}
int main(int argc, char *argv[])
{
char *s = NULL;
func(s);
strcpy(s, “i love xiyou_linux”);
puts(s);
return 0;
}
func函数中没有返回p的地址;main函数中没有变量接收func函数传递的值;没有释放通过malloc申请的内存。
20. 如何理解本张试卷中所出现的
“int main( int argc, char *argv[] )”?
请谈一谈你所理解的 main 函数。
用来接收命令行参数,intmain(int argc, char *argv[])中,argc是argumentcount的缩写,表示参数的个数,argv是argumentvalue的缩写,表示参数的值,argv是一个字符指针数组,每一个元素指向一个字
符串,其中argv[0]指向程序的路径名,argv[1]指向第一个参数字符串。
main函数即主函数,程序由main函数开始运行并由main函数结束,main函数可以调用任何函数,但任何函数都不能调用main函数,可以把程序比作做菜,main函数就是炒菜的过程,其他函数便是“买菜”
“洗菜”“切菜”等过程。
(排版的话先凑合一下吧!!以上便是全部了That's all !!)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: