3.内功题
解答:
剖析:
void Func ( char str[100] )
{
sizeof( str ) = ?
}
解答:
剖析:
Func ( char str[100] )函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。
数组名的本质如下:
(1)数组名指代一种数据结构,这种数据结构就是数组;
例如:
char str[10];
cout << sizeof(str) << endl;
输出结果为10,str指代数据结构char[10]。
(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++; //编译出错,提示str不是左值
(3)数组名作为函数形参时,沦为普通指针。
试题3:写一个“标准”宏MIN,这个宏输入两个参数并返回较小的一个。另外,当你写下面的代码时会发生什么事?
least = MIN(*p++, b);
解答:
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
MIN(*p++, b)会产生宏的副作用
剖析:
#define MIN(A,B) (A) <= (B) ? (A) : (B)
#define MIN(A,B) (A <= B ? A : B )
都应判0分;
宏定义#define MIN(A,B) ((A) <= (B) ? (A) : (B))对MIN(*p++, b)的作用结果是:
((*p++) <= (b) ? (*p++) : (*p++))
除此之外,另一个应该判0分的解答是:
#define MIN(A,B) ((A) <= (B) ? (A) : (B));
这个解答在宏定义的后面加“;”,显示编写者对宏的概念模糊不清,只能被无情地判0分并被面试官淘汰。
试题4:为什么标准头文件都有类似以下的结构?
#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern "C" {
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */
解答:
#ifndef __INCvxWorksh
#define __INCvxWorksh
#endif
void foo(int x, int y);
该函数被C编译器编译后在symbol库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。_foo_int_int这样的名字包含了函数名和函数参数数量及类型信息,C++就是考这种机制来实现函数重载的。
试题5:编写一个函数,作用是把一个char组成的字符串循环右移n个。比如原来是“abcdefghi”如果n=2,移位后应该是“hiabcdefgh”
函数头是这样的:
//pStr是指向以'/0'结尾的字符串的指针
//steps是要求移动的n
void LoopMove ( char * pStr, int steps )
{
//请填充...
}
解答:
void LoopMove ( char *pStr, int steps )
{
int n = strlen( pStr ) - steps;
char tmp[MAX_LEN];
strcpy ( tmp, pStr + n );
strcpy ( tmp + steps, pStr);
*( tmp + strlen ( pStr ) ) = '/0';
strcpy( pStr, tmp );
}
void LoopMove ( char *pStr, int steps )
{
int n = strlen( pStr ) - steps;
char tmp[MAX_LEN];
memcpy( tmp, pStr + n, steps );
memcpy(pStr + steps, pStr, n );
memcpy(pStr, tmp, steps );
剖析:
strcpy
memcpy
memset
试题6:已知WAV文件格式如下表,打开一个WAV文件,以适当的数据结构组织WAV文件头并解析WAV格式的各项信息。
WAVE文件格式说明表
|
偏移地址 |
字节数 |
数据类型 |
内 容 |
文件头 |
00H |
4 |
Char |
"RIFF"标志 |
04H |
4 |
int32 |
文件长度 |
|
08H |
4 |
Char |
"WAVE"标志 |
|
0CH |
4 |
Char |
"fmt"标志 |
|
10H |
4 |
|
过渡字节(不定) |
|
14H |
2 |
int16 |
格式类别 |
|
16H |
2 |
int16 |
通道数 |
|
18H |
2 |
int16 |
采样率(每秒样本数),表示每个通道的播放速度 |
|
1CH |
4 |
int32 |
波形音频数据传送速率 |
|
20H |
2 |
int16 |
数据块的调整数(按字节算的) |
|
22H |
2 |
|
每样本的数据位数 |
|
24H |
4 |
Char |
数据标记符"data" |
|
28H |
4 |
int32 |
语音数据的长度 |
解答:
将WAV文件格式定义为结构体WAVEFORMAT:
typedef struct tagWaveFormat
{
char cRiffFlag[4];
UIN32 nFileLen;
char cWaveFlag[4];
char cFmtFlag[4];
char cTransition[4];
UIN16 nFormatTag ;
UIN16 nChannels;
UIN16 nSamplesPerSec;
UIN32 nAvgBytesperSec;
UIN16 nBlockAlign;
UIN16 nBitNumPerSample;
char cDataFlag[4];
UIN16 nAudioLength;
} WAVEFORMAT;
假设WAV文件内容读出后存放在指针buffer开始的内存单元内,则分析文件格式的代码很简单,为:
WAVEFORMAT waveFormat;
memcpy( &waveFormat, buffer,sizeof( WAVEFORMAT ) );
直接通过访问waveFormat的成员,就可以获得特定WAV文件的各项格式信息。
剖析:
class String
{
public:
String(const char *str = NULL); //
普通构造函数
String(const String &other); //
拷贝构造函数
~ String(void); //
析构函数
String & operate =(const String &other); //
赋值函数
private:
char *m_data; //
用于保存字符串
};
解答:
//普通构造函数
String::String(const char *str)
{
if(str==NULL)
{
m_data = new char[1]; //
得分点:对空字符串自动申请存放结束标志'/0'的空
//加分点:对m_data加NULL
判断
*m_data = '/0';
}
else
{
int length = strlen(str);
m_data = new char[length+1]; //
若能加 NULL
判断则更好
strcpy(m_data, str);
}
}
// String的析构函数
String::~String(void)
{
delete [] m_data; //
或delete m_data;
}
//拷贝构造函数
String::String(const String &other)
//
得分点:输入参数为const型
{
int length = strlen(other.m_data);
m_data = new char[length+1];
//加分点:对m_data加NULL
判断
strcpy(m_data, other.m_data);
}
//赋值函数
String & String::operate =(const String &other) //
得分点:输入参数为const型
{
if(this == &other)
//得分点:检查自赋值
return *this;
delete [] m_data;
//得分点:释放原有的内存资源
int length = strlen( other.m_data );
m_data = new char[length+1];
//加分点:对m_data加NULL
判断
strcpy( m_data, other.m_data );
return *this;
//得分点:返回本对象的引用
}
剖析:
解答:
const classA operator*(const classA& a1,const classA& a2);
classA a, b, c;
(a * b) = c; //
对a*b的结果赋值
操作(a * b) = c显然不符合编程者的初衷,也没有任何意义。
剖析:
4.技巧题
解答:
int checkCPU()
{
{
union w
{
int a;
char b;
} c;
c.a = 1;
return (c.b
== 1);
}
}
剖析:
内存地址
|
0x4000
|
0x4001
|
存放内容
|
0x34
|
0x12
|
内存地址
|
0x4000
|
0x4001
|
存放内容
|
0x12
|
0x34
|
内存地址
|
0x4000
|
0x4001
|
0x4002
|
0x4003
|
存放内容
|
0x78
|
0x56
|
0x34
|
0x12
|
内存地址
|
0x4000
|
0x4001
|
0x4002
|
|