C数组指针小结

学习视频链接

https://www.bilibili.com/video/av52627832

内存四区

  1. 代码区            代码
  2. 全局区            全局常量字符
  3. 栈区                系统自动开辟。系统自动释放。如:int a = 1;
  4. 堆区                动态开辟。手动开辟。手动释放 malloc

 

地址:

把内存以单个字节为单位分开。对每一个字节进行编号。这就是地址

C数组指针小结_第1张图片

  1. 编号连续
  2. 唯一
  3. 取地址符:& 单目运算符 结合性右往左

int a;

&a           //取出a的地址

 

首地址:一段内存空间中第一个存储单元的地址。

C数组指针小结_第2张图片

 

指针变量:

地址是一些编号。一种数据

 

  1. 用来存放地址的变量
  2. 内存大小4个字节

指针变量的定义:

                  数据类型 *变量名

int *p1;

char *p2;

                 

数据类型指明指针指向的数据类型。因为数据类型不同。所占字节数不同。所以需要指明数据类型以便正确获取数据。数据类型是什么,该指针变量就只能保存什么类型的数据的地址。

*表明这是一个指针变量

 

指针变量的赋值

int a = 1;

int *p;

p = &a;

 

         &号

         取地址符。取出指定变量的地址

        

指针变量的引用

         接上一个代码

         访问a的方式

  1. 使用变量名
printf(“%d”,a);
  1. 使用指针
printf(“%d”,*p);

 

                  这里的*号为取值符。可通过地址取出对应的数据,即返回某一个地址中的值。

        

         两种*号:

  1. 定义时使用的。为定义指针变量
  2. 非定义时使用。为取值符。通过地址取出对应的数据

 

野指针:不能明确指向的指针变量

 

int *a;

         指针定义时,没有被初始化。或者指针指向的内存空间被释放了。它就会指向随机区域。任何指针变量在定义的时(除了static修饰的指针变量)是不会被置空的。而是默认为一个随机的地址值。

         由于地址值不可控。所以将会有很大的安全隐患。

解决办法就是定义好指针后手动赋值为NULL

int *a = NULL;

 

空指针:

void *

一开始不确定存放的变量是什么类型的。就可以使用void *。之后要用的时候再转换成其他的数据类型。再动态内存分配中使用。

 

指针变量的运算:(指针偏移)为了访问地址旁边的一些内存

+       -       ++    --

 

指针变量的加减。以指针所指向的类型空间单位进行偏移

char *p1;                  //char类型。占1个字节 所以p1+1偏移量是1字节

int *p2;                      //int类型。占4个字节,所以p2+1偏移量是4字节

double *p3;              //double类型。占8个字节。所以p3+1偏移量是8字节

 

一维数组与指针

  1. 定义一个一维数组,数组名是这个数组的首地址
int a[5];

 

这里a是其实一个指针。指向的是a[0]的地址

 

但是 a 不是 &a[0]。虽然他们地址相同。但是性质不相同

 

a指向的是a[0]。是a[0]这个int类型数据的指针。a 类型是int *

&a指向的是整一个a这个数组。并不是a[0]。只是a[0]恰好和a这个数组首地址一样而已。&a类型是int (*)[5]。是一个数组指针。

 

C数组指针小结_第3张图片

 

 

演示下实例:

C数组指针小结_第4张图片

 

 

由于打印出来是16进制。14其实就是10进制的20。也就是说&a把数组当作一个整体。a有5个int类型的元素。一个int类型占4个字节。所以&a+1新开了20个字节的空间。而a是指向a[0]的是一个int *类型的指针。int类型只占4个字节。所以a+1只新开了4个字节的空间。

 

这里需要搞清楚首地址和指针偏移的概念。首地址是一段空间中的第一个存储单元的地址。这个“一段空间取决于指针指向的数据类型”。以上例为例。a指向的是a[0]。a[0]的首地址就是int 4个字节中的第一个字节。而&a指向的是整一个数组。这一个数组的首地址是数组里5个元素中第一个元素的地址。

 

                  访问数组的元素:

 int *p = a;
  1. 下标法
printf(“%d”,p[1]);
  1. 指针法
printf(“%d”,*(p+1));          //从a[0]开始偏移一位。4个字节。刚好就是a[1]

 

细节:

1、*(p+1) 需要括号,*p++不需要括号

          因为*比+优先级高。而*和++优先级一样。就从右往左执行。

          如果*(p+1)不加括号。就是变成了取出a的值后再加1了 => (*p) + (1)

 

2 、*(p+1)p 不会改变。*p++ p会变

因为++会影响到自身变量。所以p++后就不是a[0]了。指针指向地址变成a[1]。

 

                                   3、a不能++。而p可以++

因为a是一个数组名。虽然也是一个指针。但是如果数组名都++了。那这个数组就没有意义了。为了防止这个情况。数组名是不能++的。想++只能新建一个指针将a的首地址丢过去。新指针就可以用++。

 

 

二维数组与指针

 

int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

 

虽然看起来是三行4列的。但是在内存中还是一个连续的存储空间。可以看作是一个一维数组的组合。

C数组指针小结_第5张图片

 

数组名:a

a是二维数组的首地址。

a指向二维数组的第一个存储单元

所以a指向a[0] 这个一维数组。类型为int (*) [4]      由于a[0]这个一维数组中有4个int。所以a + 1新增字节为16个字节

 

a[0]是一维数组的数组名。a[0]指向a[0][0] 类型为int * 由于a[0]指向一个int数据。所以a + 1新增字节为4 个字节

 

所以:

a指向一维数组

a[0]指向一个int数据

 

C数组指针小结_第6张图片

C数组指针小结_第7张图片

 

可以看到a+1新开了16个字节。而a[0]+1只开了4个字节

 

多维数组也如此

 

二维数组取值用指针法如下:

 

取m行n列的元素

 

a[m][n]  =>  *(a[m] + n)  =>  *(*(a+m) + n)     

 

C数组指针小结_第8张图片

 

你可能感兴趣的:(c)