【C语言】小妹不懂指针和数组的关系?那就安排指针数组关系详解

目录

前言

一、什么是数组

二、什么是指针

三、指针变量的大小

四、数组和指针的关系

五、指针变量的自增自减运算

六、两个参数确定一个数组

七、字符型指针和字符型数组

总结

写在最后


前言

前段时间整理的C语言的一些基础知识,给到我家小妹复习用的。

有整体入门基础文章——【C语言】拯救新手,半小时从零到一认识C语言基础

还有C语言数据类型的详解——【C语言】数据类型一文详解

问了下她,还需要什么,她说要字符指针跟数组的,那这期就安排C语言指针类型的详解

关于数组和指针的一些定义的介绍和使用,我在【C语言】数据类型一文详解一文中有提到。为了方便这次数组和指针的应用详解,这里咱们简单复习一下。

一、什么是数组

数组可以看作是一系列相同类型变量的一个集合,而这个集合的名称就叫数组名。

比如上面的例子,咱们可以声明一个数组来代替

int i_baiyu[5] = {1,2,3,4,5};//baiyu 就是数组名,这里是声明了一个长度为5的int型数组

所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。

请注意上面提到的连续内存的位置,也就是说,数组元素的地址是连续的。

二、什么是指针

指针是一种特殊的变量类型。

每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。而指针则是指向了这个变量所在的内存地址。

这样子可能不太好理解,咱们举个例子

比如:baiyu是住在贝克街221号B,那么baiyu(变量)所住的地方(内存),而门牌号(指针)贝克街221号B(内存地址)

指针就是相当于咱们的门牌号,指向的是内存所在的地址。指针变量是用来存放内存地址的变量。

指针变量的声明格式如下:

数据类型 *指针变量名

这里的数据类型跟咱们前面提到的数据类型是一致的,也就是int、char、double、float这些

回到小妹的提问,字符型指针,那其实就是用char关键字定义的指针

char *c_baiyu_p = NULL;//定义一个字符型指针,并赋值为空NULL

三、指针变量的大小

我在【C语言】数据类型一文详解一文中有提到,C 语言里有六种基本数据类型,分别用short、int、long、char、float、double 这六个关键字表示。这六种类型分别占用的内存空间不一样。通过sizeof函数,咱们知道了,char 型变量占 1 字节、short型变量占2个字节、int 型变量占 4 字节,long型变量个字节、占float 型变量占 4 字节、double 型变量占 8 字节。

同样的,想要知道不同类型的 指针变量占用多少内存空间,咱们也一样可以用sizeof函数来获取。

#include<stdio.h>
int main() {
    int* i_baiyu_p = NULL;    /* 一个整型的指针 */
    char* c_baiyu_p = NULL;    /* 一个字符型的指针 */
    double* d_baiyu_p = NULL;    /* 一个 double 型的指针 */
    float* f_baiyu_p = NULL;    /* 一个浮点型的指针 */

    printf("指针 i_baiyu_p 的大小为:%d\n", sizeof(i_baiyu_p));
    printf("指针 c_baiyu_p 的大小为:%d\n", sizeof(c_baiyu_p));
    printf("指针 d_baiyu_p 的大小为:%d\n", sizeof(d_baiyu_p));
    printf("指针 f_baiyu_p 的大小为:%d\n", sizeof(f_baiyu_p));
    return 0;
}

从输出结果可以看出,所有的类型的指针变量大小都是占4个字节,并不像普通变量一样,根据数据基类型不一样而对应的内存大小不一样。因为指针变量存放的都是数据的内存地址。

四、数组和指针的关系

上面咱们说到,定义了数组之后,数组元素的内存空间是连续的。口说无凭,上代码

#include <stdio.h>
int main() {
    int i_baiyu[5] = {1,2,3,4,5};
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        printf("i_baiyu[%d]的地址是:0x%p\n",i, &i_baiyu[i]);
    }
    printf("i_baiyu的地址是:0x%p\n",i_baiyu);//注意这里不用取地址符&
    return 0;
}

根据打印出来的信息,我们可以看到,数组元素的内存地址是连续的。而且数组名的地址跟数组的第一个元素的地址是相同的,也就是说,数组名是指向数组的第一个元素。

PS:小伙伴们在实验过程中可能会发现打印出来的地址跟我不一样,这是没关系的,因为每次程序都会重新向内存申请一块区域来存放数据。关于内存这一块,后面我会写一篇文章专门来讲~

数组数据在内存的存储关系图如下:

既然如此,我们是不是就可以直接通过指针来访问数组元素了呢?答案是肯定的。

我们可以通过对指针进行运算,让指针进行移动。

C 语言规定:如果指针变量 p 已经指向一维数组的第一个元素,那么 p+1 就表示指向该数组的第二个元素。

咱们直接上代码可能好理解一些:

