现在的位置: 首页 > 综合 > 正文

有点意思的C/C++问题及解答:11-15

2013年03月18日 ⁄ 综合 ⁄ 共 2105字 ⁄ 字号 评论关闭

问题11:下面这个函数希望完成什么任务?

int func(int x) 
{ 
	int countx = 0; 
	while(x) 
	{ 
		countx ++; 
		x = x&(x-1); 
	} 
	return countx; 
} 

解答:这个函数是求一个整数的二进制表示中含1的个数。假定x
= 9999,该函数返回8。这是道微软的面试题,在《编程之美》一书中给出了若干种方法,用来求二进制数中1的个数。

问题12:以下三条输出语句分别输出什么?

	char str1[] = "abc"; 
	char str2[] = "abc"; 
	const char str3[] = "abc"; 
	const char str4[] = "abc"; 
	const char* str5 = "abc"; 
	const char* str6 = "abc"; 
	cout << boolalpha << ( str1==str2 ) << endl; // 输出什么
	cout << boolalpha << ( str3==str4 ) << endl; // 输出什么
	cout << boolalpha << ( str5==str6 ) << endl; // 输出什么 

解答:输出分别为false false true。str1
和str2 都是字符数组,每个都有其自己的存储区,它们的值则是各 存储区首地址,不等;str3 和str4 同上,只是按const 语义,它们所指向的数据区不能修改。str5 和str6 并非数组而是字符指针,并不分配存储区,其后的“abc”以常量形式存于静态数据区,而它们自己仅是指向该区首地址的指针,相等。 如果去掉定义str5、str6时加的const修饰,输出还是相等的。

问题13: 已知String类定义如下,请实现这些函数。

class String 
{ 
public: 
	String(const char *str = NULL); //默认构造函数 
	String(const String &another);  //拷贝构造函数 
	~String();                      //析构函数 
	String & operator =(const String &rhs); //赋值操作符 
private: 
	char *m_data;                   //用于保存字符串 
}; 

解答:实现中有几点要注意:(1)默认构造函数中,判断str是否为空。(2)析构函数中应使用delete [ ]
运算符。(3)赋值操作符应判断是否是给自身赋值。代码如下:

String::String(const char *str)
{
	if(str == NULL)
	{
		m_data = new char[1];
		m_data[0] = '\0';
	}
	else
	{
		m_data = new char[strlen(str) + 1]; //需要加1,strlen返回的字符串长度并不包含'\0'
		strcpy(m_data,str);
	}
}
String::String(const String &another)
{
	m_data = new char[strlen(another.m_data) + 1];
	strcpy(m_data,another.m_data);
}
String& String::operator=(const String &rhs)
{
	if(this != &rhs) //防止给自身赋值
	{
		delete [] m_data;
		m_data = new char[strlen(rhs.m_data) + 1];
		strcpy(m_data,rhs.m_data);
	}
	return *this;
}
String::~String()
{
	delete [] m_data; //注意是delete []
}

问题14:写一个在一个字符串(T)中寻找一个子串(P)第一个位置的函数。

解答:用KMP算法即可。基本策略是预处理子串 P ,获得其中与模式匹配有关的子字符串关系规律,从而当发生匹配失败时,可以确定继续与 T 当前位置匹配的 P 的新位置,这样就不需要在 T 中回溯了。时间复杂度为O(T+P)。

int KMP(char *T, char *P)
{
	int lenT = strlen(T);
	int lenP = strlen(P);
	int i = 0, j = 0;
	int *next = new int[lenP + 1];  //最后一个元素用不到
	Fail(next, P);                  //计算失败函数
	while(i < lenT && j < lenP)
	{
		if(j == -1 || T[i] == P[j])
		{
			i++; j++;
		}
		else
			j = next[j];   //P的下一个比较位置
	}
	delete [] next;
	if(j < lenP || j == 0)
		return -1;
	else 
		return i - lenP;
}

//仍是一个模式匹配的过程,只不过目标串和模式串是同一串P,所以两个代码的程序很相似
void Fail(int *next, char *P)
{
	int lenP = strlen(P);
	int i = -1,j = 0;
	next[0] = -1;
	while(j < lenP)
	{
		if(i == -1 || P[i] == P[j])
		{
			i++; j++;
			next[j] = i;
		}
		else
			i = next[i];
	}
}

问题15:为什么一个空类的sizeof为1而不是0?

解答:空类同样可以被实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址。

抱歉!评论已关闭.