C/C++有意思的指针(3)

指针是内存的空间戒指

指针类似于玄幻小说主角手上的空间存物戒指,有些属性好的戒指包含完整的宇宙空间。属性差的可能就只有一个仓库大小的空间。所以如果手上有一个牛逼的空间戒指那不知道有多爽。程序员有机会通过计算机的内存空间来获得这样一种能力–拥有储物戒指,从而获得某个空间(内存空间)。

内存空间也是一种空间,只是存储的东西受限制于现在计算机的功能,能存储二进制数。我相信未来肯定可以像小说那样拥有真实的空间,想在这个空间存什么都可以。

那么程序怎么样生成一样空间戒指呢,就是定义一个指针,把这个指针指向内存的一片存储区域。这样就可以使用这片内存空间。

程序中只是定义指针,并没有初始化指针内存空间,或是指向了NULL(空)内存地址区域都是不能使用的。
示例:

int* p; //定义没有初始化,没有指向任何内存空间
int* p1  = nullptr; //指向一个无效内存地址空间。
int a =10; int* p2 = &a //p2指针指向一个能存放4字节的内存空间,因为程序与CPU约定的读取内存方式为int类型数据点4字节。

其它比如 char类型,short类型, long类型等占不同内存空间。

所谓的数据类型,只是程序员与CPU约定好的一种读取内存的方式。也可以不约定,直接申请内存空间想怎么存就怎么存,想怎么取就怎么取。其实最好还是约定一种方式,不然随意存取很空间就破坏内存已经存好的数据。举例说吧,你按一次4字节的方式写数据到内存,但其它人在写片存储区或是一次读2字节或6字节,那么读出来的数据很容易出问题。读写方式不统一程序大了肯定维护不了。

程序可以通过malloc方式申请到很大的空间,当然前提是你的计算得有一个大容量内存。通过malloc申请的内存空间返回是一个(void*)类型的指针,这就是说你可以把申请到的内存空间强制转换成你想要的类型。比如定义了一个结构体

struct stu {
    
    
int age;
int height;
char* name;
};
struct stu* st = (struct stu*)malloc(size); 
//malloc括号里的size是可以从计算拿到的任意大小内存空间。

如果编程语言没有提供malloc函数,那么只能使用其它方式获得内存。比如new关键来生成一个对象,这样也能获得对象的内存空间

class Stu{
    
    
	int age;
	int height;
	char* name
};
Stu* st = new Stu();

指针与数组的关系

有些人可能会想,能不能一次就可以有很多个空间戒指。答案是肯定的,通过定义指针数组就可以一次获得多个指针变量。

int* array[10]; //定义数组,数组有10个元素。每个元素都是指针类型。

这样就一次拿到了10个int类型的指针。即你拥有了10个空间戒指,只是每个空间戒指只能存4字节的内容。当然你也可以定义很多数量,具体多少个根据需要定义。

我们知道数组名也是指针类型,数组名地址指向数组首地址,完全可以通过数组名+偏移来访问数组中的元素。

数组的指针定义

一维数组数组名即为指针变量。int a[10]; //通过数组变量名a加偏移量即可以访问所有元素
二组数组的指针变量比较特别,这个特别的原因是因为二组数组是通过线性的存储空间来实现出来的。

定义一个二维数组 int c[3][2] 其它就是把6个连续的线性存储空间,按2个一组分划分,6个即可以划分成3份,每一份都有一个首地址,那么需3指针变量来存储它们的首地址。所以数组中的c[3]是用来存储后面划分组的首地址。每个首地址都包含2个数组数据类型的空间。

在这里插入图片描述

就可以这么定义二维数组指针变量:
1) 定义一个指针变量 (*p)
2)指针指向的数据类型为int类型 int(*p)
3)每一个指针都包含有2个数据类型存储空间即么就是 int(*p) [2]

推出二维指针类型:知道 int* p; 指针指向的类型为 int, 那么 int(*p)[2] 的类型为 int[2](就是2个int空间)。

数组的数据类型为 int()[2] 即指针每次加一则指针偏移 int[2] 空间。

同理 int c[2][4] 就是这样定义 int(*p)[4] 即指针每次加一则指针偏移 int[4] 空间。

void print_array_info(int(*p)[2]) //二维数组指针传参
 {
    
    
     printf("The member:%d \n", p[1][1]);

     for(int i = 0; i < 3; i++){
    
    
         for(int j = 0; j < 2; j++)
         printf("The member value:%d \n", *(*(p+i)+j)); //指针访问二维数组元素
     }
 }

 int main(int argc, char** argv)
 {
    
    
     int a[3] = {
    
     1, 2, 3 }; //一维数组
     int* b[3] = {
    
     &a[0], &a[1], &a[2] }; //指针数组

     int c[3][2] = {
    
    {
    
    11, 22}, {
    
    33, 44}, {
    
    55, 66}};

     print_array_info(c); //可以同时把数组元素个数传进去

     for(int j = 0; j < 3; j++){
    
    
         printf("The array b value:%d \n", *(*(b+j))); //指针访问
     }

     return 0;
 }

到其它的结构体数组都是相同的理解,只是数据类型不相同,另外结构体指针访问元素的方式不同。