椋鸟C语言笔记#20:指针数组、指针模拟二维数组、数组指针、二维数组传参的本质、字符指针与字符串

萌新的学习笔记,写错了恳请斧正。


目录

指针数组

指针模拟二维数组

数组指针

数组指针的初始化

二维数组传参的本质

字符指针与字符串


指针数组

整型数组存放整型,那么指针数组自然是存放指针的数组。

要定义一个指针数组,我们应该像这样写:

int* parr[3] = { pa, pb, pc };

因为方括号的优先级要高于解引用操作符,所以parr先与方括号结合,规定其为数组。其中存储的数据类型为int*(整型指针)。

指针模拟二维数组

#include <stdio.h>

int main()
{
    int arr1[] = {1,2,3,4,5};
    int arr2[] = {2,3,4,5,6};
    int arr3[] = {3,4,5,6,7};
    int* parr[3] = {arr1, arr2, arr3};
    int i = 0;
    int j = 0;
    for (i = 0; i < 3; i++)
    {
        for(j=0; j<5; j++)
        {
            printf("%d ", parr[i][j]);
        }
        printf("\n");
    }
    return 0;
}

上述代码就是用指针数组来模拟实现一个三行五列的二维数组

parr[i]是访问parr数组的元素,找到的数组元素指向了整型一维数组,parr[i][j]就是整型一维数
组中的元素。
上述的代码模拟出二维数组的效果,但实际上并非不是二维数组,每一行不是连续的。

数组指针

相反的,那数组指针就是指向数组的指针

但是如果我们写成下面这样,定义的就是指针数组而不是数组指针

int* parr[3] = { pa, pb, pc };

所以我们就要避免parr与方括号先结合,导致被认为是数组

那么就只需加一个括号就行:

int (*parr)[3] = &arr;

这样parr先与解引用操作符结合,被认为是指针,指向int [3]类型的数据(数组)

数组指针的初始化

可以看到,上面我是通过取地址数组名来初始化数组指针的。

因为数组指针是指向整个数组的,一般只能用这种方式来初始化与赋值(数组名的特例,上一篇笔记讲了)(类型应当是这种格式:int[3] *)

二维数组传参的本质

我们之前把二维数组作为参数传递给函数是这么写的:

#include <stdio.h>

void func(int arr[8][9], int m, int n)
{
    //...
}

int main()
{
    int arr[8][9] = { 0 };
    func(arr, 8, 9);
    return 0;
}

实参是二维数组名,形参直接写成二维数组

我们知道,二维数组其实是元素为一维数组的数组

根据数组名是数组首元素的地址,二维数组的数组名表示的就是第一个一维数组的地址

上述代码中,第一行的一维数组的类型就是 int [9],所以第一行的地址的类型就是数组指针类型 int(*)[9]。所以说二维数组传参本质上也是传递了地址,传递的是第一个一维数组的地址,那么形参也是可以写成指针形式的。如下:

#include <stdio.h>

void func(int (*arr)[9], int m, int n)
{
    //...
}

int main()
{
    int arr[8][9] = { 0 };
    func(arr, 8, 9);
    return 0;
}

字符指针与字符串

字符指针,就是指向字符的指针

一般我们这么用:

#include <stdio.h>

int main()
{
    char ch = 'a';
    char* pch = &ch;
    printf("%c", *pch);
    return 0;
}

但是,我们 看看下面这一段代码:

#include <stdio.h>

int main()
{
    const char* pch = "abc";    //这里const可以省略
    printf("%s", pch);
    return 0;
}

这一段代码其实也是对的,能正常打印字符串abc,那我们如何理解呢?

首先我们要知道一点,%s作为格式控制字符,接受的其实是字符串第一个字符的地址。随后从这个地址开始,一个一个打印字符,直到遇到\0为止

那第一句怎么理解呢?难道是把字符串存储在字符指针pch中吗?

不是的,这里就涉及到字符串双引号的作用了。

字符串的双引号有3个作用:

  • 常量区申请一片空间用于存放字符串
  • 在字符串结尾加上\0
  • 返回字符串第一个字符的地址

所以第一句其实是创建了字符串常量并将首元素地址传递给pch

那么,我们其实也就可以这么写:

#include <stdio.h>

int main()
{
    printf("%s", "abc");
    return 0;
}

这样,同样可以将字符串abc打印出来。

!!!注意!!!

用等号对字符数组整体赋值只能与初始化同时进行,不能分开!

初始化的时候使用等号只是规定了其一开始指向的位置。在初始化完成后数组名就是一个指向首元素地址的指针常量了,不能进行等号赋值操作(不能改变指向)。

这时如果想整体赋值可以使用strcpy函数(后面会讲)

为了更好的理解字符串双引号的作用,我们来看看这一段代码:

#include <stdio.h>

int main()
{
    char str1[] = "abcdef";
    char str2[] = "abcdef";
    const char *str3 = "abcdef";    //const可省略
    const char *str4 = "abcdef";    //const可省略

    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");

    return 0;
}

上述代码的输出结果是什么呢?

答案是:

str1 and str2 are not same.

str3 and str4 are same.

为什么呢?

因为str1与str2是两个字符数组变量的首元素的地址,而创建的两个数组的首元素地址肯定不一样,所以输出的就是str1 and str2 are not same.

而str3和str4是创建的字符指针,其指向的是由双引号在常量区创建的字符串常量abcdef。常量不像变量一样会重复创建,所以两个指针最终指向的其实就是同一个地址,输出str3 and str4 are same.


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

椋鸟Starling

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

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

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

打赏作者

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

抵扣说明:

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

余额充值