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必须是初始化好的。否则不可以使用指针pp->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

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/41225

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月8日 下午6:06
下一篇 2023年2月8日 下午6:06

相关推荐