临沂网站开发技术员,广州设计公司前十名,网站织梦如何让会员注册,网络营销发展方案策划书欢迎来到白刘的领域 Miracle_86.-CSDN博客
系列专栏 C语言知识
先赞后看#xff0c;已成习惯 创作不易#xff0c;多多支持#xff01; 目录
一、数组名的理解
二、使用指针访问数组
三、一维数组传参本质
四、冒泡排序
五、二级指针
六、指针数组
七、指针数组…欢迎来到白刘的领域 Miracle_86.-CSDN博客
系列专栏 C语言知识
先赞后看已成习惯 创作不易多多支持 目录
一、数组名的理解
二、使用指针访问数组
三、一维数组传参本质
四、冒泡排序
五、二级指针
六、指针数组
七、指针数组模拟二维数组 一、数组名的理解
在上一篇博客中我们在使用指针访问数组时有这样的代码
int arr[10] {1,2,3,4,5,6,7,8,9,10};
int *p arr[0]; 详见灵魂指针教给一-CSDN博客 这里我们使用了arr[0]的方式拿到了数组的首元素地址但是数组名本身就是地址而且是数组首元素的地址我们可以做个测试来看下面这段代码
#include stdio.h
int main()
{int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(arr[0] %p\n, arr[0]);printf(arr %p\n, arr);return 0;
}
第一个printf打印arr[0]的地址第二个打印数组名代表的地址。
来看运行结果 我们可以发现这两个地址一模一样这也证明了数组名就是数组首元素第一个元素的地址。
我们再来看一段代码
#include stdio.h
int main()
{int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(%d\n, sizeof(arr));return 0;
}
我们在前面讲到指针地址的大小是4或者8个字节而arr是数组名是数组首元素的地址那这个应该是打印4或者8但是这段代码的结果为40。这是为什么呢
确实arr作为数组名是数组首元素的地址但是这里有两个例外 sizeof(数组名),在sizeof中单独存放数组名这里的数组代表整个数组计算的是整个数组的大小单位为字节 数组名这里的数组名也表示整个数组取出的是整个数组的地址整个数组的地址和数组首元素地址是有区别的。 除了上述两个例外其它任何位置出现数组名都是代表的数组首元素地址。
那我们再来看一段代码
#include stdio.h
int main()
{int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(arr[0] %p\n, arr[0]);printf(arr %p\n, arr);printf(arr %p\n, arr);return 0;
} 来看结果 我们发现三个地址完全相同那arr和arr到底有啥区别呢别着急我们继续来做个测试
#include stdio.h
int main()
{int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(arr[0] %p\n, arr[0]);printf(arr[0]1 %p\n, arr[0]1);printf(arr %p\n, arr);printf(arr1 %p\n, arr1);printf(arr %p\n, arr);printf(arr1 %p\n, arr1);return 0;
}
来看运行结果 这里挑了一组比较明显的结果我们可以发现arr[0]和arr[0]1之间差了4个字节arr和arr1之间也差了4个字节这是因为它们都是数组首元素的地址1的意思是跳过一个元素。
但是arr和arr1差了有40个字节因为arr是数组的地址而arr有10个元素每个元素的大小是4个字节所以arr的大小为40个字节1是跳过整个数组。
讲到这想必大家都明白数组名的意义了吧。
二、使用指针访问数组
前面做好铺垫我们就可以很容易地使用指针访问数组了。
#include stdio.h
int main()
{int arr[10] {0};//输⼊int i 0;int sz sizeof(arr)/sizeof(arr[0]);//输⼊int* p arr;for(i0; isz; i){scanf(%d, pi);//scanf(%d, arri);//也可以这样写}//输出for(i0; isz; i){printf(%d , *(pi));}return 0;
}
创建了一个int类型的指针p指向数组arr的首元素的地址然后pi代表指向第i个元素再对其解引用进行输出。
上述代码搞清之后我们不妨大胆想象一下既然arr和p是等价的那我们既然可以写arr[i]那可不可以写p[i]呢答案是可以来看代码
#include stdio.h
int main()
{int arr[10] {0};//输⼊int i 0;int sz sizeof(arr)/sizeof(arr[0]);//输⼊int* p arr;for(i0; isz; i){scanf(%d, pi);//scanf(%d, arri);//也可以这样写}//输出for(i0; isz; i){printf(%d , p[i]);}return 0;
}
运行结果毫无疑问是没有问题的 同理arr[i]也等价于*(arri)数字元素的访问在编译器处理的时候也是转换为首元素地址偏移量求出元素地址然后解引用访问。
三、一维数组传参本质
数组我们已经很熟悉了我们在之前也有所提到过数组可以传递给函数如果有忘了的老铁可以进入下方传送门 C语言中的工具箱——函数-CSDN博客 那今天我们来认真介绍一下一维数组传参的本质 。
首先引出一个问题我们之前计算数组元素个数都是在函数外部的那我们在函数内部计算个数可以吗
#include stdio.h
void test(int arr[])
{int sz2 sizeof(arr)/sizeof(arr[0]);printf(sz2 %d\n, sz2);
}
int main()
{int arr[10] {1,2,3,4,5,6,7,8,9,10};int sz1 sizeof(arr)/sizeof(arr[0]);printf(sz1 %d\n, sz1);test(arr);return 0;
}
我们来看运行结果 可以看出在函数内部没有得到正确的数组元素个数。
所以我们来学习数组传参的本质刚刚我们介绍过数组名是数组首元素的地址那么在数组传参的时候传递的是数组名也就是说数组传参的本质上是传递数组首元素的地址。
所以函数形参理论上应该使用指针变量来接收首元素地址。你们函数内部我们在写sizeof(arr)计算的是一个地址的大小而不是数组的大小单位字节。正是因为函数的参数部分的本质是指针所以在函数内部是没法求数组元素个数的。 总结一维数组传参形参可以写成数组也可以写成指针。 四、冒泡排序
排序想必大家都知道是什么意思但是这个冒泡是什么意思呢咕嘟咕嘟冒泡泡嘛事实上确实可以是这样的。
来看下图 我们在生活中可以看见这种现象烧开水冒的泡泡或者是我们在水下吐泡泡从下往上移动越接近水面泡泡会越来越大。上面这个动图也是如此我们看5是最大的数字所以我们要让它慢慢浮到后面或者前面。 冒泡排序的核心思想两两相邻元素进行比较。其实也可以总结为两层循环一层判断。 直接上代码
//⽅法1
#includestdio.h
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{int i 0;for(i0; isz-1; i){int j 0;for(j0; jsz-i-1; j){if(arr[j] arr[j1]){int tmp arr[j];arr[j] arr[j1];arr[j1] tmp;}}}
}
int main()
{int arr[] {3,1,7,5,8,9,0,2,4,6};int sz sizeof(arr)/sizeof(arr[0]);bubble_sort(arr, sz);for(int i0; isz; i){printf(%d , arr[i]);}return 0;
} 我们来看第二种优化后的方法
//⽅法2 - 优化
#includestdio.h
void bubble_sort(int arr[], int sz)//参数接收数组元素个数
{int i 0;for (i 0; i sz - 1; i){int flag 1;//假设这⼀趟已经有序了int j 0;for (j 0; j sz - i - 1; j){if (arr[j] arr[j 1]){flag 0;//发⽣交换就说明⽆序int tmp arr[j];arr[j] arr[j 1];arr[j 1] tmp;}}if (flag 1)//这⼀趟没交换就说明已经有序后续⽆序排序了break;}
}
int main()
{int arr[] { 3,1,7,5,8,9,0,2,4,6 };int sz sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz);for (int i 0; i sz; i){printf(%d , arr[i]);}return 0;
}
由于第一种可能存在无效遍历所以我们第二种方法设置了一个flag变量来判断是否有序。
五、二级指针
二级指针听起来很牛逼的样子但实际上还是挺好理解的。我们说指针变量它其实也是个变量是变量就有地址那它的地址存放在哪里呢
这就引出了二级指针。 上图中的ppa就是指向指针pa的二级指针存放的是pa的地址它的类型是int * * **ppa 30等价于*pa 30等价于a 30。 六、指针数组
指针数组这个名字很抽象你说它到底是指针还是数组答案是数组其实它是这么理解的装着指针的数组。后面我们还会学到一个非常非常容易和它混淆的东西叫数组指针。我们中国汉语一般是习惯把定于放在中心词的前面像红苹果、小朋友...这俩玩意也不例外数组指针和指针数组谁在后面就是谁。
我们还可以类比一下其它类型的数组像整型数组和字符数组。 指针数组是用来存放指针地址的。
如下图 指针数组的每个元素是地址又可以指向一块区域。
指针数组有什么用呢我们接着往下学习。
七、指针数组模拟二维数组
既然指针数组可以存放指针那我每个指针都再指向一个地址是不是就模拟出二维数组了因为二维数组的本质是元素为一维数组的数组我们在之前也有提过 C语言中的百宝箱——数组2-CSDN博客 画图的话就是如下 我们来代码实现一下
#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数组中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;
} 运行结果如下 注上述代码仅是模拟出二维数组的效果并非完全是二维数组因为每一行是非连续的。