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

来源:互联网 发布:isis软件使用方法 编辑:程序博客网 时间:2024/06/05 16:09

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=20cout << "b = " << b << endl;  //b=20rn = 100;  //将100赋值给rn,于是,a的值就变成了100cout << "a = " << a << endl;  //a=100cout << "b = " << b << endl;  //b=20equal = (&a == &rn) ? 1 : 0; //将a的地址与rn的地址进行比较,如果相等,变量equal的值为1,否则为0                           //将rn声明为a的引用,不需要为rn另外开辟内存单元。rn和a占内存中的同一个                           //存储单元,它们具有同一地址,所以equal为1.cout << "equal = " << equal << endl;  //equal=1return 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并初始指向aint* &pa = p; //声明p是一个指针引用pa (*pa)++;   //将pa指向的内容加1。由于pa是p的引用,所以此时实际上是对p指向的内容加1,           // 也就是a加1,结果为a变成了2.cout << "a = " << a << endl; //a=2cout << "b = " << b << endl;  //b=10cout << "*p = " << *p << endl;  //*p=2 pa = &b;   //将pa指向b的地址,由于pa是p的引用,所以此时p也指向b的地址。(*pa)++;   //将pa指向的内容加1,也就是b加1,b就变成了11cout << "a = " << a << endl;  //a=2cout << "b = " << b << endl;  //b=11cout << "*p = " << *p << endl;  //*p=11return 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],即5int *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其实指向同一块数据区的内存,所以后三个都输出是1cout << (str1 == str2) << endl; //0cout << (str3 == str4) << endl; //0cout << (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];  //定义指针数组aint *b = x1; //数组指针b指向了数组x1int i = 0;a[0] = x2;  //a里的量指针元素分别指向了数组x2和x3a[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释放内存。动态内存的生存期由我们决定,使用非     常灵活,但问题也最多。

原创粉丝点击