#include <stdio.h>
int main() {
    int i_baiyu[5] = { 1,2,3,4,5 };
    int i = 0;

    int* i_p = i_baiyu;// 数组名赋值给指针 i_p
    int* i_q = &i_baiyu[0];// 数组第一个元素的地址赋值给 i_q

    printf("----\n");
    for (i = 0; i < 5; i++)
    {
        printf("i_baiyu[%d]的地址是:0x%p,对应元素的值是:%d\n", i, &i_baiyu[i],i_baiyu[i]);
        printf("指针i_p的地址是:   0x%p,指向的值是:%d\n", (i_p + i), *(i_p + i));
        printf("指针i_q的地址是:   0x%p,指向的值是:%d\n", (i_q + i), *(i_q + i));
        printf("----\n");
    }

    return 0;
}

(i_p + i) 得到的是对应数组元素的指针地址

*(i_p + i )得到的是对应数组元素的指针地址指向的值

从上面这个例子可以看出,数组名就是指向了数组的首个元素的地址。

五、指针变量的自增自减运算

这两天刚解决了粉丝关于普通变量的自增自减运算符的疑问,有需要的同学可以戳链接

【C语言】一文弄通++i,i++,i--,--i,解决粉丝疑问

没错,咱们可爱的指针变量也有这种运算操作惊不惊喜,意不意外。

前面说过,i_p+i表示指向数据的第i个元素。当i等于1时,i_p = i_p+1可以写成 i_p++。是不是很熟悉,这里的加加减减运算符的用法跟普通变量的自增自减是一样的。

给段代码让大家熟悉一下。

#include <stdio.h>
int main() {
    int i_baiyu[5] = { 1,2,3,4,5 };
    int i = 0;
    
    int* i_p = i_baiyu;// 数组名赋值给指针 i_p
    
    printf("----\n");
    for (i = 0; i < 5; i++)
    {
        printf("指针i_p的地址是:0x%p,指向的值是:%d\n", (i_p), *(i_p++));
        printf("----\n");
    }
    
    return 0;
}

六、两个参数确定一个数组

根据上面咱们讲到的,数组名指向数组的首地址(第一个元素的地址),通过数组长度对指针进行加(减)运算,从而可以得出一个完整的数组的数据内容。因此当我们把数组作为参数,在函数间传递数组时,可以在形参定义一个指针变量用于接收数组名,以及定义一个整型数据用于接收数组长度。

上代码示例

#include<stdio.h>
void outputArr(int* i_arr, int i_arr_length) {
    int* i_p = i_arr;
    printf("数组的值为:");
    for (; i_arr < i_p + i_arr_length; i_arr++) {
        printf("%d  ", *i_arr);
    }
    printf("\n\n");
}
int main() {
    int i_baiyu[] = { 1,2,3,4,5 };
    int i_baiyu_2[] = { 111,222,333,444,555,666,777 };
    outputArr(i_baiyu, 5);
    outputArr(i_baiyu_2, 7);
    return 0;
}

七、字符型指针和字符型数组

回到小妹提给我的问题,其实通过前面六点的解释应该可以明白指针与数组之间的关系。而字符型指针和字符型数组只是指针和数组里的一个子类

相同的点,这里就不再赘述。这里讲一下字符型数组一些要注意的地方。

  1. 在字符型数组的时候,可以直接通过字符数组元素进行修改赋值。在字符型指针赋值字符串常量之后,不可以通过指针指向某个元素修改值。
  2. 字符数组名是常量,故数组名不能++;字符指针是个变量,故指针可以++;

给一个示例代码

#include<stdio.h>
int main() {
    char c_baiyu[] = "https://blog.csdn.net/zhh763984017";
    int i;
    for ( i = 0; i < 35; i++)
    {
        printf("%c", *(c_baiyu + i));
    }
    printf("\n");

    char* c_baiyu_p = "zhh_baiyu";//字符型指针也可以直接赋值为字符串常量

    c_baiyu[0] = '6';//因为c_baiyu是数组,所以元素的值可以修改
    //*(c_baiyu_p +1) = '6';//取消注释报错,这里是字符型指针指向的值,不可以修改
    printf("%s\n", c_baiyu);
    printf("%s\n", c_baiyu_p);

}

总结

本文简单阐述了数组和指针之间的关系。每一个变量都有一个内存位置,每一个内存位置都定义了可使用【&】运算符访问的地址,指针表示了在内存中的一个地址。访问指针变量中可用地址的值,通过取值运算符【*】将指针变量里地址对应的变量值取出这个操作也被叫做解引用。

数组则是定义了一系列相同类型的变量,这些变量在内存地址上是连续的,因此咱们可以通过指针运算偏移的方式来读取对应的数组的值。

写在最后

如果觉得本文对你有帮助的话,麻烦一键三连支持一下攻城狮白玉,你的一个小小的三连是我创作的无限动力。

如果有想看的内容,也可以在博文底部评论,我会整理出来给到大家~

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

攻城狮白玉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值