C笔记
2.默认构造函数不用括号
3.三元表达式的两个操作数必须为相同类型
4.数组长度必须是编译期间的常量
5.vector:size_type是unsigned int类型
6.默认构造函数中再执行带参构造函数,不会执行初始化赋值
7.空类会产生:
class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
8.(int&)a表示将a看成整数,但不做实际转换.浮点数和整数在存储区的存储方式是不一样的.
9.static可以限制变量的作用域,设置变量的存储域.
10.全局变量存于静态存储区,局部变量存于堆栈中.
11.平衡二叉树是指左右子树都是平衡二叉树,且左右子树的深度差值绝对值不大于1.
12.construct函数不能声明为虚函数
13.冒泡算法的时间复杂度为O(n^2),比较次数为O(N*logN).
14.if(x>-0.000001&&x<0.000001) float与"零值"的差值
15.switch()的参数类型不能为实型.
16.引用已经定义的全局变量可以使用头文件,也可以使用extern声明.
17.
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
19.#include <stdlib.h> 中的long atol(const char *nptr)将字符型转为长整形.
20.对于常用的短小函数:C使用宏定义,C++使用inline.
21.
///////////
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
22.对于#include<filename.h> ,编译器从标准库路径开始搜索 filename.h;对于#include“filename.h” ,编译器从用户的工作路径开始搜索 filename.h
23.const 有什么用途?(请至少说明两种)
(1)可以定义 const 常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
24.在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”?
使用不同的编译器,在库中生成的名字不同.例如,foo(int x,int y),被C编译后生成_foo,被C++编译后生成_foo_int_int之类的.
25.atoi,itoa(int,char *,基数) <cstdio.h><cstdlib.h>
五、编写strcpy函数(10分)
已知strcpy函数的原型是
char*strcpy(char *strDest, const char *strSrc);
其中strDest是目的字符串,strSrc是源字符串。
(1)不调用C++/C的字符串库函数,请编写函数 strcpy
char *strcpy(char *strDest, constchar *strSrc);
{
assert((strDest!=NULL) && (strSrc !=NULL));
// 2分
char *address =strDest;
//2分
while( (*strDest++ = * strSrc++) != ‘\0’ )
// 2分
NULL ;
return address;
// 2分
}
(2)strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
答:为了实现链式表达式。
// 2分
例如
int length = strlen(strcpy( strDest, “hello world”) );
六、编写类String的构造函数、析构函数和赋值函数(25分)
已知类String的原型为:
class String
{
public:
String(constchar *str = NULL);
// 普通构造函数
String(constString &other);
// 拷贝构造函数
~ String(void);
// 析构函数
String &operate =(const String &other);
// 赋值函数
private:
char
*m_data;
// 用于保存字符串
};
请编写String的上述4个函数。
标准答案:
// String的析构函数
String::~String(void)
// 3分
{
delete [] m_data;
// 由于m_data是内部数据类型,也可以写成 delete m_data;
}
//String的普通构造函数
String::String(constchar *str)
// 6分
{
if(str==NULL)
{
m_data = new char[1];
// 若能加 NULL 判断则更好
*m_data = ‘\0’;
}
else
{
int length = strlen(str);
m_data = new char[length+1];
// 若能加 NULL 判断则更好
strcpy(m_data, str);
}
}
// 拷贝构造函数
String::String(constString &other)
// 3分
{
int length = strlen(other.m_data);
m_data = new char[length+1];
// 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
}
// 赋值函数
String &String::operate =(const String &other)
// 13分
{
// (1) 检查自赋值
// 4分
if(this ==&other)
return*this;
// (2)释放原有的内存资源
// 3分
delete []m_data;
// (3)分配新的内存资源,并复制内容 // 3分
int length = strlen(other.m_data);
m_data = new char[length+1];
// 若能加 NULL 判断则更好
strcpy(m_data, other.m_data);
// (4)返回本对象的引用
// 3分
return *this;
}
///////////////////////////////////////////////////////////
附:
c/c++笔试题大解析
1. 以下三条输出语句分别输出什么?[C易]
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”以常量形式存于静态数据区,而它们自己仅是指向该区首地址的指针,相等。
12. 以下代码中的两个sizeof用法有问题吗?[C易]
void UpperCase( char str[] ) // 将 str 中的小写字母转换成大写字母
{
for( size_t i=0; i<sizeof(str)/sizeof(str[0]); ++i )
if( 'a'<=str[i] && str[i]<='z' )
str[i] -= ('a'-'A' );
}
char str[] = "aBcDe";
cout << "str字符长度为: " << sizeof(str)/sizeof(str[0]) << endl;
UpperCase( str );
cout << str << endl;
答:函数内的sizeof有问题。根据语法,sizeof如用于数组,只能测出静态数组的大小,无法检测动态分配的或外部数组大小。函数外的str是一个静态定义的数组,因此其大小为6,函数内的str实际只是一个指向字符串的指针,没有任何额外的与数组相关的信息,因此sizeof作用于上只将其当指针看,一个指针为4个字节,因此返回4。
13. 非C++内建型别 A 和 B,在哪几种情况下B能隐式转化为A?[C++中等]
答:
a. class B : public A { ……} // B公有继承自A,可以是间接继承的
b. class B { operator A( ); } // B实现了隐式转化为A的转化
c. class A { A( const B& ); } // A实现了non-explicit的参数为B(可以有其他带默认值的参数)构造函数
d. A& operator= ( const A& ); // 赋值操作,虽不是正宗的隐式类型转换,但也可以勉强算一个
4. 以下代码有什么问题?[C++易]
struct Test
{
Test( int ) {}
Test() {}
void fun() {}
};
void main( void )
{
Test a(1);
a.fun();
Test b();
b.fun();
}
答:变量b定义出错。按默认构造函数定义对象,不需要加括号。
5. 以下代码有什么问题?[C++易]
cout << (true?1:"1") << endl;
答:三元表达式“?:”问号后面的两个操作数必须为同一类型。
8. 以下代码能够编译通过吗,为什么?[C++易]
unsigned int const size1 = 2;
char str1[ size1 ];
unsigned int temp = 0;
cin >> temp;
unsigned int const size2 = temp;
char str2[ size2 ];
答:str2定义出错,size2非编译器期间常量,而数组定义要求长度必须为编译期常量。
2. 以下反向遍历array数组的方法有什么错误?[STL易]
vector array;
array.push_back( 1 );
array.push_back( 2 );
array.push_back( 3 );
for( vector::size_type i=array.size()-1; i>=0; --i ) // 反向遍历array数组
{
cout << array[i] << endl;
}
答:首先数组定义有误,应加上类型参数:vector<int> array。其次vector::size_type被定义为unsigned int,即无符号数,这样做为循环变量的i为0时再减1就会变成最大的整数,导致循环失去控制。
9. 以下代码中的输出语句输出0吗,为什么?[C++易]
struct CLS
{
int m_i;
CLS( int i ) : m_i(i) {}
CLS()
{
CLS(0);
}
};
CLS obj;
cout << obj.m_i << endl;
答:不能。在默认构造函数内部再调用带参的构造函数属用户行为而非编译器行为,亦即仅执行函数调用,而不会执行其后的初始化表达式。只有在生成对象时,初始化表达式才会随相应的构造函数一起调用。
10. C++中的空类,默认产生哪些类成员函数?[C++易]
答:
class Empty
{
public:
Empty(); // 缺省构造函数
Empty( const Empty& ); // 拷贝构造函数
~Empty(); // 析构函数
Empty& operator=( const Empty& ); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const; // 取址运算符 const
};
3. 以下两条输出语句分别输出什么?[C++难]
float a = 1.0f;
cout << (int)a << endl;
cout << (int&)a << endl;
cout << boolalpha << ( (int)a == (int&)a ) << endl; // 输出什么?
float b = 0.0f;
cout << (int)b << endl;
cout << (int&)b << endl;
cout << boolalpha << ( (int)b == (int&)b ) << endl; // 输出什么?
答:分别输出false和true。注意转换的应用。(int)a实际上是以浮点数a为参数构造了一个整型数,该整数的值是1,(int&)a则是告诉编译器将a当作整数看(并没有做任何实质上的转换)。因为1以整数形式存放和以浮点形式存放其内存数据是不一样的,因此两者不等。对b的两种转换意义同上,但是0的整数形式和浮点形式其内存数据是一样的,因此在这种特殊情形下,两者相等(仅仅在数值意义上)。
注意,程序的输出会显示(int&)a=1065353216,这个值是怎么来的呢?前面已经说了,1以浮点数形式存放在内存中,按ieee754规定,其内容为0x0000803F(已考虑字节反序)。这也就是a这个变量所占据的内存单元的值。当(int&)a出现时,它相当于告诉它的上下文:“把这块地址当做整数看待!不要管它原来是什么。”这样,内容0x0000803F按整数解释,其值正好就是1065353216(十进制数)。
通过查看汇编代码可以证实“(int)a相当于重新构造了一个值等于a的整型数”之说,而(int&)的作用则仅仅是表达了一个类型信息,意义在于为cout<<及==选择正确的重载版本。
6. 以下代码有什么问题?[STL易]
typedef vector IntArray;
IntArray array;
array.push_back( 1 );
array.push_back( 2 );
array.push_back( 2 );
array.push_back( 3 );
// 删除array数组中所有的2
for( IntArray::iterator itor=array.begin(); itor!=array.end(); ++itor )
{
if( 2 == *itor ) array.erase( itor );
}
答:同样有缺少类型参数的问题。另外,每次调用“array.erase( itor );”,被删除元素之后的内容会自动往前移,导致迭代漏项,应在删除一项后使itor--,使之从已经前移的下一个元素起继续遍历。
11. 写一个函数,完成内存之间的拷贝。[考虑问题是否全面]
答:
void* mymemcpy( void *dest, const void *src, size_t count )
{
char* pdest = static_cast<char*>( dest );
const char* psrc = static_cast<const char*>( src );
if( pdest>psrc && pdest<psrc+cout ) 能考虑到这种情况就行了
{
for( size_t i=count-1; i!=-1; --i )
pdest[i] = psrc[i];
}
else
{
for( size_t i=0; i<count; ++i )
pdest[i] = psrc[i];
}
return dest;
}