C/C++ 一般性编程题汇总

无知是痛苦的根源,坚持学习可以改变你的无知。

有些题目是经典的试题,有些题目是我自己编写的,都是平时在工作中遇到的头痛问题,最终得到了解决,希望后来人不要走弯路,与大家共勉。

 

【1】下面程序有什么问题
#include <string>
#include <sstream>
#include <iostream> 
using namespace std; 
int main() {    
stringstream ss("this is a string\n");     
string str(ss.str());     
const char* cstr1 = str.c_str();     
const char* cstr2 = ss.str().c_str();     
cout << cstr1       
cout << cstr2;            
system("PAUSE");     
return 0;
}
参考答案:
.c_str()返回的是临时地址,会被STL的内存池回收。
cout << cstr1        // Prints correctly        
cout << cstr2;       // ERROR, prints out garbage
扩展说明,stringstream也有类似问题
http://blog.csdn.net/jimmyleeee/archive/2009/06/26/4300548.aspx

【2】 unsigned int 类型的数转换成二进制后,计算有多少个0多少个1。

参考答案

#include <iostream>
using namespace std;

void CalNumInfoByType(unsigned int uNum, int iNumType)
{
     int iOneNum = 0, iZeroNum = 0;
     unsigned int uTemp;
     uTemp = uNum;

     do {
        (uTemp % 2 == 1 )?iOneNum++:iZeroNum++;

     } while( uTemp /= 2 );

     cout<<uNum<<"转换为二进制后,1的个数为"<<iOneNum<<",0的个数为:"<<iZeroNum<<endl;

     return ;
}

例如计算123转换成2进制后的情况: CalNumInfoByType(123, 2);

【3】请写出 float  x 与“零值”比较的 if 语句。

float型变量与零值比较:
#define FLT_EPSILON 1.192092896e-07F
if ((x >= - FLT_EPSILON) && (x <= FLT_EPSILON) )

不可将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”此类形式。
如下是错误的写法。
if (x == 0.0)  
if (x != 0.0)      

【4】32位C++程序,请计算sizeof的值
sizeof数组,即计算数组所占用的空间大小,例如
char  str[] = "Hello"; int  str2[] = {1,2,3,4,5};
sizeof(str)为6 sizeof(str2)为20
sizeof指针,大小固定为4。
char   *p = str ; sizeof(p)为4
注意:数组做为参数在C语言中是按指针变量对待的
 void Func ( char str[100])
{
sizeof( str ) =   4    
}
void *p = malloc( 100 );
sizeof ( p ) =  4     

 

【5】头文件中的 ifndef/define/endif 干什么用?

通常用来防止头文件被重复引用。还有就是按照条件编译,比如

#ifdef WIN32
#define write(fd,buf,len) send((fd),(buf),(len),0)
#define read(fd,buf,len) recv((fd),(buf),(len),0)
#endif

如果定义了宏WIN32(windows平台),就重新定义write和read

 

【6】const 有什么用途?

(1)可以定义 const 常量

(2)const可以修饰函数的参数、返回值,甚至函数的定义体。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。
【7】 extern的用法?
1. 在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern “C”C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);
该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。
C++提供了C连接交换指定符号extern“C”来解决名字匹配问题。
extern "C"
{
#include "lua/lua.h"
#include "lua/lualib.h"
#include "lua/lauxlib.h"
}
2. extern告诉编译器,某个变量、函数或类已经在某个.cpp(非.h)中已经定义了,另外一个cpp里面只不过是声明一下有这个东西,然后拿来用一下。定义只能出现一次,声明却可出现多次,也就是说extern声明可在多个文件中用(包括.h)。
// 1.cpp
int x = 10;
// 2.cpp 注意没有包含1.cpp
#include <iostream>
using namespace std;
extern int x;
int main ()
{ cout << x << endl; }
//则输出10

 

【8】 请问运行Test函数会有什么样的结果?

void Test(void)

{

char *str = (char *) malloc(100);

    strcpy(str, “hello”);

    free(str);     

    if(str != NULL)

    {

      strcpy(str, “world”);

printf(str);

}

}

答:篡改动态内存区的内容,后果难以预料,非常危险。

因为free(str);之后,str成为野指针,

if(str != NULL)语句不起作用。


 


【9】编写strcpy函数

已知strcpy函数的原型是

       char *strcpy(char *strDest, const char *strSrc);

       其中strDest是目的字符串,strSrc是源字符串。

char *mstrcpy(char *strDest, const char *strSrc)
{
 assert(strDest !=NULL );
 assert(strSrc !=NULL );
 char *strDestTmp = strDest;
 while( (*strDestTmp++ = *strSrc++) != NULL);

 return strDest;
}

strcpy能把strSrc的内容复制到strDest,为什么还要char * 类型的返回值?
例如       int length = strlen( strcpy( strDest, “hello world”) );

 


【10】 编写类String的构造函数、析构函数和赋值函数

已知类String的原型为:

    class String

    {

      public:

        String(const char *str = NULL); // 普通构造函数

        String(const String &other);        // 拷贝构造函数

        ~ String(void);                     // 析构函数

        String & operator =(const String &other);    // 赋值函数

      private:

        char    *m_data;                // 用于保存字符串

    };

       请编写String的上述4个函数。

