2.C/C++引用和指针

1.一般变量引用

#include<iostream>
#include<string>
using namespace std;
int main()
{
int a = 10;
int b = 20;
int &rn = a; //声明rn为变量a的一个引用
int equal;

rn = b;    //将b的值赋值给rn。此时rn其实就是a的一个别名,对rn赋值
         //其实就是对a的赋值。因此执行完赋值后,a的值就是b的值,即都是20;
cout << "a = " << a << endl;  //a=20
cout << "b = " << b << endl;  //b=20

rn = 100;  //将100赋值给rn,于是,a的值就变成了100
cout << "a = " << a << endl;  //a=100
cout << "b = " << b << endl;  //b=20

equal = (&a == &rn) ? 1 : 0; //将a的地址与rn的地址进行比较,如果相等,变量equal的值为1,否则为0
                           //将rn声明为a的引用,不需要为rn另外开辟内存单元。rn和a占内存中的同一个
                           //存储单元,它们具有同一地址,所以equal为1.
cout << "equal = " << equal << endl;  //equal=1
return 0;
}

a = 20

b = 20
a = 100
b = 20
equal = 1



2.指针变量引用

//2.指针变量引用
#include<iostream>
using namespace std;
int main()
{
	int a = 1;
	int b = 10;
	int* p = &a;  //声明整型的指针变量p并初始指向a
	int* &pa = p; //声明p是一个指针引用pa
	 
	(*pa)++;   //将pa指向的内容加1。由于pa是p的引用,所以此时实际上是对p指向的内容加1,
	           // 也就是a加1,结果为a变成了2.
	cout << "a = " << a << endl; //a=2
	cout << "b = " << b << endl;  //b=10
	cout << "*p = " << *p << endl;  //*p=2
	 
	pa = &b;   //将pa指向b的地址,由于pa是p的引用,所以此时p也指向b的地址。
	(*pa)++;   //将pa指向的内容加1,也就是b加1,b就变成了11
	cout << "a = " << a << endl;  //a=2
	cout << "b = " << b << endl;  //b=11
	cout << "*p = " << *p << endl;  //*p=11
	return 0;
}

a = 2
b = 10
*p = 2
a = 2
b = 11
*p = 11



3.用参数引用交换两个字符串

//3.用参数引用交换两个字符串
#include<iostream>
#include<string.h>
using namespace std;
void swap(char *&x, char *&y) //swap函数是利用传指针引用实现
{                             //字符串交换的。由于swap函数是指针引用类型,
	char *temp;              //因此传入函数的是实参,而不是形参
	temp = x;               //如果不用指针引用,那么指针交换只能在swap函数中有效,
	x = y;                 //因为在函数体中,函数会分配两个临时的指针变量分别指向
	y = temp;              //两个指针参数,对实际的ap和bp没有影响
}
int main()
{
	char *ap = "hello";
	char *bp = "how are you";

	cout << "ap: " << ap << endl;
	cout << "bp: " << bp << endl;

	swap(ap, bp);

	cout << "swap ap,bp" << endl;
	cout << "ap: " << ap << endl;
	cout << "bp: " << bp << endl;

	return 0;
}

ap: hello
bp: how are you
swap ap,bp
ap: how are you
bp: hello


4.指针和引用的区别

(1)初始化要求不同。引用在创建的同时必须初始化,即引用到一个有效的对象;而指针在定义的时候不比初始化,可以在定义后面的任何地方重新赋值。

(2)可修改性不同。引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是改变它和原始对象的绑定关系。

(3)不存在NULL引用,引用不能使用指向空值的引用,它必须总是指向某个对象;而指针则可以是NULL,不需要总是指向某些对象,可以把指针指向任意的对象,所以指针更加灵活,也容易出错。

(4)测试需要的区别。由于引用不会指向空值,这意味着引用之前不需要测试它的合法性;而指针则需要经常进行测试。因此使用引用的代码效率比使用指针的要高。

(5)应用的区别。如果是指一旦指向一个对象后就不会改变的指向,那么应该使用引用。如果有存在指向NULL(不指向任何对象)或在不同的时刻指向不同的对象这些可能性,应该使用指针。



5.为什么传引用比传指针安全

由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。

对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为NULL,所以不安全。const指针仍然存在空指针,并且有可能产生野指针。



6.复杂指针的声明

用变量a给出下面的定义

(1)一个整型数:int a

(2) 一个指向整型数的指针:int *a

(3)一个指向指针的指针,它指向的指针是指向一个整型数的:int **a;

(4)一个有10个整型数的数组:int a[10]

