C++中的数组,指针解析

哎,由于上课的时候没有听课,导致指针这里真的是似懂非懂,虽然对写代码影响不大,但是总是精确度下了一个档次,所以今天趁机把这写个玩意儿弄明白点,省的以后每次都得查。咱们不求文章长,只求内容清楚~

 如果有谁看出了里面有什么问题,请帮忙指出来,免得误导别人~饺子在此先说声谢谢了~


其实关于数组比较好掌握,就是分配某种类型的一个组,这个组的长度必须给出或者初始化,我一开始觉得很不方便,因为有很多情况下我们不知道数组的长度,比如这个数组要由用户定义之类的情况,但是没办法,电脑要为这个数组分配一个内存空间,你不告诉电脑,电脑编译的时候就迷茫了,得出错,所以就互相迁就吧,给他个长度,或者给个初始值,这都是必要的。

 

数组的声明:简单来说,数组是从低维,0开始存放的,举个例子  int a[2][2] 在内存里的存放顺序就是:a[0][0] - a[0][1] - a[1][0] - a[1][1]. 额,因为就俩数字所以看起来像二进制数数,反正就这个道理。声明的时候,要么就给出中括号里面的数字,要么就给个初始化,比如 int a[2][2];   或者int a[][2]={1,1,1,1};当然这个等效于int a[][2]={{1,1},{1,1}};  注意,低维的数字不能省,这个‘[2]’里的2不可以省。

 

接下来是指针

首先要知道的是内存的访问方式,一般来说我们都是通过变量名来访问内存的,比如int a=1; 我们通过a来访问这个存放1的内存,但是还有一种方式是通过地址来访问。打个比方,学校就是我们的内存,每个学生都有自己的名字,以及对应的学号,那么名字就是这里的变量名,而学号就是地址,在批量处理,要传输大量数据的时候,通过学号当然比通过名字访问要方便,所以两个方式各有千秋,必须都掌握好。

指针: 指针其实是一种数据类型,具有指针类型的变量成为指针变量,指针变量用来存放内存单元地址。声明方法如下:

//数据类型 * 标识符
char * c;

这里的*就告诉电脑这是个指针变量,前面的数据类型只表示指针所指地址的数据是那种类型,也就是说,c是指针,不是char(说了句废话。。)。

可以这么理解,'*' 相当于我们定义一个变量int a=3;时的'int', 至于为什么要声明内存的数据类型(也就是为什么'*'前要有'char'),原因很简单,不同的数据类型占有的内存单元长度不同,比如是个short类型的指针,那么内存占俩个字节,但是如果是long的话,就占4个字节,所以要有数据类型,告诉指针取几个字节。

 

感谢8楼的总结,我在这里引用一下:

指针,是一个内存读取器类。
可以按照给定的数据类型定义和地址位置返回期望的数据值。

数组,是对指针的再次封装。
包含一个连续内存块以及一个指针常量。

 

关于'*'和'&'

'*'的意思之前也讲过了,就是个指针运算符。‘&’的名字叫取地址运算符。区别可以这么说:

int * p; //定义了一个int型指针。
int a;
p=&a; // p等于a的地址,也就是说&这个符号表示‘取地址’

‘&’ 这个符号还可以这么用:int &y; 表示声明一个int型的引用 y。

 

给指针赋值可以像上面↑那样,先声明,后赋值,也可以是声明的时候直接赋值,效果雷同给普通变量赋值。注意,对于数组,可以直接用数组名,因为数组名就是它的地址:

int a[5];
int *p=a;//不需要'&',因为a本身即是一个地址了。

使用指针是,如果直接使用,出来的是地址,加个'*',出来的是内容,具体这么表示吧:

int a=5;
int *p=&a;
cout<<p<<endl; // 这一行将输出a的地址
cout<<*p<<endl; // 这一行将输出数字'5'

声明的时候要注意:

  • 可以声明指向常量的指针,但是不要妄图通过指针来改变这个常量值╮(╯_╰)╭,不过指针不像常量那么有节操,指针可以改变所指对象的值。如下:
    const char * p="HELLO"; // 这个const是形容char的
    char s[]="HI";
    p=s; //这么写是可以的,就是相当于给p一个新的地址,

    *p='HI'; // 这就要出错了,都说了人家char是个常量了,不要改人家嘛。

    //但是:
    char *p="HELLO";
    *p='H'; //这个编译可以通过,但是运行出错了。因为违反了指针的规则。
    利用这个特点,可以保证指针所指向的常量不被意外更改。
  • ‘*’放在const前面的话,表示这个指针是个常量,指针本身不能被更改。下面这种情况 line2是不被允许的说~
    char * const p="abc";
    p="def"; // nonono,要出错咯~
     
  • 虽然我很讨厌规矩,但是编程嘛,必须按着规矩来,定义了什么类型的指针,就赋什么类型的值,咱不能给int型指针赋个'x'是吧。不过总有那么几个叛逆的,所以就有了种叫做void类型的指针,通过强制转换,可以访问任何类型的数据。void指针的使用:
    void *vp;  // 一个void类型的指针
    int a=5;
    int *px;
    vp = &a;
    px = (int *)vp;//把vp的void * 强制转换成 int *,好满足px的类型。


