Chinaunix首页 | 论坛 | 博客
  • 博客访问: 553349
  • 博文数量: 233
  • 博客积分: 2221
  • 博客等级: 大尉
  • 技术积分: 3184
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-16 14:01
个人简介

瓜瓜派的瓜瓜

文章分类

全部博文(233)

文章存档

2013年(28)

2012年(197)

2011年(8)

分类: IT业界

2012-01-09 15:52:33

想吃肉的兔兔 @ 2010年02月6日


这篇C++指针基础是兔兔不呕心不沥血,边CWOW,边QQ 写出来的,所以看官们不管觉得写的好不好不要骂我就是了。。。。

在C/C++最大的特点是指针的使用,特别是C++(主要我比较熟悉C++ = 。=||);由于贴图不是很方便,内存地址的示意图我就不画

了,我尽可能用比较清楚的语句表述我想说的内容

那么我们为什么需要使用指针呢?比如我们在写一个较为复杂的程序,我们这个程序用了很多函数,这时我们可能需要让一个函数将

一个数据地址传给另外一个函数,这样程序中会复制大量的代码,为了避免这个情况,我们就需要用到指针。在C/C++中这是对函数

传值的修改最便捷的方法之一。

到底什么是指针?指针就是存储内存地址的变量。
指针的本质也就是个变量,是存放的是变量地址的变量其逻辑是独立的。指针式可以改变滴,包括其所指向的地址的改变和指向的地

址所存放的数据的改变。(注意:指针本身也是一种数据类型)
  
看了上面的东西是不是晕乎乎的,现在我们先从地址讲起,到底什么是地址?(本文提到的地址皆为内存地址)
在计算机所有内存位置都会有个数值地址,虽然你曾经听过、用过(金山游戏修改游戏)、或者从来不知道,这些都没有关系,现在

我们来了解下什么是地址。我们又来假设你在写程序,而且应用了某个变量,比如OOXX,对我们人眼看到的就是变量的引用,实际上

对于计算机他是不知道的,这个时候通过编译器、链接器、加载器、会在内存里面申请一块地址给OOXX,因为是CPU唯一能认知的就

是这个地址,地址会加载到一个CPU得寄存器中,根据他来访问内存的数据项。内存地址,是为了区分各种不同数据的,而每个地址

则相对应一个数据。

指针需要初始化在初始化过程中可以指向一个地址,当然也是可以为空的。
指针变量的声明一般为:
   <数据类型> *<指针名称>;(符号“*”是指针类型说明符,声明变量是一个指针型变量)
   好吧书上声明是: type *name;(注:type *name和type* name是一样的)
比如我们现在声明一个int类型的指针 ooxx,就是int *ooxx;
注意这个时候我们只是简单的声明了指针,并没有初始化,而且只能指向int类型的数据元素,现在我们来写个完整的用法:
    int *xxoo;
    int  ooxx = 1;//声明整形OOXX且赋值为1
    xxoo = &ooxx;  //xxoo指向了ooxx   ,“&“为取地址操作符
从上面的语句运行就得到0x开头的8位16进制数,这就是ooxx在内存中的地址
请看一段完整的代码:
int main(int argc, char *argv[])
{
    int oo=2;
    int *xx;
    xx=&oo;//得到oo的地址
    cout<<”oo=2的地址是:”<    *xx=20;//这里是新的值获取(引传用),尤其体现指针的方便
    cout<<”oo的新值是”<    system(“PAUSE”);
    return EXIT_SUCCESS;
}

再来看看很特殊的值——null
没有初始化的指针变量是危险的。可是如果在声明变量之后,找不到合适的地址进行初始化,我们该怎么办呢?显然,随便找个地址

对指针变量做初始化是不负责任的。在这里,我们引入一个特殊的地址——NULL。它的意思是“空”,即指针没有指向任
何东西。比如:int *iptr=NULL;

再来看一组代码算是对上面的总结,顺便把指针地址、指针保存的地址以及指针地址的值做一个辨析:
#include
#include

using namespace std;

int main(int argc, char *argv[])
{
    int a;
    int *p=0;
    cout<<”a的地址为: “<<&a<    cout<<”P的地址为: “<<&p<    cout<<”p的值为:” <    a=3;
    p=&a;
     cout<<”a的地址为: “<<&a<    cout<<”P的地址为: “<<&p<    cout<<”a的值为:” <    system(“PAUSE”);
    return EXIT_SUCCESS;
}

不知道大家有没注意到我的*p的初值是0,这里把0赋予*p是大家需要值得注意的地方。这个和上面null是一样滴

想到上面的 我就顺带提一下空指针吧,指针式用来保存内存地址的变量,所以我们的指针要是用的不当会给我们带来很大的麻烦。

如果一个指针没有来保存内存地址那么它就是一个失控指针,可以指向任何地址并且可以对值进行修改。所以我们为了要避免这种情

况 一般情况就是把指针初始化为0.大家可以看看初始为0的指针地址 一定是00000000,这样我们就可以很烦西的使用指针了~
有了上面的一些基础 貌似我们就能做的更多了 比如指针的运算,我们依然用比较简单的程序来说明问题(= =||我承认我马上要下

副本去拿蛋刀了,上天啊 出一把主手蛋刀吧)

#include
#include

using namespace std;

void ooxx(int *ox);
void ooxx(int *ox)
{
    *ox*=10;// *ox=*ox * 10
   
}
int main(int argc, char *argv[])
{
    int oo=2;
    ooxx(&oo);//传递oo的地址实现了函数的运用
    cout<<”oo的新值=”<   
    system(“PAUSE”);
    return EXIT_SUCCESS;
}
参数再传给一个函数的时候,函数会获得参数的一个拷贝,但是函数一旦返回,拷贝就被丢弃了,但是如果函数获得的是变量的地址

