浅析c/c++中的指针

2016-02-19 18:36 3 1 收藏

下面是个简单易学的浅析c/c++中的指针教程,图老师小编详细图解介绍包你轻松学会,喜欢的朋友赶紧get起来吧!

【 tulaoshi.com - 编程语言 】


  在学习c/c+过程中,指针是一个比较让人头痛的问题,稍微不注重将会是程序编译无法通过,甚至造成死机。在程序设计过程中,指针也往往是产生隐含bug的原因。下面就来谈谈指针的应用以及需要注重的一些问题,里面也许就有你平时没有注重到的问题,希望能帮助各位读者理解好指针。 !-- frame contents -- !-- /frame contents --
  
  一、我们先往返忆一下指针的概念吧,方便下面的介绍
  
  指针是存放地址值的变量或者常量。例如:int a=1;&a就表示指针常量(“&”表示取地址运算符,也即引用)。int *b,b表示的是指针变量(注重,是b表示指针变量而不是*b),*表示要说明的是指针变量。大家注重int *b[2]和int(*b)[2]是不同的,int *b表示一个指针数组,而int (*b)[2]表示含有两个元素的int指针,这里要注重运算优先级问题,有助于理解指针问题。
  
  在这里大概介绍基本概念就够了,至于具体使用方法,如赋值等,很多书都有介绍,我就不多说了。
  
  二、应用以及注重的问题
  
  1、 理解指针的要害所在——对指针类型和指针所指向的类型的理解
  
  ①、 指针类型:可以把指针名字去掉,剩下的就是这个指针
  
  例如:int *a;//指针类型为int *
  
  int **a;//指针类型为int **
  
  int *(*a)[8];//指针类型为 int *(*)[8]
  ②、 指针所指向的类型:是指编译器将把那一片内存所看待成的类型。这里只要把指针声明语句中的指针名字和名字右边的“*”号去掉就可以了,剩下的就是指针所指向的类型。
  
  我之所以把他们放在第一位,是因为弄清楚他们是学c/c++指针的重点,正确理解他们才能使你打好c/c++的编程基础。
  
  2、 指针的应用——传递参数。
  
  其实它可以相当于隐式的返回值,这就比return的方法更加灵活了,可以返回更多的值,看看下面的例子自然就明白了:
  
  #include "iostream.h"
  
  void example(int *a1,int &b1,int c1)
  
  {
  
   *a1*=3;
  
   ++b1;
  
   ++c1;
  
  }
  
  void main()
  
  {
  
   int *a;
  
   int b,c;
  
   *a=6;
  
   b=7;c=10;
  
   example(a,b,c);
  
   cout "*a="*a  
   cout "b="  
   cout "c="  
  }
  
  输出:*a=18
  
  b=8
  
  c=10
  注重到没有,*a和b的值都改变了,而c没有变。这是由于a1是指向*a(=6)的指针,也即与a是指向同一个地址,所以当a1指向的值改变了,*a的值也就改变了。在函数中的参数使用了引用(int &b1),b1是b的别名,也可以把它当作非凡的指针来理解,所以b的值会改变。函数中的参数int c1只是在函数中起作用,当函数结束时候便消失了,所以在main()中不起作用。
  
  3、 关于全局变量和局部变量的一个问题
  
  先不废话了,先看看程序:
  
  #include “iostream.h”
  
  int a=5;
  
  int *example1(int b)
  
  {
  
  a+=b;
  
  return &a;
  
  }
  
  int *example2(int b)
  
  {
  
  int c=5;
  
  b+=c;
  
  return &b;
  
  }
  
  void main()
  
  {
  
  int *a1=example1(10);
  
  int *b1=example2(10);
  
  cout ”a1=”*a1  
  cout ”b1=”*b1  
  }
  
  输出结果:
  
  a1=15
  
  b1=4135
  *b1怎么会是4135,而不是15呢?是程序的问题?没错吧?
  
  由于a是全局变量,存放在全局变量的内存区,它一直是存在的;而局部变量则是存在于函数的栈区,当函数example2()调用结束后便消失,是b指向了一个不确定的区域,产生指针悬挂。
  
  下面是对example1()和example2()的反汇编(用TC++ 3.0编译):
  
  example1():
  
  push bp;入栈
  
  mov bp,sp
  
  mov ax,[bp+04];传递参数
  
  add [00AA],ax;相加
  
  mov ax,00AA ;返回了结果所在的地址
  
  .
  
  
  .
  
  .
  
  pop bp;恢复栈,出栈
  
  ret;退出函数
  
  
  example2():
  
  push bp;入栈
  
  mov bp,sp
  
  sub sp,02
  
  mov Word ptr [bp-02],0005
  
  mov ax,[bp-02];传递参数
  
  add [bp+04],ax;相加
  
  lea ax,[bp+04];问题就出在这里
  
  .
  
  .
  
  .
  
  mov sp,bp
  
  pop bp;恢复栈,出栈
  
  ret;退出函数
  对比之后看出来了吧?ax应该是存储的是结果的地址。而在example2()中,返回的却是[bp+04]的内容,因此指针指向了一个不确定的地方,由此产生的指针悬挂。example1()中,ax返回了正确的结果的地址。
  
  4、 内存问题:使用指针注重内存的分配和边界。
  
  使用指针过程中应该给变量一个适当的空间,以免产生不可见的错误。
  
  请看以下代码:
  
  #include “iostream.h”
  
  void main()
  
  {
  
  char *a1;
  
  char *a2;
  
  cin a1;
  
  cin a2;
  
  cout ”a1=”
  cout ”a2=”
  }
  
  输入:abc
  
  123
  
  输出:
  
  a1=123
  
  a2=
  
  Null pointer assignment
  指针指向了“空”。解决办法就是分配适当的内存给这两个字符串。修正后的代码如下:
  
  #include “iostream.h”
  
  void main()
  
  {
  
  char *a1;
  
  char *a2;
  
  a1=new char [10];
  
  a2=new char [10];
  
  cin a1;
  
  cin a2;
  
  cout ”a1=”
  cout ”a2=”
  delete(a1);注重,别忘了要释放内存空间
  
  delete(a2);
  
  }
  到此就能输出正确的结果了。
  
  分配了适当的内存之后要注重释放内参空间,同时还应该注重不要超出所分配的内存的大小,否则会有溢出现象产生,导致不可预料的结果。
  
   5、 关于非凡的指针——引用
  
  引用有时候应用起来要比指针要灵活,用它做返回的时候是不产生任何变量的副本的这样减小了内存的占用,提高执行的速度。引用使用起来要比指针好理解,比较直观。当引用作为参数时,不会改变参数的地址,因此可以作为左值。
  
  下面请看一个例子:
  
  #include “iostream.h”
  
  char ch[5]=”ABCD”;
  
  char &example(int b)
  
  {
  
  return ch;
  
  }
  
  void main()
  
  {
  
  cout ”ch=”  
  example(2)=”c”;
  
  cout”ch=”  
  }
  
  输出结果:
  
  ch=ABCD
  
  ch=ABcD
  在实际编程过程中,可以灵活地引用或指针,尽量提高程序的可读性和执行效率。
  
  三、小结:
  
  指针是学习c/c++的重点难点,主要原因是指针较为抽象,不轻易理解。使用指针千万要明白让指针指向什么地方,如何让指针指向正确的地方。在深入系统底层之中需要应用到大量的指针,因此需要理解好指针的基本概念,例如:指针类型和指针所指向的类型。平时应该对留心观察,了解程序的工作过程,必要时候可以对程序进行反汇编,加深对指针的理解,这种方法同样适合学别的编程方面的知识。
  
  四、结束:
  
  指针的应用是很广泛的,利用指针可以做很多事情,要成为一个好的程序员,必须对指针有比较深刻的了解。写本文的目的在于让大家对指针有更深一层的了解,提高指针的应用能力,内容大都是我在实际编程中碰到的问题。相信能给大家一定的帮助。
  
  
  

