C/C++ 拾遗(1)

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值