,就可以使用那个地址,对变量的自身的原始拷贝进行更改。所以为了让一个函数能够更改变量的值,就只有使用指针。

PS:没有出蛋刀 又出了风戒指和蛋盾,难过的很,我们团又是一往无前的继续黑手,折戟团里都开始准备分给SM了 ,还老是出蛋盾

,悲剧。

现在我们在写个略微复杂的程序再来看看,这次我们来玩数组(指针的高效处理数组是指针的一个特性)
这次继续数组排序,首先我们先来看下指针如何进行值的交换(其实和普通的交换都是一样的。。。就当凑字数吧)
我们在不使用指针的情况下是这样交换的:
a=b;
b=c;
c=a;
指针也是一样的 还记得*p就是当做变量吗?
  a=*b;
*b=*c;
*c=a;
这样就很轻松的改变了数的交换,注意这里的脚手架内存地址没有变,改变的只是内存中存放的数据。你把上面的写在函数体中,

你就可以给任意的2个数排序包括数组。

现在看一个升级版的互换:也就是数组排序
#include
#include

using namespace std;

void sort(int n);
void swap(int *p1,int *p2);
int a[10];

void sort(int n)
{
  int i,j,low;
  for (i=0;j     if (a[j]   low=j;
  if (i !=low)
swap(&a, &a[low]) ;
}

void swap(int *p1,int *p2)
{
int temp=*p1;
*p1 = *p2;
*p2=temp;
}
int main()
{
  int i;
  for (i=0;i<10;i++)
  cout<<”Enter array element “<  cin>>a;

   system(“PAUSE”);
    return EXIT_SUCCESS;
  
}

经过上面的学习应该都看得明白吧(小心翼翼的问。。。)

现在来看看数组和指针的关系,虽然上面已经用到了,这里还是罗嗦几句,虽然我认为大家都差不多明白了 = = ||

其实我们的指针的一个很大的用途就是用在高效和方便的是处理指针,看过很多大牛的作品就发现,用指针处理数是时非常多的。在

谭浩强的书里面也是大篇幅讲解指针对数组的处理,足以见得指针在数组处理的重要性,好了废话那么多,现在开始看看指针和数组

的处理。

数组的概念这里就不多说了,现在我们先来了解下基本的知识
我们现在假设声明一个数组int a[5]={1,2,3,4,5};
int *p;
p=a;//你也可以写成 int *p=&a[0];(千万不小写成*p=&a)
上面的获取地址其实就是&a[0],原因是数组名是个常量,它对应的是数组的第一个元素地址
现在留段程序大家自己去读吧,深入的体会下:
#include
#include

using namespace std;

int main(int argc, char *argv[])
{
   
    int a[6]={1,2,3,4,5};
    int *p1;
    int *p2;
    p1=a;
    p2=a+2;
    cout<    cout<        system(“PAUSE”);
    return EXIT_SUCCESS;
}

这里有个重要的概念:我们在地址运算上加减一个整数值的时候 编译器会自动为那个整数乘上基本类型的大小(貌似很多书上都么

有说)。看教程的同学一定要牢牢记住,这个很关键的概念,以后就会知道他的好处了。

我们再说下指针数组和数组指针的概念(传说很多人搞混):
指针数组:一个数组里存放的都是同一个类型的指针,通常我们把他叫做指针数组。
数组指针:一个指向一维或者多维数组的指针;

最后讨论下指针泄露 ,这里说明一下 由于时间的问题,我们在指针关于堆和栈的相关基础知识请大家自己学习,这里只小小的讨论

下指针泄露,不做深入讨论。为什么要说这个呢?不光是指针泄露的问题,其实在日常的工作中我们也会很多的使用到,当我们通常

会把较大的数据放入堆,然后用存放在栈的指针指向它,在提高运行的速度同时也就避免碎片的产生。这里我想在插一句 我们在用

指针的时候要注意我们需要即使的腾出内存空间,所以我们要及时的把不用的内存空间释放。在释放内存的时候一定要为p[0],p

[1],p[2],单独delete[] ,否则又会造成内存泄露,在delete[]p 的时候一定先delete p[0]; delete p[1],然后再把给p申请的空间

释放掉 delete [] p ……这样会防止内存泄露。 现在给段的代码示范下:
#include
#include

using namespace std;

int main(int argc, char *argv[])
{
    int *p = new int ;
    *p=1;
    cout<<*p<    delete p;
    cout<<*p<    long *p1=new long;
    cout<    *p1=1111111;
    cout<    *p=2;
    cout<<*p<    cout<<*p1<    delete p1;
    system(“PAUSE”);
    return EXIT_SUCCESS;
}

运行下,看了结果,原因就不言而喻了。
指针虽然好用灵活但是我们用的时候一定要小心小心+小心~

好了到这里吧,就到这里

最后说一下,程序设计的关键我个人认为是要多做题,甚至可以说是多做基本的题,熟能生巧,选定一门合适自己的语言用题目来熟

悉语言的特性。其实谭浩强的书我一直觉得课后习题很好,很能锻炼程式设计,真的很不错。

后记:磨磨蹭蹭写了很久 主要是不敢写太多,怕写到后面自己也写迷糊了,同时最近要在CWOW拿装备和组织工会新年活动,所以拖

到现在。本文都是用最简单的程式阐述了指针的一些基本的特性,但是指针的高级特性,比如智能指针之类,还是需要大家自己看书

,这里不做说明。

参考书目:谭浩强《C程序设计》
          Stanley B.Lippman《C++ primer 第四版》
阅读(707) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~