C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)

简介: C语言----关于二维数组传参的本质相关的知识点(数组指针、指针数组)
//指针数组
// 1.是数组
// 2.是存放指针的数组
// char* arr[6]---数组元素类型+数组名+[元素个数]---存放字符指针的数组
// int * arr[5]---存放整型指针的数组
// 
// 
// 数组指针
// 
// 
// 字符指针---char*pc--指向字符的,变量中存放的是字符的地址
// 整型指针---int*pi---指向整型,变量中存放的是整形数字的地址
// 
// 那么数组指针就是指向数组的指针
// *p--说明这个是指针
// [元素个数]--说明前面的p是指向后面的数组的
// (*p)添加括号,不然p会与后面的[元素个数]进行组合,p就成数组名了,所以在定义数组指针的时候要将*p括起来
// (*p)[10]
// int(*p)[10]--说明p是数组指针,数组内有10个元素,每个元素有的类型是int
// 
// 那么p的类型就是int(*)[10]
//int main()
//{
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int(*p)[10] = &arr;//取出的是数组的地址
//    //把一个数组指针的地址取出来放到数组指针变量内
//
//    //使用p数组指针来访问arr数组的内容
//
//    for (int i = 0; i < 10; i++)
//    {
//        //printf("%d", *p);//因为p里面存放的是数组的地址,那么解引用就是拿到了整个数组的地址
//        //所以如果我们想访问这个数组的每个元素,我们需要做出改变
//
//        printf("%d", (*p)[i]);//(*p)访问了这个数组,后面加上[i],随着i的变化访问数组内的元素
//        //就相当于在打印arr[i],因为p里面存的是数组的地址,*p=arr
//    }
//    return 0;
//}
//上面的方法略显复杂,我们进行变更
//int main()
//{
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int*p= arr;//存放数组首元素的地址,直接创建指针来存放数组首元素的地址
//
//    for (int i = 0; i < 10; i++)
//    {
//        
//        printf("%d ", p[i]);//p[i]---*(p+i)--随着i的变化访问数组内的元素
//    }
//    return 0;
//}
 
// 上面的使用数组指针访问数组有点麻烦,远不及其他的方法
//那么数组指针到底在什么地方能用上呢?
// 
// 二维数组传参
//常规方式:
//void print(int arr[3][5], int r, int c)//传过来的数组就创建一个数组来接收数组
//{
//    //两层循环遍历数组,第一层解决行,第二层解决列
//    for (int i = 0; i < r; i++)
//    {
//        for (int j = 0; j < c; j++)
//        {
//            printf("%d ", arr[i][j]);
//        }
//        printf("\n");//打印完一行就换行打印另一行
//    }
//}
//int main()
//{
//    int arr[3][5] = { {1,2,3,4,5} ,{2,3,4,5,6} ,{3,4,5,6,7} };//创建二维数组
//    print(arr,3,5);//借助函数将数组打印出来,将数组名传过去,3行5列也传过去
//
//    return 0;
//}
//
//一维数组的数组名是数组首元素的地址
// 二维数组的数组名也是数组首元素的地址
// 对于上面的这个二维数组,可以理解为存放3个一维数组的数组
// 二维数组的每一行可以理解为每一行就是一维数组
// 
// 那么二维数组的数组名是首元素的地址,所以二维数组的地址就是第一行的地址
// 
//
void print(int (*arr)[5], int r, int c)//传过来的数组就创建一个数组来接收数组
{//传过来的是第一行的一维数组的地址,我么用数组指针接收
    //这个数组指针指向的是第一行的一维数组的5个元素
    // 每个元素的返回类型就是int  
    // 所以我们用int (*arr)[5]这个数组指针来接收
    // 
    //两层循环遍历数组,第一层解决行,第二层解决列
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < c; j++)
        {
            printf("%d ", (*(arr + i))[j]);
        }
        printf("\n");//打印完一行就换行打印另一行
    }
}
int main()
{
    int arr[3][5] = { {1,2,3,4,5} ,{2,3,4,5,6} ,{3,4,5,6,7} };
    print(arr, 3, 5);//arr是数组首元素的地址,就是第一行的一维数组地址,不是这个一维数组首元素的地址
    //这里传过去的是第一行一位数组的的地址,就是第一行一维数组的地址
    //数组的地址传过去了,我们要用数组指针来接受
    return 0;
}
//形参是传的是数组首元素的地址,那么我们就创建数组指针来接收
//对于这个数组来说
//
// 
// 第一行1 2 3 4 5
// 第二行2 3 4 5 6
// 第三行3 4 5 6 7
// 
// arr指向的是第一行的,当我们想指向第二行,我们就需要arr+1,
// 因为是指向数组的指针,所以+1就是直接跳过一个数组
// 那么想找到第三行的时候就直接arr+2
//
// 那么在上面的循环里,打印这个二维数组我们就能这么写
// *(arr+i)
// arr+i就是这个二维数组内三个一维数组的地址,那么我们对其进行解引
// 用就能访问这三个数组的内容了
// 
// *(arr+i)就是想当与拿到这一行
// 
// 那我们已经拿到了这一行,我们该如何访问每一个元素呢?
// 我们 还是得通过下标访问数组内的每个元素
//
// 
// 因为这个函数有两个循环,那么第二个循环就是我们访问这三个一维数组内的每个元素了
// 那我们就在后面添加[j]访问每个元素,
// 前面的(*(arr+i))就是把访问这个二维数组内的三个一维数组
// 那么在后面加上[j]就能访问到每个元素了
// (*(arr+i))[j]------第一种写法
// 
// 
// *((*(arr+i)+j))--第二种写法
// 解释:
 
// 因为实参传过来的是arr是二维数组的数组名,那么我们是用一个数组指针进行接收的
// ,所以arr是一个数组指针
// 这里的arr是指针啊,数组指针
// arr数组内存放的是这个二维数组里面的第一个一维数组的地址
//*(arr+i)得到的是第i行的数组的首地址,也是指向第i行第一个元素的指针
//为什么解引用得到的是地址呢?
// 
// 因为arr+i里面存放就是第i行的地址 
// 对其进行解引用得到的就是第i行的地址
// *(arr+i)得到的是第i行的地址,
// 同样,arr+i里面存的是一维数组首元素的地址,对其进行解引用得到的是地址,是数组首元素的地址
// *(arr+i)得到的是一维数组首元素的地址
//那么*(arr+i)+j得到的就是这一下标为j的地址
// 对整体再次进行解引用就得到了i行j列的元素了
// 
//记住,这里的arr是一个数组指针

末尾涉及到(*(arr+i))[j]和 *((*(arr+i)+j))的区别

尽管二者相同但有些知识点十分复杂

关键点,这里的arr是一个数组指针,存放的是这个二维数组内的一个一维数组的地址(二维数组的首元素就是这个一维数组)

在这个函数里面arr仅仅只是一个指针

相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
37 3
|
25天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
29天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
29天前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
29天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
53 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
48 2
|
2月前
链表指针的传参,传值和传地址
本文讨论了链表操作中指针传参的问题,特别是指针的传值与传地址的区别,并提供了修正代码,以确保链表插入操作能正确地修改指针指向的地址。
19 1
链表指针的传参,传值和传地址
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
39 1
|
2月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。