参考答案:
class String

{

public:

 String(const char *str = NULL);

 String(const String &other);

 ~String();
 String & operator = (const String & other);

private:

 char    *m_data;               

};
// String的普通构造函数
String::String(const char *str)
{
 if(str) {
  int len = strlen(str);
  m_data = new char[len+1];
  strcpy(m_data, str);
 } else {
  m_data = new char[1];
  *m_data = '\0';
 }

}
String::~String()
{
 delete m_data;
 m_data = NULL;
}
// 拷贝构造函数
String::String(const String &other)
{
 int len = strlen(other.m_data);
 m_data = new char[len+1];
 strcpy(m_data, other.m_data);
}

// 赋值函数
String & String::operator = (const String & other)
{
 if(this == &other) return *this;
 
 delete m_data;

 int len = strlen(other.m_data);
 m_data = new char[len+1];
 strcpy(m_data, other.m_data);
 return *this;
}

【11】 const char*, char const*, char*const的区别
事实上这个概念谁都有只是三种声明方式非常相似很容易记混。 Bjarne在他的The C++ Programming Language里面给出过一个助记的方法: 把一个声明从右向左读。 const
char  * const cp; ( * 读成 pointer to )
cp is a const pointer to char
const char * p;
p is a pointer to const char;
char const * p;
同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。

【12】 C的指针
int *p[n];-----指针数组,每个元素均为指向整型数据的指针。
int (*)p[n];------p为指向一维数组的指针,这个一维数组有n个整型数据。
int *p();----------函数带回指针,指针指向返回的值。
int (*)p();------p为指向函数的指针。

【13】数组越界问题
下面这个程序执行后会有什么错误或者效果:
#define MAX 255
int main()
{
    unsigned char A[MAX],i;
    for (i=0;i<=MAX;i++)
        A[i]=i;
}

解答:死循环A[255]=255;
由于unsigned char的取值范围在(0..255),i++以后i又为0了..无限循环下去.
注:char类型为一个字节,取值范围是[-128,127],unsigned char [0 ,255]


【14】 ASSERT()是干什么用的
ASSERT()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。例如
......
ASSERT( n != 0);
k = 10/ n;
......
ASSERT只有在Debug版本中才有效,如果编译为Release版本则被忽略。
assert()的功能类似,它是ANSI C标准中规定的函数,它与ASSERT的一个重要区别是可以用在Release版本中。

【15】system("pause");
系统的暂停程序,按任意键继续,屏幕会打印,"按任意键继续。。。。。"
省去了使用getchar();

【16】 请问C++的类和C里面的struct有什么区别?
c++中的类具有成员保护功能,并且具有继承,多态这类oo特点,而c里的struct没有

【17】 请讲一讲析构函数和虚函数的用法和作用?
析构函数也是特殊的类成员函数,它没有返回类型,没有参数,不能随意调用,也没有重载。知识在类对象生命期结束的时候,由系统自动调用释放在构造函数中分配的资源。这种在运行时,能依据其类型确认调用那个函数的能力称为多态性,或称迟后联编。另:析构函数一般在对象撤消前做收尾工作,比如回收内存等工作,
虚拟函数的功能是使子类可以用同名的函数对父类函数进行重载,并且在调用时自动调用子类重载函数,如果是纯虚函数,则纯粹是为了在子类重载时有个统一的命名而已。

【18】全局变量和局部变量有什么区别?实怎么实现的?操作系统和编译器是怎么知道的?
全局变量的生命周期是整个程序运行的时间,而局部变量的生命周期则是局部函数或过程调用的时间段。其实现是由编译器在编译时采用不同内存分配方法。全局变量在main函数调用后,就开始分配,如果是静态变量则是在main函数前就已经初始化了。而局部变量则是在用户栈中动态分配的(还是建议看编译原理中的活动记录这一块)
【19】 8086是多少位的系统?在数据总线上是怎么实现的?
8086系统是16位系统,其数据总线是20位。

【20】 编写用C语言实现的求n阶阶乘问题的递归算法:
long fact(int n)
{
 if( n>0 ) {
  return (n * fact(n-1));

 } else if( n == 0 ) {
  return 1;
 } else {
  cout<<"error n < 0"<<endl;
 }

}

【21】      交换两个数,不用第三块儿内存:
int a = ……;
int b = ……;
a = a + b;
b = a - b;
a = a - b;


【22】        递归计算如下递归函数的值(斐波拉契):
f(1)=1
f(2)=1
f(n)=f(n-1)+f(n-2) n>2

 

参考文献:http://bbs.bccn.net/thread-175695-1-1.html
解:
1)递归算法
int calfun(int n)
{
 if(n > 2) {
  return calfun(n-1) + calfun(n-2);
 } else if(n == 2 || n == 1) {
  return 1;
 }
}
2)非递归算法
int Fibona(int n)
{
 int p1=1,p2=1;
 //int a[100]={0};
 //a[1]=1,a[2]=1;
 for(int i=3;i<=n;i++) //从三开始就可以了,后面的return包括1,2两种情况
 {
  int r=p1; //递推,可以使用数组全部保存
  p1=p2;
  p2+=r;
  //a[i]=a[i-1]+a[i-2]
 }
 return p2;
 //return a[n];
}

