从C出发 28 --- 指针与数组

文章详细阐述了C语言中数组和指针的关系,包括数组名作为指针的特性,数组地址与元素地址的区别,以及指针类型的定义和使用。同时,解释了如何通过指针访问数组元素,以及字符串常量在内存中的表示和处理。文中强调了类型匹配在指针赋值和操作中的重要性,并通过例子展示了指针自增操作的逻辑。
摘要由CSDN通过智能技术生成

 

 

 int a[ ] = {1, 2, 3, 4, 0};      //定义了一个数组,这个数组有5个元素,每个元素是一个 int 类型变量

 

 

 这里的地址是相同的,是相同的意味着数组的地址和 0  号元素的地址是一样的

结论:

数值上相同但是意义上不同,一个是数组整体的地址,一个是元素个体的地址,虽然数值相同但是意义不同

除此之外类型也不同

int (*) [5]

(*) ------ 这里描述的肯定是一个指针类型 

具体什么样的指针类型呐 ?指针类型有很多很多,这里的指针类型具体是哪一种呐?

int  [5]  这 2 个, 我们就清楚了,这个指针类型用于指向数组     指向什么样子的数组?

int  [5],  由5个元素,每个元素是整型变量的数组

 这个指针的名字为  pName 

类型是  : int (*)[5];

&a 数组地址

用数组地址来初始化 pName

pa    这个指针 就指向了上面定义的数组a[ ] 

int* p = a;   定义一个指针  p ,并且指向这个数组的第0 号元素     

所以     &a    和  a   不同

在做赋值的时候,在做初始化的时候,类型必须一致,特别对于指针来说,如果类型不一致就不能相互的赋值

while 里面打印 p 指向的整型数

定义一个指向数组的指针

int (*pa) [5];     这个数组长什么样子,由5个元素,每个元素是一个整型变量 ,这样一个指向数组的指针就定义好了

警告 : 赋值符号左右两边的指针类型不兼容 

为什么打印  1,因为死循环了,当前p的值指向了数组当中的第 0 号元素,而第 0 号元素的值就为 1,所以这里反复不停的循环,反复不停的打印 1 出来,

while( *p )    这里就是判断当前 p 所指向的元素值是不是 0 ,如果不是0,那么就继续的循环,如果是0呐,就跳出循环

p++ ; 移动指针的语句,将指针 p 指向下一个元素

为什么没有打印最后一个元素的值呐?

因为最后一个元素的值为0,当p++;指针移动到0的时候,while( *p )取到的值为0,既然取到的值为0,while 循环就跳出了


定义一个指针指向数组中的元素,比如说 p ,这个时候我们执行 p++;的操作,指针p 将会指向 4 ,

现在扩展成   p = p + i ,i 是任意一个整数值, 数组a 第 0 号元素的地址就是数组名 a,数组名可以看作一个指针,这个指针指向第0号元素,然后我们知道  a + 1 = > &a[ 1 ];(a + 1指的是第1号元素的地址)

使用 指针访问操作符 (*)  将得到的是第 i 号元素

然后定义了一个指针 p ,这个指针指向了第 0 号元素,换句话说在数值上 a 和 p 等价了,代表相同的地址值

意味着 我们可以定义一个指针,然后把这个指针指向数组中的第 0 号元素,之后就可以通过 p[ i ]这样的方式来访问数组元素了

#include <stdio.h>

int main()
{
    int a[] = {1,2,3,4,5};
    int* p = a;
    int i = 0;

    for(i= 0;i<5;i++)
    {
        printf("%d, %d\n", a[i], *(a + i));   // (a + i)就是数组中第 i 号元素的地址,对这个地址使用指针访问操作符的结果就是访问了地址中的元素,换句话说这里打印的结果就是 1 1,2 2,3 3,4 4,5 5
    }

    return 0;
}

又是一样的结果,意味着 :  a[i] 和 p[i] 是等价的

#include <stdio.h>

int main()
{
    int a[] = {1, 2, 3, 4, 5};
    int* p = a;
    int i = 0;

    //对于一个数组来说有这样的等价关系
    //  a[i] <==> *(a + i)   <==>  *(p+i) <==> p[i]
    

    for(i = 0; i < 5 ;i++)
    {
        printf("%d, %d\n", a[i], *(a + i));
    }

    for(i = 0; i < 5 ;i++)
    {
        printf("%d, %d\n", a[i], p[i]);
    }

    for(i = 0; i < 5 ;i++)
    {
        printf("%d, %d\n", p[i], *(p + i));
    }

    return 0;

}


 p + i 得到的是什么呐?

