C++易错总结(持续更新)

本文总结了C++编程中常见的错误和陷阱,包括内存管理、指针运算、数组和指针的关系、函数指针、运算符重载、类的静态成员和友元等知识点,旨在帮助开发者避免这些易错点,提升编程技能。

1、以下涉及到内存管理的代码中,有错误的是:

A:

int *a=new int(12);
//......
free(a);

B:

int *ip=static_cast<int *>(malloc(sizeof(int)));
*ip=10;
//......
delete ip;

C;

double *a=new double[1];
//.....
delete a;

D;

int *ip=new int(12);
for(int i=0;i<12;i++)
{
      ip[i]=i;
}
delete [] ip;

解析:new和delete搭配,malloc和free搭配,所以A B错误。

   关于D,要注意new int[12] 和new int (12)的区别,new int[12]生成一个大小为12 的int数组,而new int(12)是生成一个初始值为12的int变量。所以D错

       关于C,乍一看,a是一个数组,应该用delete [ ] a,但是对于基本类型数组来说,delete a和delete [ ] a效果是一样的,如果a是一个用户自己定义的结构类型数组,只能            使用delete [ ] a。

2、如下代码,result变量的输出结果是多少?

#include<iostream>
using namespace std;
int i=1;
class MyCls
{
	public:
	MyCls():m_nFor(m_nThd),m_nSec(i++),m_nFir(i++),m_nThd(i++)
	{
		m_nThd=i;
	}
	void echo()
	{
		cout<<"result"<<m_nFir+m_nSec+m_nThd+m_nFor<<endl;
	}
	private:
	int m_nFir;
	int m_nSec;
	int m_nThd;
	int &m_nFor;
};

int main()
{
	MyCls oCls;
	oCls.echo();
	return 0;
}
解析:首先要明白, 变量初始化的顺序是其声明的顺序,跟初始化列表中的顺序无关,所以变量的初始化顺序m_nFir(i++),m_nSec(i++),m_nThd(i++),m_nFor(m_nThd),i初始化为1,所以经过初始化列表后的m_nFir=1,m_nSec=2,m_nThd=3,m_nFor是m_nThd的一个引用,并且此时i的值为4,执行构造函数中的赋值语句后,m_nThd=4,此时m_nFor是m_nThd的一个引用,也是4。result=1+2+4+4=11。

3、由多个源文件组成的C程序,经过编辑、预处理、编译、链接等阶段会生成最终的可执行程序,下面哪个阶段会发现被调用的函数没有定义?

A:预处理           B:编译            C:链接           D:执行

解析:预处理阶段主要是对各种预处理命令的处理,包括头文件的包含、宏定义的扩展、条件编译的选择等

    编译阶段进行c词法和语法的分析,首先编译成纯汇编语句,再汇编程二进制码,再生成各个目标文件

   链接阶段,到了链接阶段才会知道各个函数的调用关系,才能出现调用某个函数但是该函数没有声明的情况。

4、下面哪个指针表达式 可以用来引用数组元素a[i][j][k][l]?

A:((((a+i)+j)+k)+l)        B:*(*(*((a+i)+j)+k)+l)          C:(((a+i)+j)+k+l)          D:((a+i)+j+k+l)

解析: 如果a是一个指向四维数组的指针,那么*a就指向的是一个三维数组,**a只想一个二维数组,***a指向一个三维数组,****a指向某个元素。

5、下面的代码会输出:

int main()
{	
	int a[4]={1,2,3,4};
	int *ptr=(int *)(&a+1);
	printf("%d",*(ptr-1));
}
解析:最终结果会输出4。考察数组和指针, 指针加一的能力由指针指向的类型决定。&a和a都指的是数组首元素的地址,不同的是,a就是a+0,*(a+0)也就是a[0],而&a+1相当于对a[]类型的数组类型的指针加一,此时指针加到数组的末尾。ptr接受之后,ptr指向最后一个元素后面的那个位置,而ptr的类型是int*,因此,ptr-1之后指向数组最后一个元素4。

5、下面哪个用法是错误的

        A:int *a                   B:extern const int array[256]               C:const int &a            D:typedef void (*FUN)()

解析:C错误,原因是引用定义的时候必须对其进行初始化。指针不是必须初始化,而引用是在定义的时候必须对其进行初始化。对于D,其实D定义的是一个函数指针数据类型,通过FUN foo就定义一个指向的函数参数列表为空,返回值为空的函数。详见:http://blog.youkuaiyun.com/zhangleo1987/article/details/5707290

6、有下面一段程序,则下列不合法的是

int f1(float);
int f2(char);
int f3(float);
int f4(float);
int (*pf)(float)
A:int (*p)(float)=&f1             B:pf=&f4             C:pf=&f2                  D:pf=f3
解析:C错误,原因是函数参数类型不匹配。函数指针声明的方法:  返回值类型   (*指针变量名)([参数列表])

根据定义,则int (*pf)(float)                           int (*p)(float)=&f1     ,pf和p都是函数指针。对于函数地址的获取,可以是函数名,也可以是函数名前加取地址符&。

7、若有下列定义语句,则以下赋值语句错误的是:

     定义

char s[3][10];
char (*k)[3];
char *p;
    赋值:

1.p=s;
2.p=k;
3.p=s[0];
4.k=s;
解析:s是一个二维数组,也可以看成是一个一维数组,这个一维数组的每个元素是一个包含10个元素的一维数组,s指向这个包含三个元素的一维数组的第一个元素,也就是s中的第一个一维数组的第一个元素。k是一个指向有三个cha元素的数组指针。p是一个指向char变量的指针。所以1、2、4都是错误的。3是正确的,因为s[0]就指向一个一维数组。

8、math.h中abs返回值()

解析:abs的返回值可能是正数,可能是负数,可能是0。因为负数的范围比正数的范围大一。比如,8位二进制数范围是-128~+127,abs(-128)不可能返回128,只能返回原值,也就是-128,但是其他正数、负数、零都按正常取绝对值返回。

9、以下代码的执行结果是:

int _tmain(int argc, _TCHAR* argv[])
{
	int i=-2147483648;
	printf("%d  %d  %d  %d",~i,-i,1-i,-1-i);
	cin.get();
	return 0;
}
解析:-2147483648是32位int所能表示的最小负整数,其用原码表示为1000  0000  0000  0000  0000  0000  0000  0000,,最小负整数原码和补码表示一样。

           ~i:表示按位取反,为 0111 1111  1111 1111  1111  1111 1111 1111,符号位为0,表示正数,原码补码一样,2147483647

    -i:对数值执行单目运算符-表示对该数按位取反(包括符号位)再+1,也就是求补运算注意求补运算和求补码的不同,求补码是对数值位(不包括符号位)取反再+1,求补运算时按位取反(包括符号位)再+1。对i=1000  0000  0000  0000  0000  0000  0000  0000求补再+1还是得到1000  0000  0000  0000  0000  0000  0000  0000,也就是-2147483648。

    1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值