国嵌唐老师(22134670) 21:08:48

编写一个函数,该函数的参数是一个长整型数,返回值是长整型,且函数的返回值是参数中各个十进制位的从大到小排序的整数(性能要求:以最少的空间和时间完成)。

如:

原型:long f(long n);

调用: long num = f(1302181);

函数返回后num的值为8321110

国嵌唐老师(22134670) 21:15:48

对于笔试 大家可以先考虑如何实现 再考虑如何快速实现 否则就只有交白卷

国嵌唐老师(22134670) 21:24:05

主要思想:十进制数的每一位出现的数字只可能为09,因此可以先统计各个位上的数字出现的次数,然后根据这些统计信息重新组合为一个符合要求的十进制数返回。

国嵌唐老师(22134670) 21:39:41

咱们再来一个面试题 练练手

下面程序的输出结果是什么?为什么?

#include <stdio.h>

int main()

{

int i = 0;

int a[5];

for( ;i<=5; i++)

{

a[i] = -1;

printf("%d %d \n",i,a[i]);

}

return 0;

}

答案:会陷进死循环

个人理解,首先,数据的定义把定义的数据一个一个压入栈中,然后再压入 int i在栈中, 数据紧邻a的偏移位置,a+5;使得访问时,a[5] 的空间正好是i 的空间,此时,i= -1i=-1;即开始循环,最终又到这个位置,变成了死循环,

单步调试测验:

数据是依次压入栈中的,把i放在数组后面便访问不到,而变成越界出错,同时可以得出结论,数组的空间访问权限,在一个代码块中可以有权限的话,即使数组越界也不宜擦觉,慎用指针,控制好访问有助于减少程序的错误 例 :

int a[5];

int i = 0;

for( ;i <= 5; i++)

{

a[i] = -1;

printf("%d %d\n",i,a[i]);

}

2 已经超出了了几个访问的单位,,权限的慎用

#include <stdio.h>

int main()

{

int k = 7;

int i = 0;

int a[5];

int j = 90;

for( ;i <= 7; i++)

{

a[i] = -2;

printf("%d %d\n",i,a[i]);

}

return 0;

}

国嵌唐老师(22134670) 21:47:27

哈哈 出了什么事 好玩不

相信大家一眼就可以看出本题的主要问题是数组a只有5个元素,访问其元素的下标分别是01234。当循环变量i的值为5的时候将访问a[5],这个时候产生了一个数组越界的错误。但问题是,为什么会产生死循环,当i的值为5的时候,程序究竟做了什么?在C语言中产生死循环只有一个原因,就是循环条件一直为真。在本题中也就是i<=5将一直成立。可问题是,循环变量i在每次循环结束后都做了i++。理论上,不可能产生死循环。为了弄清楚问题的本质,我们先弄清楚a[5]究竟代表什么?在Ca[5]其实等价于*(a+5),也就是说当i的值为5的时候,将对a+5这个内存空间进行赋值。很不幸,在本题中a+5这个内存空间正好就是i的地址,也就是说当i的值为5的时候,在for循环中的赋值语句其实等价于i=-i,即将i赋值为-5,因此i<=5永远无法满足。更进一步,为什么i正好在a+5这个位置呢?

胡飞(858523704) 21:51:18

i 和 数组都是在栈上分配的空间 挨在一起了

陈齐(714335388)21:51:19

就是进入函数之后参数的压栈操作

国嵌唐老师(22134670)21:52:38

我们都知道在C语言中,每次函数调用都会使用掉一部分的栈空间,且函数返回后会自动释放掉这部分栈空间。那这些栈空间拿来干什么用呢?局部变量!C语言中的局部变量是在栈空间自动分配的,也就是说函数调用的时候所使用的栈空间就是用于创建局部变量的。

国嵌唐老师(22134670) 21:53:14

因此我们可以改写一下程序:

#include <stdio.h>

int main()

{

int i = 0;

int a[5];

for( ;i<5; i++)

{

printf("a+%d = %0x\n",i,&a[i]);

}

printf("i = %0x\n",&i);

return 0;

}

国嵌唐老师(22134670)21:53:44

大家运行这个程序 看看结果

国嵌唐老师(22134670)21:55:21 一个可能的结果如下

从运行结果可以知道:局部变量i确实紧跟着数组中的第4个元素a[4]在栈上分配空间,因此a[5]就是i

国嵌唐老师(22134670) 20:56:18

下一个题

阅读下面函数的实现,确定fn(200)的返回值。

int fn(int n)

{

int ret = 0;

while(n)

{

ret++;

n = n & (n-1);

}

return ret;

}

国嵌唐老师(22134670) 21:03:42

想要快速确定fn(200)的返回值必须首先搞清楚该函数的核心行 n = n & (n - 1)的意义。

我们都知道在计算机的世界里任何数字都是以二进制的形式来表示的,那么从二进制的角度我们就可以得到下面的规律:

任意二进制数减1等价于把这个二进制数最低位的10,然后将这位后的所有01

所以这个函数就是确定实参的二进制表示中1的个数而已了