也是一个地址值,第 i 号元素的地址值

a 的类型是int*   

i 是 int 类型

然后做相加     a + i 最终的结果是内存地址 这个内存地址类型就是 int* 类型

& a   和   &p  打印出来的数值是一样的吗 ?

不一样,为什么不一样, a 是数组,所以&a 这样写,取到的是数组的起始地址    。 p 是变量,是一个指针变量,所以这样写 &p ,得到的是指针变量的地址,

注意 : 指针变量也是变量,既然是变量显然可以取到地址

所以 &a  和  &p  肯定不相等

数组的地址怎么可能等于另一个变量的地址呐?不可能

 a 和 p 所对应的地址是相同的

对a 取地址,和对p 取地址 ,得到的结果不相同,为什么不相同?因为a 和 p是不同的程序元素,因此,他们有各自的,不同的地址

实验结果证明  : 数组名只是可以看作指针,而它并不是指针,数组名并不是指针


字符串的本质是 字符数组,一种特殊的字符数组,特殊在字符数组当中存在 0 元素,‘  \0 '

那么字符串常量又是什么呐?直接在程序中 用双引号所定义的字符序列  “ Delplin”

这是一个字符数组,这个字符数组因为有 0元素,所以成为了字符串

 在 C 语言中要成功的被 %S 打印出来,那么是一个合法的 char* 类型

C 语言中的字符串,其类型为 char*

 为什么打印出来的地址一模一样?

字符串常量本质是一个字符数组,那么它必然在内存中占空间,也就是说这个字符串常量是存在于内存中的,那么存在内存中具体哪个区呐? 全局数据区,并且起始于  *ps  地址处

当程序中需要使用 这个字符串常量时,简单的借助于 ps 指针就好了

因此在这段代码中,编译器其实这样做了,直接将这里的字符串常量 替换成了  PS 指针,事实上这里的 PS 指针并不存在,真正替换的目标就是 这里的地址,也就是这个字符串常量在全局数据区的起始地址,所以才会打印相同地址出来

 打印相同的地址,这个地址就是 D.T Software 在全局数据区的起始地址


*     : 指针访问操作符

++  : 自增运算操作符

先把指针所指向的内存中的值给拿出来,拿出来用于初始化变量 v ,完了之后p 指针进行指针移动

简单来说  2 件事  ,第一件事取值  ,第二件事移动

 为什么是  1 和 2 呀? 

*p++;  这里一次性干了2 件事

 (*p)第一件事将 p 所指向的内存当中的值取出来,取到的值是 1 ,于是用 1 初始化 v 

 (p++) 第二件事 p++ ,指针移动,指向2


 在 main 函数中首先定义了一个指针,这个指针被初始化为 空,也就是用 0 来进行初始化

D.T.Software  在程序中使用它的时候,其实就是使用它的起始地址,用 PS来指代它的起始地址,并且PS 它的类型是 char* ,换句话说 PS 的起始地址的类型就是 char*,于是这里等价于从指针中取值了,通过PS 取到的值就是字符 ' D '

s = "D.T.Software"   使用指针 s 来指向全局数据区当中的常量,于是就可以访问这个字符串常量当中的每一个字符了

怎么访问,一个while 循环来访问的    %c (每次打印的是一个字符), *s 先访问了 s 所指向的数据,这个时候 s 所指向的数据就是字符,然后进行移动,移动后指向下一个字符,所以这样不停的取值,不停的取值,不停的指向下一个字符,肯定 s 最终指向一个  '\0' 值,这个'\ 0' 值就是 D.T.Software这个字符串常量的结束符

打印结果

这个while ( *s )循环刚开始通过 s 取到的值为 0 吗?

不为 0 ,刚开始通过 s 取到的值是  D 

打印 s 所指向的字符,然后移动s 指针,使其指向下一个字符

 

 数组名可以看作一个指针,本质是不是指针,显然不是

&a 代表数组作为一个整体的地址

a 代表数组 0 号元素的地址     ,一个是整体的地址,一个是个体的地址,所以意义上不同

当指针指向数组元素时,才能使用组合拳 *p++;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长生君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值