【23】分别用C与C++代码读取文件

int loadEncryptedFileCpp(lua_State *L, const char *filename)
{
 int pos, filesize;
 int iRet;
 char *pszBuf;
 static const TCHAR szPwd[] = {"~!df*2212212@#$|+_"};
 int iPwdLen = sizeof(szPwd);

 ifstream readfile(filename, ios::binary | ios::in);
 if(!readfile.is_open()) {
  return 1;//  1 : cannot open file error
 }

 pos = readfile.tellg();
 readfile.seekg(0, ios_base::end);
 filesize = readfile.tellg();
 readfile.seekg(pos, ios_base::beg);

 pszBuf = new char[filesize+1];
 memset(pszBuf, 0, sizeof(pszBuf));
 
 readfile.read(pszBuf, filesize);
 

 for(int i = 0; i < filesize; i++) {
  pszBuf[i] ^= szPwd[i % iPwdLen];
 }

 iRet = luaL_loadstring(L, pszBuf);
 if (iRet) {
  //fprintf(stderr, "%s", lua_tostring(m_pLua, -1));
  //lua_pop(m_pLua, 1);
  delete pszBuf;
  return iRet;
  
 }

 delete pszBuf;
 return 0;
}


int loadEncryptedFile(lua_State *L, const char *filename)
{
 int     pos, iFilesize;
 int     iRet;
 char    *pszBuf;
 static const TCHAR szPwd[] = {"~!df*2212212@#$|+_"};
 int     iPwdLen = sizeof(szPwd) - 1;
 FILE    *fpFile = NULL;
   
        fpFile = fopen(filename, "rb");
 if (NULL == fpFile) {
  _tprintf("fopen error. LINE:%d", __LINE__);
        return 1;//  1 : cannot open file error
        }

 fseek(fpFile,0L,SEEK_END);
 iFilesize = ftell(fpFile);
 fseek(fpFile, 0L, SEEK_SET);
 
        pszBuf = new char[iFilesize + 1];
        memset(pszBuf, 0, iFilesize + 1);


        iRet = fread(pszBuf, iFilesize, 1, fpFile);
        if(iRet != 1) {
            _tprintf("fread error. line: %d\n", __LINE__);
            //delete pszBuf;
            fclose(fpFile);
            return -1; //??error code returned maybe not right
        }

        for(int i = 0; i < iFilesize; i++) {
            pszBuf[i] ^= szPwd[i % iPwdLen];
        }

        iRet = luaL_loadstring(L, pszBuf);
        if (iRet) {
            delete pszBuf;
            fclose(fpFile);
            return iRet;
        }
}

 

【24】printf中格式化参数"%-*.*s"代表什么意思,编程举例说明。

#include <stdio.h>

#include<string.h>

int main()

{

  char ch[20];

  int m,n;

  strcpy(ch,"Happy!");

  scanf("%d%d",&m,&n);

  printf("%*.*s\n",m,n,ch);

  return 0;

}

其中"-"表示左对齐,前边*定义的是总的宽度,后边*是指定输出字符个数。分别对应外边参数m和n。

输入: 10 3

输出: Hap

参考:http://baike.baidu.com/view/410546.htm

 

【25】虚析构函数

虚析构函数是为了解决这样的一个问题:基类的指针指向派生类对象,并用基类的指针删除派生类对象。

有下面的两个类:

class  ClxBase
{
public :
    ClxBase() {};
    
virtual   ~ ClxBase() {};

    
virtual   void  DoSomething() cout  <<   " Do something in class ClxBase! "   <<  endl; };
};

class  ClxDerived  public  ClxBase
{
public :
    ClxDerived() {};
    
~ ClxDerived() cout  <<   " Output from the destructor of class ClxDerived! "   <<  endl; }; 

    
void  DoSomething() cout  <<   " Do something in class ClxDerived! "   <<  endl; };
};

代码

ClxBase  * pTest  =   new  ClxDerived;
pTest
-> DoSomething();
delete pTest;

的输出结果是:

Do something in class ClxDerived!
Output from the destructor of class ClxDerived!

如果把类ClxBase析构函数前的virtual去掉,那输出结果就是下面的样子了:

Do something in class ClxDerived!

 当然,并不是要把所有类的析构函数都写成虚函数。因为当类里面有虚函数的时候,编译器会给类添加一个虚函数表,里面来存放虚函数指针,这样就会增加类的存储空间。所以,只有当一个类被用来作为基类的时候,才把析构函数写成虚函数。

【26】书写圆括号匹配函数,函数原型int check(char *input, int len)
返回值:匹配返回1,不匹配返回0。

例如:(a+b*9)(a+B)匹配返回1  (Com)$)不匹配返回0
答案:

 

本文转出处: http://blog.sina.com.cn/faithfish

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值