(5)一个有10个指针的数组,该指针是指向一个整型数的:int* a[10]

(6)一个指向有10个整型数数组的指针:int(*a)[10]

(7)一个指向函数的指针,该函数有一个整型参数,该参数有一个整型参数并返回一个整型数:int(*a)(int)

(8)一个有10指针的数组,该指针指向一个函数,该指针指向一个函数,该函数有一个整型参数并返回一个整型数:int(*a[10])(int)




7.用指针赋值

//7.用指针赋值
#include<stdio.h>
int main()
{
	char a[] = "hello,world"; //声明了一个数组a,并初始化,包括以'\0'结束字符。
	char *ptr = a;         //声明一个字符指针ptr,并初始化指向数组a首(a的第一个元素地址)

	printf("%c\n", *(ptr + 4)); //将ptr加4,在输出地址的内容,也就是指向了输出a[4]的内容
	printf("%c\n", ptr[4]);   //ptr[4]和*ptr[4]一样,也是a[4]的内容
	printf("%c\n", a[4]);    //输出a[4]的内容
	printf("%c\n", *(a + 4)); //*(a+4)与a[4]一样,也是a[4]的内容

	*(ptr + 4) += 1;      //使数组a[4]的内容加1,'o'加1后就是'p'
	printf("%c\n", *(ptr + 4));
	
	return 0;
}

o
o
o
o
p



8.指针加减操作


//8.指针加减操作
#include<stdio.h>
int main()
{
	int a[5] = {1,2,3,4,5 };
	int *ptr1 = (int *)(&a + 1); //a与&a的地址是一样的,但是意思不一样,a是数组首地址,也就是a[0]的地址;
	printf("%d\n", ptr1);       //&a是对象(数组)首地址,a+1是数组下一个元素的地址,即a[1];
	                            //而&a+1是下一个对象的地址,即&a+5*sizeof(int)即a[5]
	printf("%d\n", *(ptr1 - 1)); //输出a[4],即5
	
	int *ptr = (int *)(a + 1); //指向数组a中的第二个元素
	printf("%d\n", *ptr);      //
	printf("%d\n", *(a + 1));  //也是指向a中的第二个元素

	return 0;
}

//对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址直接加1。所以,一个类型为t的指针的移动,以sizeof(t)为移动单位。


1900248
5
2
2



9.指针比较

//9.指针比较
#include<iostream>
using namespace std;

int main()
{
	char str1[] = "abc";
	char str2[] = "abc";
	const char str3[] = "abc";
	const char str4[] = "abc";
	const char* str5 = "abc";
	const char* str6 = "abc";
	char* str7 = "abc";
	char* str8 = "abc";

	//数组str1,str2,str3,str4都在在栈中分配的,内存中的内容都为“abc”加上一个'\0',但是它们的位置是不同的
	//因此前两个输出都是0;
	//指针str5,str6,str7,str8也都是在栈中分配的,它们都指向"abc"字符串,注意“abc”存放在数据区,
	//所以str5,str6,str7,str8其实指向同一块数据区的内存,所以后三个都输出是1
	cout << (str1 == str2) << endl; //0
	cout << (str3 == str4) << endl; //0
	cout << (str5 == str6) << endl;
	cout << (str6 == str7) << endl;
	cout << (str7 == str8) << endl;

	return 0;
}

0
0
1
1
1



10.指针常量与常量指针的区别

常量指针就是指向常量的指针,它所指向的地址的内容是不可修改的。

指针常量就是指针的常量,它是不可改变地址的指针,但是可对所指向的内容进行修改。



11.const关键字在指针声明时的作用

char * const p1;

char const * p2;

const char *p3;

const char * const p4;

如果const位于 * 号的左侧,则const 就是用来修饰指针所指的向量,即指针指向为常量;如果const 位于 * 号的右侧,const 就是修饰指针本身,即指针本身是常量。

p1 是指针常量,它本身不能被修改,指向的内容可以被修改。

p2和p3是常量指针,它本身可以被修改,指向的内容不可以被修改。

p4本身是常量,并且它指向的内容也不可以被修改。




12.指针数组与数组指针的区别

//12.指针数组与数组指针的区别

//指针数组指一个数组里存放的都是同一个类型的指针,例如
// int * a[10]
//数组a里面存放了10个int* 型变量

//数组指针指一个指向一维或多维数组的指针,例如
//int * b=new int[10]
//指针b指向含有10个整型数据的一维数组。注意,这个时候释放空间一定要delete[],否则会造成内存泄漏。

