c/c++易错知识点整理3(引用和指针)(一)

来源:互联网 发布:thinkphp5 写的 cms 编辑:程序博客网 时间:2024/06/13 23:29

1.一般变量

#include <iostream>

#include <string>using namespace std;int main(){      int a=10;      int b=20;      int &rn=a;      int equal;      rn=b;      cout<<a;      cout<<b;      rn=100;      cout<<a;      cout<<b;      equal=(&a==&rn)?1:0;      cout<<equal;} 

输出结果为:20,20,100,20,1

将rn声明为a的引用,不需要为rn另外开辟内存单元。rn和a占内存中的同一个存储单元,它们具有同一地址。


2.指针变量引用

#include <iostream>using namespace std;int main() {     int a=1;     int b=10;     int* p=&a;     int* &pa=p;                  //声明p的一个指针引用pa     (*pa)++;     cout<<"a="<<a<<endl;     cout<<"b="<<b<<endl;     cout<<"*p="<<*p<<endl;     pa=&b;     (*pa)++;     cout<<"a="<<a<<endl;     cout<<"b="<<b<<endl;     cout<<"*p="<<*p<<endl;     return 0;}

输出结果:a=2,b=10,*p=2,a=2,b=11,*p=11


3. 看代码找错误---变量引用

#include <iostream>using namespace std;int main(){ int a=1,b=2;        int &c;                //错误,声明了一个引用类型的变量,但是没有初始化。        int &d=a;        &d=b;                //错误,把d作为变量b的别名        int *p;         *p=5;                  // 错误,指针p未被初始化,p为野指针,不能对野指针赋值         return 0;}
引用类型的变量在声明的同时必须初始化。
引用只能在声明的时候被赋值,以后都不能再把该引用名作为其他变量名的别名。


4.如何交换两个字符串

void swap(char *&x,char *&y){      char *temp;      temp=x;      x=y;      y=temp;}




这里swap函数是利用传指针引用实现字符串交换的。由于swap函数是指针引用类型,因此传入函数的就是实参,而不是形参。
如果不用指针引用,那么指针交换只能在swap函数中有效,因为在函数体中,函数栈会分配两个临时的指针变量分别指向两个指针临时参数,对实际的ap和bp没有影响。
当然,如果不用引用,还可以用二维指针达到同样的目的。可以把swap函数的定义改为下面的形式。
void swap1(char **x,char **y){       char *temp;       temp =*x;       *x=*y;       *y=temp;}


调用函数形式swap1(&ap,&bp);
用这种传址的方式,同样可以起到交换两个字符串的目的。  


5.参数引用
#include <iostream.h>const float pi=3.14f;float f;float f1(float r){        f=r*r*pi;        return f;}int main(){     float f1(float=5);     float& b=f1();}


这里 float& b=f1()错误。因为在f1()函数里,全局变量f的值78.5赋给一个临时变量temp,这个temp变量由编译器隐式地建立,然后建立这个temp的引用b。这里对一个临时变量temp进行引用会发生错误。


常量引用类型参数即const type& 或type const &,函数体内不能被修改。
对于常量类型的变量,其引用也必须是常量类型的;对于非常量类型的变量。其引用可以是非常量的,也可以是常量的。但是要注意,无论什么情况,都不能使用常量引用修改其引用的变量的值。


6.指针和引用有什么区别


(1)初始化要求不同。引用在创建的同时必须初始化,即引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值。
(2)可修改性不同。引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是改变它和原始对象的绑定关系。
(3)不存在NULL引用,引用不能使用指向空值的引用,它必须总是指向某个对象;而指针则可以是NULL,不需要总是指向某些对象,可以把指针指向任意的对象,所以指针更加灵活,也容易出错。
(4)测试需要的区别。由于引用不会指向空值,这意味着使用引用之前不需要测试它的合法性;而指针则需要经常进行测试。因此使用引用的代码效率比使用指针的要高。
(5)应用的区别。如果是指一旦指向一个对象后就不会改变指向,那么应该使用引用。如果有存在指向NULL(不指向任何对象)或在不同的时刻指向不同的对象这些可能性,应该使用指针。
实际上,在语言层面,引用的用法和对象一样;在二进制层面,引用一般都是通过指针来实现,只不过编译器帮我们完成了转换。总体来说,引用既具有指针的效率,又具有变量使用的方便性和直观性。


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


由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。
对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或者NULL,所以不安全。const指针仍然存在空指针,并且有可能产生野指针。


8.复杂指针的声明


用变量a给出下面的定义
a.一个整型数
b.一个指向整型数的指针
c.一个指向指针的指针,它指向的指针是指向一个整型数的
d.一个有10个整型数的数组
e.一个有10个指针的数组,该指针是指向一个整型数的
f.一个指向有十个10个整型数数组的指针
g.一个指向函数的指针,该函数有一个整型参数并返回一个整型数
h.一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
a.int a
b.int* a
c.int** a
d.int a[10]
e.int* a[10]
f.int (*a)[10]
g.int(*a)(int)
h.int  (*a[10])(int)


9. 指针加减操作
#include <stdio.h>int main(){      int a[5]={1,2,3,4,5};      int *ptr=(int*)(&a+1);      printf("%d\n",*(a+1));      printf("%d\n",*(ptr-1));}

输出为:2;5
对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址值直接加1。所以,一个类型为t的指针的移动,以sizeof(t)为移动单位。
代码第6行,ptr是一个int型的指针&a+1,即取a的地址,该地址的值加sizeof(a)的值,即&a+5*sizeof(int),也就是a[5]的地址,显然,当前指针已经越过了数组的界限。(int*)(&a+1)是把上一步计算出来的地址强制转换为int*类型,赋值给ptr。



10.指针比较

#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";          cout<<(str1==str2)<<endl;     cout<<(str3==str4)<<endl;     cout<<(str5==str6)<<endl;     cout<<(str6==str7)<<endl;     cout<<(str7==str8)<<endl;}


0,0,1,1,1
这个程序考查的是内存中各个数据的存放方式。
数组str1、str2、str3和str4都是在栈中分配的,内存中的内容都为“abc“加一个‘\0',但是它们的位置是不同的。
指针str5、str6、str7和str8也是在栈上分配的,它们都指向“abc“字符串,注意“abc"存放在数据区,所以str5、str6、str7和str8其实指向同一块数据区的内存。

原创粉丝点击