来源:http://www.tulaoshi.com/n/20160219/1618288.html

延伸阅读
译者序: 本文介绍了一种在调试过程中寻找悬挂指针(野指针)的方法,这种方法是通过对new和delete运算符的重载来实现的。 !-- frame contents -- !-- /frame contents -- 这种方法不是完美的,它是以调试期的内存泄露为代价来实现的,因为文中出现的代码是绝不能出现在一个最终发布的软件产品中的,只能在调试时使用。 ...
对于数组和多维数组的内容这里就不再讨论了,前面的教程有过说明,这里主要讲述的数组和指针类型的关系,通过对他们之间关系的了解可以更加深入的掌握数组和指针特性的知识! 一个整数类型数组如下进行定义 int a[]={1,2,3,4}; 如果简单写成 a;//数组的标识符名称 这将代表的是数组第一个元素的内存地址,a;就相当于&a...
//程序作者:管宁 //站点:www.cndev-lab.com //所有稿件均有版权,如要转载,请务必著名出处和作者 #include iostream #include string using namespace std; void print_char(char* array[]);//函数原形声明 void main(void) { char* test[]={"abc","cde","fgh",NULL};//这里添加一个NULL,表示不指向任何地址,值为0 print_char(test)...
1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误。本文将对void要害字的深刻含义进行解说,并详述void及void指针类型的使用方法与技巧。 2.void的含义 !-- frame contents -- !-- /frame contents -- void的字面意思是“无类型”,void *则为“无类型指针”,v...
     智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始...

经验教程

479

收藏

67
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部