#include<iostream>
using namespace std;
int main()
{
	int x1[4] = { 1,2,3,4 };
	int x2[2] = { 5,6 };
	int x3[3] = { 7,8,9 };
	int *a[2];  //定义指针数组a
	int *b = x1; //数组指针b指向了数组x1
	int i = 0;

	a[0] = x2;  //a里的量指针元素分别指向了数组x2和x3
	a[1] = x3;

	cout << "输出a[0]: ";
	for(i=0;i<sizeof(x2)/sizeof(int);i++)
	{
		cout << a[0][i] << " ";
	}
	cout << endl;

	cout << "输出a[1]: ";
	for (i = 0; i < sizeof(x3) / sizeof(int); i++)
	{
		cout << a[1][i] << " ";
	}
	cout << endl;

	cout << "输出b: ";
	for (i = 0; i < sizeof(x1) / sizeof(int); i++)
	{
		cout << b[i] << " ";
	}
	cout << endl;
	return 0;
}

输出a[0]: 5 6
输出a[1]: 7 8 9
输出b: 1 2 3 4



13.函数指针和指针函数

指针函数是返回指针类型的函数

定义如下:

返回类型标识符   *返回名称   (形式参数表)    {  函数体  }

函数指针是指向函数地址的指针。

//13.函数指针和指针函数
#include<iostream>
using namespace std;
int max(int x, int y)
{
	return (x > y ? x : y);
}

float *find(float *p, int x)   //函数find()被定义为指针函数
{
	return p + 1;
}

int main()
{
	float score[] = { 10,20,30,40 };
	int(*p)(int, int);  //指针p被定义为函数指针类型
	float *q = find(score + 1, 1); //
	int a;

	p = max;  //指针p被赋为max()函数的地址
	a = (*p)(1, 2); //使用指针p就能完成调用max()函数的目的

	cout << "a = " << a << endl;
	cout << "*q = " << *q << endl;

	return 0;
}

a = 2
*q = 30



14.函数指针的使用

//14.函数指针的使用
#include<stdio.h>
int add1(int a1, int b1);
int add2(int a2, int b2);
int main()
{
	int numa1 = 1, numb1 = 2;
	int numa2 = 2, numb2 = 3;
	int(*op[2])(int a, int b); //定义了一个函数指针数组op,它包含两个指针元素
	op[0] = add1;             //第一个指针元素指向了add1的地址
	op[1] = add2;             //第二个指针元素指向了add2的地址
	
	printf("%d %d\n", op[0](numa1, numb1), op[1](numa2, numb2)); //使用函数指针调用add1和add2这两个函数

	return 0;
}
int add1(int a1, int b1)
{
	return a1 + b1;
}
int add2(int a2, int b2)
{
	return a2 + b2;
}

3 5



15.什么是野指针

“野指针”不是NULL指针,而是指向 “垃圾” 内存的指针。其成因主要为:指针变量没有被初始化,或指针p被free或者delete之后,没有置为NULL。



16. malloc/free 和 new/delete的区别

malloc与free是C++/C的标准库函数,new/delete是C++的运算符。他们都可用于申请内存和释放内存。

对于非内部数据类型而言,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是元算符,不在编译器控制权限之内,不能把执行构造函数和析构函数的任务强加于malloc/free,(即用malloc/free不会执行构造函数和析构函数)。因此只有使用new/delete函数。

//16.malloc/free和new/delete的区别
#include<iostream>
using namespace std;
class Obj
{
public:
	Obj(void)
	{
		cout << "Initialization" << endl;
	}
	~Obj()
	{
		cout << "Destroy" << endl;
	}
};
void UseMallocFree(void)   //用malloc/free申请和释放堆内存,类的构造函数和析构函数函数不会被调用
{
	cout << "in UseMallocFree()....." << endl;
	Obj *a = (Obj*)malloc(sizeof(Obj));
	free(a);
}
void UseNewDelete(void)   //用new/delete申请和释放内存,类的构造函数和析构函数函数都会被调用
{
	cout << "in UseNewDelete()....." << endl;
	Obj *a = new Obj;
	delete a;
}
int main()
{
	UseMallocFree();  //类的构造函数和析构函数函数不会被调用
	UseNewDelete();  //类的构造函数和析构函数函数都会被调用

	return 0;
}

in UseMallocFree().....
in UseNewDelete().....
Initialization
Destroy



17.内存的分配方式有几种

静态存储区、栈、堆的内存分配。

(1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量。

(2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

(3)从堆上分配,亦称动态内存分配。程序运行的时候用malloc或new申请多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非     常灵活,但问题也最多。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术提高效率

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值