C++易错知识点。对方正在输入...

目录

 

数组地址问题

形参和实参的区别:

new使用方法:

有关new的良好变成习惯


数组地址问题

  1. 数组初始化int data[3]。此时data[]中有三个数据,而不是四个。
  2. 关于数组的地址问题:
int main() {
	int data[] = { 2,8,6,1,10,15,3,12,11 };
	//data代表着data首元素的地址
	cout << "data:" << data << endl;
	//data+1代表着data第二元素的地址
	//因此其地址比data多sizeof(int)
	cout << "data+1:" << data + 1 << endl;
	//&data中的data表示的是整个data数组
	//但&data的值也是数组首元素地址
	cout << "&data:" << &data << endl;
	//&data+1代表着除了data数组外,还多了一个与data相同的数组
	//因此其地址比data多sizeof(data),即4*9=36
	cout << "&data+1:" << &data+1 << endl;
	//*表示取地址,因此为data[0]
	cout << "*data:" << *data << endl;
	//可以将data[0]理解为一个指针,指向data
	cout << "data[0]:" << data[0] << endl;
	system("pause");
	return 0;
}

 

 

形参和实参的区别:

实参(argument):

  全称为"实际参数"是在调用时传递给函数的参数. 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。      

形参(parameter):

全称为"形式参数" 由于它不是实际存在变量,所以又称虚拟变量。是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数.在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值。

3、Swap函数一些注意事项

1)达不到交换的作用

template<class T>
void swap(T a,Tb)
{
  T temp=a;
  a=b;
  b=temp;
}

因为当main函数调用swap时,仅仅是相当于实参的数值赋予swap函数的形参(除此之外实参无作用),形参中的a,b确实进行了交换,但由于形参是局部变量,因此在swap函数结束时便销毁的形参。所以实参并不会进行swap的动作。

2)可以达到交换的作用

template<class T>
void swap(T &a,T &b)
{
    T c(a);
    a=b;
    b=c;
}

在swap函数中,其形参使用了引用&。引用即是对某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。而且引用本身并不占用内存,而是和目标变量共同指向目标变量的内存地址。因此对形参的操作就是对main函数中实参的操作,所以可以交换。

 

template<class T>
void swap(T *a,T *b)
{
    T temp;//不可以T *temp,因为指针必须初始化,否则其值不可预见
    temp=*a;
    *a=*b;
    *b=temp;
}

int main()
{
    int a=1,b=2;
    swap(&a,&b);
    return 0;
}

swap形参的类型为指针变量,因此main函数中需要传递的实参为带交换变量的地址,这样形参中的指针才有所指向的地址。在swap函数中,它操作的内容是在内存中此地址指向的数据,因此它确确实实交换了main中的变量。在swap结束后,存放实参地址的形参被销毁,但这不影响我们已经交换了的数据,注意区分与第一种的区别。

 

//使用异或的概念来交换数组
template<class T>
void swap(T &a,T &b)
{
    a^=b;
    b^=a;       //相当于b=a
    a^=b;       //相当于a=b
}


//使用加法的概念来交换数组
template<class T>
void swap(T &a,T &b)
{
    a=a+b;
    b=a-b;       //相当于b=a
    a=a-b;       //相当于a=b
}

 当传递的是数组时,不用引用却可以交换,具体分析如下:

#include <iostream>
using namespace std;

template<class T>
void swap_self(T data[])
{
	T tem = data[1];
	data[1] = data[0];//可以理解成*data+1=*data,取data首地址,即data[0],
					  //送到地址data[1]所指向的元素上,因此,虽然地址形参
					  //在函数结束后会销毁,但其操作的是地址指向的元素,
					  //交换之后不会随着地址形参的销毁而恢复
	data[0] = tem;
}
int main() {
	int data[] = { 2,8,6,1,10,15,3,12,11 };
	swap_self(data);//传递的是数组的首地址过去
	printdata(data, 9);
	system("pause");
	return 0;
}

new使用方法:

1 int *x = new int;       //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
2 int *a = new int(100);  //开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
3 char *b = new char[10]; //开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
4 float *p=new float (3.14159);//开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p

  1. int *a = new int;

    delete a;   //释放单个int的空间

2.int *a = new int[5];

    delete [] a; //释放int数组空间

3.指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身(指针p本身并没有撤销,它自己仍然存在,该指针所占内存空间并未释放),释放堆空间后,p成了空指针,注意,此时p成为了野指针!!delete指针p后必须设置指针p的地址为NULL方可。

有关new的良好变成习惯

1、指针变量没有被初始化

声明一个指针但未分配内存空间时,最好将其置为NULL。           char *pc = NULL;
2、指针超过了变量的作用范围。

char *pc = NULL;

pc = new char[5];

此时不但可以给p[0]到p[4]赋值,还可以给后面的地址赋值,如p[5],p[10]等。

这就是C/C++完美之余的一个历史遗留缺陷,不进行越界检查,导致编译没有任何问题,运行阶段有时一不小心也察觉不出,这就要求程序员养成良好的习惯:new后面必出现delete。

若我们在给p[5]或之后的地址赋过值,在运行到delete [] p;语句时,会报错,程序强制中断。错误原因如提示的信息:damage:after normal block。

这就是上面遗留的第二个问题*2:对同一个指针变量指向的内存释放两次,与释放一个没有成功分配内存或引用越界的指针变量类似,都是不允许的。

3、指针指向的内存被释放了,而指针本身没有置NULL

指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针.

char *p=new char[10];  //指向堆中分配的内存首地址,p存储在栈区
cin>> p;
delete []p; //p重新变为野指针

还需加上一句p=NULL;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值