1、请填写BOOL , float, 指针变量 与“零值”比较的 if 语句。
请写出 BOOL flag 与“零值”比较的 if 语句:
if ( flag )
if ( !flag )
请写出 float x 与“零值”比较的 if 语句:
const float EPSINON = 0.00001;
if ((x >= - EPSINON) && (x <= EPSINON)
不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式
不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式
请写出 char *p 与“零值”比较的 if 语句: if (NULL != p)
if (p == NULL)
if (p != NULL)
Addtion: while(p) 与while(*p)
while(*p)中的*p是指针所指向地址的内容(即值),而while(p!=null)中p!=null是指针指向不能为空(即地址)
p != NULL指的是指针存在,只要指针有指向的值就为True
而 *p是指指针指向的值为True,
当*p指向0时,p!=NULL为True;而*p为False
2、头文件中的 ifndef/define/endif 干什么用?
防止头文件被重复引用,重复include
3、#include <filename.h> 和 #include “filename.h” 有什么区别?
#include <filename.h>首先查找库目录,然后从当前工作目录查找。#include “filename.h”先查找当前工作目录。
4、const 有什么用途?(请至少说明两种)
(1)可以定义 const 常量
(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
5、extern 关键字
extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块
中寻找其定义。另外,extern也可用来进行链接指定。
(1)、在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern "C"声明?
融合C和C++程序,在C中编译的函数和C++中是不同的,C++链接的时候不能直接调用C的函数,必须使用extern "C"来告诉编译器是C的函数,这样就可以调用了。C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern "C"来解决名字匹配问题。
(2)、extern 变量: 在.c中定义或使用声明的变量; 在.c中声明extern变量, 表示其链接方式, 表示此变量可以被外部文件使用
(3)、extern 函数: 函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。
(4)、extern 和 static:extern 表明该变量在别的地方已经定义过了,在这里要使用那个变量 ;static 表示静态的变量,分配内存的时候, 存储在静态区,不存储在栈上面.
static 作用范围是内部连接的关系, 和extern有点相反.它和对象本身是分开存储的,extern也是分开存储的,但是extern可以被其他的对象用extern 引用,而static 不可以,只允许对象本身用它. 具体差别首先,static与extern是一对“水火不容”的家伙,也就是说extern和static不能同时修饰一个变量;其次,static修饰的全局变量声明与定义同时进行,也就是说当你在头文件中使用static声明了全局变量后,它也同时被定义了;最后,static修饰全局变量的作用域只能是本身的编译单元,也就是说它的“全局”只对本编译单元有效,其他编译单元则看不到它; 一般定义static全局变量时,都把它放在原文件中而不是头文件.
6、关于内存的思考
void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:程序崩溃。因为GetMemory并不能传递动态内存,Test函数中的 str一直都是 NULL。strcpy(str, "hello world");将使程序崩溃。
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行Test函数会有什么样的结果?
答:可能是乱码。
因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
请问运行Test函数会有什么样的结果?
答:(1)能够输出hello
(2)内存泄漏
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
请问运行Test函数会有什么样的结果?
答:篡改动态内存区的内容,后果难以预料,非常危险。 因为free(str)之后,str成为野指针, if(str != NULL)语句不起作用。
7、编写strcpy函数
(1)不调用C++/C的字符串库函数,请编写函数 strcpy
char *strcpy(char *strDest, const char *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”) );
8、编写类String的构造函数、析构函数和赋值函数
已知类String的原型为:
class String
{
public:
String(const char *str = NULL);// 普通构造函数
String(const String &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(const char *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(const String &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;
}