指针的运算:

         指针可以进行加、减运算,规则其实很容易理解。比如我定义了一个short型指针p,占4个字节,那么p+1,就是地址往后数4个字节,一般是给数组用的。比如:

int a[]={2,3,4,5};
int *p=a;
cout<<*(p+1)<<endl; //输出就是3

 

指针型函数:

这个东西是大大的好啊,可以让返回值从一个扩展的大批的数据,具体用法就是返回类型后面加个"*",用起来很爽。同样来点内容免得光说不练。

int * getAll(int *a){
.....
// 处理了半天,然后返回
return a;
}

(这里谢谢@陈梓瀚(vczh)的指正)

这样返回的就是四个数字而不是一个数字了,可以通过返回的指针,进行运算,得到这批数据,并且可以保护这批数据。

 

指向函数的指针

其实函数和数组一样,在内存中从函数名开始存起,也就是说知道了函数名,接下来的内存里放的就是函数体了,所以,既然指针可以指向数组,当然也可以指向函数了。形式就是: 数据类型 (* 函数指针名)(形参表)   如果一个函数的   返回值类型=指针数据类型  形参表=指针形参表,那个这个函数指针就可以指向这个函数了。

void function(int a,int b);
void function2(int x,int y);
void (* fpointer)(int,int); //必须和要指向的函数形参类型,个数,顺序完全相同,才能指向这个函数

//使用时:
function(5,5);
// 上下 两者效果等同
fpointer=function;
fpointer(6,6);

fpointer=function2; // 多好啊还可以指向别的函数,只要条件符合。

对象指针:(话说这部分其实很废柴啊囧rz)
 就是指向一个类的指针 语法: 类名 * 指针名;   调用成员时: 指针名->成员名; 注意在给指针赋值前,要对这个对象进行初始化~

Clock c(1,2,4);
Clock *p;
p=&c; //这里c必须是初始化好的。否则不可以使用指针p
p->getTime();


指向类的非静态成员的指针:在类的外部定义一个指针指向类得公有成员时,定义如下:

如果是公有数据成员:

Clock  clock(1,1,2);
Clock *pClock = &clock;
//定义
int Clock::*pHour;

//赋值:
pHour=&Clock::Hour;

//调用:(三个效果相同)
clock.*pHour;
pClock->Hour;
clcok.Hour;

如果是公有函数成员:

Clock  clock(1,1,2);
Clock *pClock = &clock;
//定义: 返回类型 (类名::*指针名)(参数表)
int (Clock::*pGetHour)();

//赋值:
pGetHour= &Clock::GetHour;

//调用:(三个效果相同)
clock.*pGetHour;
pClock->GetHour;
clcok.GetHour;


到这里我已经头晕了,不知道耐心看到这里的同学们头晕了没?晕了的话喝口水,刷刷微博先,劳逸结合嘛~

 

动态内存分配:(哇,听起来好高端)7行代码概括:

int *point;
point = new int(2); //分配动态存储空间并把数值2放入内存
// .....
delete point;
/*------------------------------------------*/
Clock *pclock = new Clock[2]; //此时不可以初始化
pclock[0].Set(1,2,3);//就假设有这么个函数呗
pclock[1].Set(4,5,6);
delete[] pclock; //就是为了说,这里delete后面要有‘[]’


浅拷贝和深拷贝:(最后一点儿啦  加油~)

其实这个用代码写起来复杂,但是说起来很简单。

如果一个类里面有个成员p是个指针,定义了实体对象clock, clock2,然后clock中的p指向一个存着int型数据的内存空间。当我们仅仅用clock2.p=clock.p来给clock2中的p赋值的话,其实两个实体对象的指针p就指向了同一个内存空间,这样的话,对这个内存空间的数字进行操作的时候,就会同时影响到clock和clock2.这就是浅拷贝。

深拷贝,就是让它不印象呗。所以clock2的p如果这么拷贝:p=new int(*clock.p); 那么俩玩意儿就互不影响了,如此这般,就是深拷贝。

 

呼,终于结束了,玩儿微博去也~

 

转载于:https://www.cnblogs.com/jiaozihardworking/archive/2012/02/09/2343404.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值