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仅仅只是一个指针

相关文章
|
24天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
45 0
|
23天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
23天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
23天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
23天前
|
编译器 C语言
【c语言】指针就该这么学(2)
本文详细介绍了指针与数组的关系,包括指针访问数组、一维数组传参、二级指针、指针数组和数组指针等内容。通过具体代码示例,解释了数组名作为首元素地址的用法,以及如何使用指针数组模拟二维数组和传递二维数组。文章还强调了数组指针与指针数组的区别,并通过调试窗口展示了不同类型指针的差异。最后,总结了指针在数组操作中的重要性和应用场景。
17 0
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
33 3
|
6天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
22 6
|
26天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
34 10
|
19天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
|
25天前
|
机器学习/深度学习 C语言
【c语言】一篇文章搞懂函数递归
本文详细介绍了函数递归的概念、思想及其限制条件,并通过求阶乘、打印整数每一位和求斐波那契数等实例,展示了递归的应用。递归的核心在于将大问题分解为小问题,但需注意递归可能导致效率低下和栈溢出的问题。文章最后总结了递归的优缺点,提醒读者在实际编程中合理使用递归。
53 7