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

Posted 攻城狮白玉

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);

}

总结

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

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

写在最后

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

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

以上是关于C语言小妹不懂指针和数组的关系?那就安排指针数组关系详解的主要内容,如果未能解决你的问题,请参考以下文章

C语言指针Ⅶ 指针运算指针+-整数指针-指针指针的关系运算标准关系标准规定指针和数组二级指针指针数组。

关于c语言二维数组列指针初始化

C语言指针,下标,

C语言学习笔记--指针和数组的关系

C语言学习 -- 指针

C语言用指针求数组和