iOS求职之C语言面试题
1.static有什么用途?(请至少说明两种)
1)限制变量的作用域
2)设置变量的存储域(堆,主动分配内存也是堆)
1)在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。
2.全局变量和局部变量在内存中是否有区别?如果有,是什么区别?
全局变量储存在静态数据库,局部变量在栈
3.堆栈溢出一般是由什么原因导致的?
堆栈溢出一般是循环的递归调用导致的,如果使用的大数据结构的局部变量,也可能导致堆栈溢出。没有回收垃圾资源导致的是内存泄露最后内存耗尽。
4.不能做switch()的参数类型是:
switch的参数不能为实型。(只能是int char)
5.写出float x 与“零值”比 较的if语句。
if(x<0.000001&&x>-0.000001)
6.在c语言库函数中将一个字符转换成整型的函数是atol()吗,这个函数的原型是什么?
函数名: atol
功能: 把字符串转换成长整型数
函数的原型: long atol(const char *nptr);
程序例:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
long l;
char *str = "98765432";
l = atol(lstr);
printf("string = %s integer = %ld\n", str, l);
return(0);
}
7.对于一个频繁使用的短小函数,在C语言中应用什么实现,在C++中应用什么实现?
c用宏定义,c++用inline
8.软件测试都有那些种类?
黑盒:针对系统功能的测试 白合:测试函数功能,各函数接口
9.确定模块的功能和模块的接口是在软件设计的那个阶段完成的?
概要设计阶段
10.unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问p1+5=? ;
p2+5=? ;
答:p1+5=0x801005 ;
p2+5=0x810014 ;
11.请问下面程序有什么错误?
int a[60][250][1000],i,j,k;
for(k=0;k<1000;k++)
for(j=0;j<250;j++)
for(i=0;i<60;i++)
a[i][j][k]=0;
把循环语句内外换一下
(编译的时候没错,运行的时候出错,但这个数组太大,如果放在栈中,还是会溢出,要作为全局变量)
12.#define Max_CB 500
void LmiQueryCSmd(Struct MSgCB * pmsg)
{
unsigned charucCmdNum;
......
for(ucCmdNum=0;ucCmdNum<Max_CB;ucCmdNum++)
{
......;
}
死循环(unsignedchar 0 到 255)
13.以下是求一个数的平方的程序,请找出错误:
#define SQUARE(a)((a)*(a))
int a=5;
int b;
b=SQUARE(a++);//a被加了2次 a=7,b=25
14.有一个16位的整数,每4位为一个数,写函数求他们的和。
解释:
整数1101010110110111
和 1101+0101+1011+0111
/* n就是16位的数,函数返回它的四个部分之和 */
char SumOfQuaters(unsigned short n)
{
char c = 0;
int i = 4;
do
{
c += n & 15;
n = n >> 4;
} while (--i);
return c;
}
15、两个字符串,s,t;把t字符串接到s字符串尾,s字符串有足够的空间存放t字符串
void connect(char *s, char *t, int i)
{
char *q =t;
char *p =s;
if(q ==NULL)return;
while(*p!='\0')
{
p++;
}
while(*q!=0)
{
*p=*q;
p++;
q++;
}
*p = '\0';
}
void main()
{
charp[7]="ABC";
charp2[]="EFG";
connect(p,p2,3);
printf("%s",p);
}
16、分析下面的代码:
char *a = "hello";
char *b = "hello";
if(a= =b)
printf("YES");
else
printf("NO");
常量字符串。位于静态存储区,它在程序生命期内恒定不变。如果编译器优化的话,会有可能a和b同时指向同一个hello的。则地址相同。如果编译器没有优化,那么就是两个不同的地址,则不同。对VC,是相同。
17、局部变量能否和全局变量重名?
答:能,局部会屏蔽全局。要用全局变量,需要使用"::" ;局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。
18、如何引用一个已经定义过的全局变量?
答:extern 例如在某个.cpp中定义了一个全局变量int a,可在头文件中加入extern a;然后在需要引用的文件中包含该头文件。或者直接在文件中加入 extern a;
19、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
答:可以
在头文件中用static来定义同名全局变量。
另外某个.C文件中定义的非静态全局变量,可以在其头文件中用extern声明,需引用此全局变量的其他.C只需包含此头文件即可。
20、请写出下列代码的输出内容
#include <stdio.h>
int main(void)
{
int a,b,c,d;
a=10;
b=a++;
c=++a;
d=10*a++;
printf("b,c,d:%d,%d,%d",b,c,d);
return 0;
}
答:10,12,120
21、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
答: 1) 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。
这两者的区别在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
2) 从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。
3) static函数与普通函数作用域不同,仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
综上所述:
static全局变量与普通的全局变量有什么区别:
static全局变量只初使化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:
static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:
static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
22、设有以下说明和定义:
typedef union
{
long i;
int k[5];//20
char c;
} DATE;
struct data
{
int cat; //4
DATE cow; //20
double dog;//8
} too;
DATE max;
则语句printf("%d",sizeof(struct data)+sizeof(max));的执行结果是:
考点:区别struct与union.(一般假定在32位机器上)
答:DATE是一个union, 变量公用空间. 里面最大的变量类型是int[5], 占用20个字节. 所以它的大小是20. data是一个struct, 每个变量分开占用空间. 依次为int4 + DATE20 + double8 = 32. 所以结果是 20 + 32 = 52.
23、请找出下面代码中的所有错误 (题目不错,值得一看)
说明:以下代码是把一个字符串倒序,如“abcd”倒序后变为“dcba”
#include"string.h"
main()
{
char*src="hello,world";
char* dest=NULL;
int len=strlen(src);
dest=(char*)malloc(len);
char* d=dest;
char* s=src[len];
while(len--!=0)
*d++=*s--;
printf("%s",dest);
return 0;
}
答:
方法1:一共有4个错误;
int main()
{
char* src ="hello,world";
int len = strlen(src);
char* dest =(char*)malloc(len+1);//要为分配一个空间
char* d =dest;
char* s =&src[len-1]; //指向最后一个字符
while( len--!= 0 )
*d++=*s--;
*d = 0; //尾部要加’\0’
printf("%sn",dest);
free(dest); // 使用完,应当释放空间,以免造成内存汇泄露
dest = NULL; //防止产生野指针
return 0;
}
方法2: (方法一需要额外的存储空间,效率不高.) 不错的想法
#include <stdio.h>
#include <string.h>
main()
{
charstr[]="hello,world";
intlen=strlen(str);
char t;
for(int i=0;i<len/2; i++)
{
t=str[i];
str[i]=str[len-i-1];//小心一点
str[len-i-1]=t;
}
printf("%s",str);
return 0;
}
24.Heap与stack的差别。
答:Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。
Stack空间有限,Heap是很大的自由存储区
C中的malloc函数分配的内存空间即在堆上,C++中对应的是new操作符。
程序在编译期对变量和函数分配内存都在栈上进行,且程序运行过程中函数调用时参数的传递也在栈上进行
// 1 2 4 8 16。。。
// 1 10 100 1000 1 0000
// 0 1 11 111 1111
25. 一语句实现x是否为2的若干次幂的判断
#define is2*n(x) ((x & (x - 1))? 0 :1)
int main(void)
{ int m = 512;
cout << ((m & (m - 1)) ? false: true) << endl;
//即当m中只有一位为1时,才为若干次幂值
//考试大提示:若有两个及以上1,则(m & (m - 1))不为0,输出0,表示不为2的若干次幂
return(0);
}
类比:x为2的若干次幂即表示x中1的位数为1,题目转化为求一个32位数中1的位数,如果为1,则表示该数为2的若干次幂 同理也可以利用此规则求一个32位数中1的位数, (m & (m -1)每次可用消除一个1,计算的次数即为1的个数!
26. 下述三个有什么区别?
char * const p;
char const * p
const char *p
解答:
char * const p; //常量指针,p的值不可以修改
char const * p;//指向常量的指针,指向的常量值不可以改
const char *p; //和char const *p
27. 解释下列输出结果
char str1[] = "abc";
char str2[] = "abc";
const char str3[] = "abc";
const char str4[] = "abc";
const char *str5 = "abc";
const char *str6 = "abc";
char *str7 = "abc";
char *str8 = "abc";
cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;
结果是:0 0 1 1
答:str1,str2,str3,str4是数组变量,它们有各自的内存空间;
而str5,str6,str7,str8是指针,它们指向相同的常量区域。节省内存。
28. 以下代码中的两个sizeof用法有问题吗?[C易]
#include <stdio.h>
#include"iostream.h"
void UpperCase( char str[] )// 将 str 中的小写字母转换成大写字母
{ int i;
for( i=0; i<sizeof(str)/sizeof(str[0]); ++i )//是指针的大小4,只循环了4次。数组做参数,会退化为指针。可改为strlen(str)
if( 'a'<=str[i] &&str[i]<='z' )
str[i] -= ('a'-'A' );//由小写转大写
}
void main()
{
char str[] = "aBcDefg";
cout << "str字符长度为: " <<sizeof(str)/sizeof(str[0]) << endl;//是数组的大小6
UpperCase( str );
cout << str << endl;
}
答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为8,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。
注意:数组名作为函数参数时,退化为指针.
数组名作为sizeof()参数时,数组名不退化,因为sizeof不是函数.
29. 一个32位的机器,该机器的指针是多少位 2^32 =4G
地址总线宽度决定了CPU可以访问的物理地址空间.简单地说就是CPU到底能够使用多大容量的内存.对于386以上的微机系统.地址线的宽度为32位.最多可以直接访问4096MB (4GB)的物理空间.对大多数人来说已经够用了.
指针是多少位只要看地址总线的位数就行了。80386以后的机子都是32的数据总线。所以指针的位数就是4个字节了。
8位处理器、16位处理器、32位处理器和64位处理器,其计数都是8的倍数。它表示一个时钟周期里,处理器处理的二进制代码数。“0”和“1”就是二进制代码,线路上有电信号,则计做1,没有电信号则为0。8位机有8条线路,每个时钟周期有8个电信号,组成一个字节。所以,随8位处理器上升至64位处理器,每个时钟周期传送1个字节到8个字节,关联到时钟速度提高到若干个千兆赫之后,处理器处理信息的能力越来越大。
CPU 的一次基本运算 (and, or, xor, not), 能处理/运算几个 bits. 64 bits data 交由 32-bit CPU 去运算, 得分两次才行.
30. 指出下面代码的输出,并解释为什么。(不错,对地址掌握的深入挖潜)
main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1);//指针是数组类型,+1相当于加20.如果是(a+1)是+4
printf(“%d %d”,a,ptr);
printf("%d,%d",*(a+1),*(ptr-1));
}
输出:12450361245056 2,5
a,&a的地址是一样的,但意思不一样,a是数组首地址,也就是a[0]的地址,&a是对象(数组)首地址,a+1是数组下一元素的地址,即a[1],&a+1是下一个对象的地址,即a[5].
31.请问以下代码有什么问题:
1).int main()
{
char a;
char *str=&a;
strcpy(str,"hello");
printf(str);
return 0;
}
答;没有为str分配内存空间,将会发生异常问题出在将一个字符串复制进一个字符变量指针所指地址。虽然可以正确输出结果,但因为越界进行内在读写而导致程序崩溃。
2).char* s="AAA";//常量的内容不能改,可定义为数组
printf("%s",s);
s[0]='B';
printf("%s",s);
有什么错?
答:"AAA"是字符串常量。s是指针,指向这个字符串常量,所以声明s的时候就有问题。
cosnt char* s="AAA";
然后又因为是常量,所以对是s[0]的赋值操作是不合法的。
32.用变量a给出下面的定义
a)一个整型数(An integer)
b) 一个指向整型数的指针(A pointer to an integer)
c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)
d) 一个有10个整型数的数组(An array of10 integers)
e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers)
f) 一个指向有10个整型数数组的指针(A pointerto an array of 10 integers)
g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as anargument and returns an integer)
h) 一个有10个函数指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take aninteger argument and return an integer )
答案是:
Int (*p[10])(int); a) int a; // Aninteger
b) int *a; // A pointer to an integer
c) int **a; // A pointer to apointer to an integer
d) int a[10]; // An array of 10integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // Apointer to an array of 10 integers
g) int (*a)(int);// A pointer to afunction a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of10 pointers to functions that take an integer argument and return an integer
33.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 *24 * 365)UL
34.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。
#defineMIN( A,B) ((A) <= (B) ?(A) :(B)) A <= B ?A : B
35.关键字static的作用是什么?
在C语言中,关键字static有三个明显的作用:
1). 在函数体,一个被声明为静态的全局变量在这一函数被调用过程中维持其值不变。(值的保存)
2). 在模块内(但在函数体外),一个被声明为静态的全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。(限制作用域)
3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。(限制作用域)
36.关键字const是什么含意?下面的声明都是什么意思?
1 const int a; 2 int const a;
3 const int *a; 4 int const * a;
5 int * consta; 6 int const * const a;
答:1、const inta; 2、int const a;
3、 4、内容不可变,指针可变: const int *a;
5、内容不可变,指针可变: int * const a;
6、内容可变,指针不可变 : intconst * const a;
37. 关键字volatile有什么含意 并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。
下面是volatile变量的几个例子:
1). 并行设备的硬件寄存器(如:状态寄存器)
2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3). 多线程应用中被几个任务共享的变量
39. int (*s[10])(int) 表示的是什么?
int (*s[10])(int) 函数指针数组,每个指针指向一个int func(int param)的函数。
40.有以下表达式:
int a=248; b=4;int const c=21;const int *d=&a;
int *const e=&b;int const int *const f=&a;
请问下列表达式哪些会被编译器禁止?为什么?
*c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;
答:*c 这是个什么东东,禁止
d=&b是很OK
e=34 不OK
e = &a 说了是const 禁止 e的地址不能改
const int *const f =&a; 禁止 f的内容和地址都不能改
41.交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;
答:有两种解法,一种用算术算法, 一种用^(异或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能对int,char..
b = a^b;
a = a^b;
2个bit (bit1与bit2异或,结果为0说明它们不同,则bit2异或0可把bit1还原。
结果为1说明它们相同,则bit2异或1可把bit1还原。
42.
#include <stdio.h>
#include <stdlib.h>
void getmemory(char *p)//函数的参数是局部变量,在这里给它分配内存还在,但是P释放了。
{
p=(char *) malloc(100);
}
int main( )
{
char *str=NULL;
getmemory(str);
strcpy(str,"helloworld");
printf("%s/n",str);
free(str);
return 0;
}
答: 程序崩溃,getmemory中的malloc 不能返回动态内存, free()对str操作很危险
解决方案1:可改为按引用传递:void getmemory(char *&p)
解决方案2:返回指针
Char* getmemory(char *p)
{
p=(char *)malloc(100);
return p;
}
43.char szstr[10];
strcpy(szstr,"0123456789");
产生什么结果?为什么?
答;正常输出,长度不一样,会造成非法的OS,覆盖别的内容.‘\0’没保存
44. c指针
int *p[n];-----指针数组,每个元素均为指向整型数据的指针。
int (*p)[n];------p为指向一维数组的指针,这个一维数组有n个整型数据。
int *p();----------函数带返回指针,指针指向返回的值。
int (*p)();------p为指向函数的指针。
45. 数组越界问题 (这个题目还是有点小险的)
下面这个程序执行后会有什么错误或者效果:
#define MAX 255
int main()
{
unsigned char A[MAX],i;
for (i=0;i<=MAX;i++)
A[i]=i;
}
解答:MAX=255,数组A的下标范围为:0..MAX-1,这是其一,其二当i循环到255时,循环内执行: A[255]=255;这句本身没有问题,但是返回for (i=0;i<=MAX;i++)语句时,由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.
注:char类型为一个字节,取值范围是[-128,127],unsigned char [0 ,255]
46. C++:memset ,memcpy 和strcpy 的根本区别?
答:#include"memory.h"
memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为' '或'';例:char a[100];memset(a, '', sizeof(a));
memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。
strcpy就只能拷贝字符串了,它遇到'\0'就结束拷贝;例:chara[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个'\0'之前)是否超过50位,如超过,则会造成b的内存地址溢出。
void main()
{
chara[100];
memset(a,'a', sizeof(a)-1);
memset(&a[99], '\0',1);
printf("%s\n",a);
charstr1[100]="abc";
charstr2[50]="efghdfkdjf";
memcpy(str1,str2, sizeof(str2));
printf("%s\n",str1);
strcpy(str1,str2);
printf("%s\n",str1);
}
strcpy 原型:
char *strcpy_su(char *dest,char *src)
{
assert((dest!=NULL)&&(src!=NULL));
char*address = dest;
while((*dest++=*src++)!='\0')
continue;
returnaddress;
}
用法:#include<string.h>
功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
memcpy原型:
void *memcpy_su(void *dest, void *src,unsigned int count)
{
assert((dest!=NULL)&&(src!=NULL));
char*bdest = (char*)dest;
char*bsrc = (char*) src;
while(count-->0)
*bdest++ = *bsrc++;
returndest;
}
用法:#include<memory.h>
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。
Memset原型:
原型:extern void*memset(void *buffer, char c, int count);
用法:#include
功能:把buffer所指内存区域的前count个字节设置成字符c。
说明:返回指向buffer的指针。
void *memset_su(void *buffer, int c, int count)
{
assert ((buffer!=NULL));
char* buffer2 = (char*)buffer;
while(count-->0)
*buffer2++ = c;
returnbuffer;
}
47. ASSERT()是干什么用的
答:ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常用来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。例如,变量n在程序中不应该为0,如果为0可能导致错误,你可以这样写程序:
......
ASSERT( n != 0);
k = 10/ n;
......
ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。
#include<stdio.h>
#include<assert.h>
void main()
{
int n=1;
assert( n != 0); //c c++中使用
//ASSERT( n != 0); //什么头文件?
printf("su\n");
}
48. 编写用C语言实现的求n阶阶乘问题的递归算法:
答:long intfact(int n)
{
If(n==0||n==1)
Return 1;
Else
Return n*fact(n-1);
}
49. 冒泡排序:
#include"stdio.h"
voidprintArr(int R[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",R[i]);
printf("\n");
}
void swap(int* a ,int * b)
{
int c=*a;
*a=*b;
*b=c;
}
//4 冒泡排序
voidmaopaoSort(int R[],int n)
{
for(int i=0;i<n-1;i++) // 需要冒泡的次数
{ /*
for(intj=0;j<n-1-i;j++) // // 每次需要比较的次数
{
if(R[j]>R[j+1]) //大的往下沉
{
swap(&R[j],&R[j+1]);
}
}
*/
for(int j=n-1;j>i;j--) // // 每次需要比较的次数
{
if(R[j]<R[j-1]) //小的往上冒
{
swap(&R[j],&R[j-1]);
}
}
}
}
void main()
{
int i;
int num[6]={0};
printf("Please input 6 numbers:\n");
for(i=0;i<6;i++)
scanf("%d",&num[i]);
puts("before sort:");
printArr(num,6);
maopaoSort(num,6);
puts("after sort:");
printArr(num,6);
}
50.再看看下面的一段程序有什么错误:
swap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
在swap函数中,p是一个“野”指针,有可能指向系统区,导致程序运行的崩溃。在VC++中DEBUG运行时提示错误“Access Violation”。该程序应该改为:
swap( int* p1,int* p2 )
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
51.分别给出BOOL,int,float,指针变量 与“零值”比较的if 语句(假设变量名为var)
解答:
BOOL型变量:if(!var)
int型变量: if(var==0)
float型变量:
const floatEPSINON = 0.00001;
if ((x >= -EPSINON) && (x <= EPSINON)
指针变量: if(NULL ==var)
52.以下为Windows NT下的32位C++程序,请计算sizeof的值
void Func ( char str[100] )
{
sizeof( str ) = ?
}
void *p = malloc( 100 );
sizeof ( p ) = ?
解答:
sizeof( str ) = 4
sizeof ( p ) = 4
剖析:
Func ( char str[100] )函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。
数组名的本质如下:
(1)数组名指代一种数据结构,这种数据结构就是数组;
例如:
char str[10];
cout << sizeof(str) << endl;
输出结果为10,str指代数据结构char[10]。
(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++; //编译出错,提示str不是左值
(3)数组名作为函数形参时,沦为普通指针。
Windows NT 32位平台下,指针的长度(占用内存的大小)为4字节,故sizeof( str ) 、sizeof ( p ) 都为4。
53.写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?
least = MIN(*p++, b);
解答:
#define MIN(A,B) ((A) <= (B) ? (A) :(B))
MIN(*p++, b)会产生宏的副作用
剖析:
(1)谨慎地将宏定义中的“参数”和整个宏用用括弧括起来。所以,严格地讲,下述解答:
#define MIN(A,B) (A) <= (B) ? (A) : (B)
#define MIN(A,B) (A <= B ? A : B )
#define MIN(A,B) ((A) <= (B) ? (A) :(B));
都应判0分;
(2)防止宏的副作用。
宏定义#defineMIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:
((*p++) <= (b) ? (*p++) : (b))
这个表达式会产生副作用,指针p会作2次++自增操作。
//”dfjdosfjkodskf” “dos” 1000 3
54.请编写能直接实现strstr()函数功能的代码。 // strstr(str,substr);在str中找substr,找到后把后面的全部截取返回。
#include <iostream>
using std::cout;
using std::endl;
char* my_strstr( char* str1, char* str2 )
{
if (NULL == str1 || NULL == str2)
{
throw;
}
char *p = NULL;
char *q = NULL;
const char v = '\0';
for (int i=0; v != str1[i]; ++i)
{
p = &str1[i];
q = str2;
while (v != *q && *q == *p)
{
++p; ++q;
}
if ('\0' == *q)
{
return &str1[i];
}
}
return NULL;
}
int main( void )
{ char a[] = "ok2002.com";
char* p = my_strstr( a, "com" );
if (NULL == p)
{
cout << "not find" << endl;
}
else {
cout << p << endl;
}
p = my_strstr( a, "2002" );
if (NULL == p)
{ cout << "not find" << endl; }
else {
cout << p << endl;
}
}
55.写一个函数,检查字符是否是整数,如果是,返回其整数值。(或者:怎样只用4行代码,编写出一个从字符串到长整形的函数?)
析 :扫描一遍,每次生成对应整数的最高位。一行也就搞定了!
//”1234”-à1*1000+2*100+3*10+4 ‘0’---‘9’“1234”1234
longconvert(char* s_string)
{
long s_integer=0;
for(int sLen = strlen(s_string),i = 0; i < sLen;s_integer += (s_string[i++] - '0')*pow(10,sLen - i - 1));
return s_integer;
}
12 21 23 34 15
56.对1,2,3, 4, 5 这五个数任意取出两个数,列出他们的所有组合。
void main()
{
char a[]={'1','2','3','4','5'};
for(int i=0;i<5-1;i++)
{
for(intj=i+1;j<5;j++)
if(a[i]!=a[j])
{
cout<<a[i]<<a[j]<<" ";
cout<<a[j]<<a[i]<<" ";
}
cout<<endl;
}
}
//12 21 13 31 1441 15 51
//23 32 24 42 2552
//34 43 35 53
//45 54
57 . 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 *24 * 365)UL
1) #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是怎么样计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3) 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
4) 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
58.
1). 一个参数既可以是const还可以是volatile吗?解释为什么。
2). 一个指针可以是volatile吗?解释为什么。
3). 下面的函数有什么错误:
int square(volatile int *ptr)
{
return (*ptr) * (*ptr);
}
下面是答案:
1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。
3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,
编译器将产生类似下面的代码:
int square(volatile int *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a *b;
}
由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr)
{
int a;
a = *ptr;
return a *a;
}
59. 嵌入式系统总是要用户对变量或寄存器进行位操作。给定一个整型变量a,写两段代码,第一个设置a的bit 3,
第二个清除a 的bit 3。在以上两个操作中,要保持其它位不变。
#define BIT3 (0x1<<3)
static int a;
void set_bit3(void)
{
a |= BIT3;
}
void clear_bit3(void)
{
a &=~BIT3;
}
访问固定的内存位置(Accessing fixed memorylocations) CC++ Development
60. 嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,
要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。
这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa66;
61. 中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。
具代表事实是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),
请评论一下这段代码的。
__interrupt double compute_area (double radius)
{
double area = PI * radius* radius;
printf(" Area =%f", area);
return area;
}
这个函数有太多的错误了,以至让人不知从何说起了:
1). ISR 不能返回一个值。如果你不懂这个,那么你不会被雇用的。
2). ISR 不能传递参数。如果你没有看到这一点,你被雇用的机会等同第一项。
3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,
有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。
4). 与第三点一脉相承,printf()经常有重入和性能上的问题。
62 . 下面的代码输出是什么,为什么?
Void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b > 6)?puts("> 6") : puts("<= 6");
}
这个问题测试你是否懂得C语言中的整数自动转换原则,我发现有些开发者懂得极少这些东西。不管如何,
这无符号整型问题的答案是输出是“>6”。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。
因此-20变成了一个非常大的正整数,所以该表达式计算出的结果大于6。
这一点对于应当频繁用到无符号数据类型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了得不到这份工作的边缘。
63. 评价下面的代码片断:
unsigned int zero = 0;
unsigned int compzero = 0XFFFF FFFF;
/*1's complement of zero */
对于一个int型不是16位的处理器为说,上面的代码是不正确的。应编写如下:
unsigned int compzero = ~0;
这一问题真正能揭露出应试者是否懂得处理器字长的重要性。在我的经验里,好的嵌入式程序员非常准确地明白硬件的细节和它的局限.