海洋网络网站建设,网站设计基本结构,德阳seo,手机网站开发语言一、数组名的理解
上一篇文章中我们写过一个这样的代码#xff1a;
int arr[10] {1,2,3,4,5,6,7,8,9,10};
int *p arr[0];这里使用arr[0] 的方式拿到了数组第⼀个元素的地址#xff0c;但是其实数组名本来就是地址#xff0c;而且是数组首元素的地址#xff…一、数组名的理解
上一篇文章中我们写过一个这样的代码
int arr[10] {1,2,3,4,5,6,7,8,9,10};
int *p arr[0];这里使用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;
}运行结果如下图 通过运行代码我们可以知道**arr[0] 拿到了数组第一个元素的地址和数组名拿到的地址是一样的。即数组名就是数组首元素的地址** 见下方代码
#include stdio.hint main(){int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf(%d\n, sizeof(arr));return 0;}运行结果如下图 观察上述代码不难看出如果数组名是首元素的地址那么打印出来应该是4或者8。 那么数组名到底是不是首元素的地址呢出现这种情况又怎样理解呢 答案是肯定的数组名就是数组首元素的地址但是有两种情况下例外 1.sizeof(数组名)这里的数组名表示整个数组计算的是整个数组的大小单位为字节。 2.数组名这里的数组名也是表示整个数组取出的是整个数组的地址。 除此之外所有的数组名都是数组首元素的地址。 那么问题又来了那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个字节是因为arr[0]和arr都是首元素的地址1就是跳过一个元素。但是arr和arr1相差40个字节这就是因为 arr是整个数组的地址1操作是跳过整个数组的地址。
二、使用指针访问数组
#include stdio.h
int main()
{
int arr[10] {1,2,3,4,5,6,7,8,9,10};
//打印数组内容
int*p arr;//int*p arr[0];
int sz sizeof(arr)/sizeof(arr[0]);
int i 0;
//给数组输入10个值
//for(i 0;i sz;i)
//{
//scanf(%d,arr[i]);
//}
for(i 0;i sz;i)
{
scanf(%d,p);
}
//输出
for(i 0;i sz;i)
{
printf(%d,*p);
p;
//这里可以合起来写成printf(%d,*(p i));
}
return 0;
}观察上述代码后我们来捋捋可以等价替换的式子如下图所示
三、一维数组传参的本质
我们之前都是在函数外部计算数组的元素个数现在我们把数组传给⼀个函数后在函数内部求数组的元素个数代码如下
#include stdio.h
void test(int arr[])//这里括号中可以替换为int*arr
{
int sz2 sizeof(arr)/sizeof(arr[0]);
printf(sz2 %d\n,sz2);//1
}
int main()
{
int arr[10] {0};
int sz1 sizeof(arr)/sizeof(arr[0]);//10
printf(sz1 %d\n,sz1);
test(arr);//本质上arr是指针
//这里的arr没有单独放在sizeof内部也没有所以arr是数组首元素的地址。
return 0;
}运行结果如下图 观察上述代码和运行结果可得在函数内部是没有正确获得数组的元素个数。数组名是数组首元素的地址那么在数组传参的时候传递的是数组名也就是说本质上数组传参传递的是数组首元素的地址所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。sizeof(arr) 计算的是一个地址的大小单位字节而不是数组的大小单位字节。正因为函数的参数部分是本质是指针所以在函数内部是没办法求的数组元素个数的。 总结1.一维数组传参的时候传过去的是数组首元素的地址。 2.形参的部分可以写成指针的形式也可以写成数组的形式但本质上都是指针写成数组的形式是为了方便理解。
四、冒泡排序 排序算法 1.冒泡排序 2.选择排序 3.插入排序 4.快速排序 5.堆排序 6.希尔排序 冒泡排序的思想 1.两两相邻的元素进行比较如果不满足顺序就交换满足顺序就找下一对。 代码如下
#include stdio.h
void bubble_sort(int arr[],int sz)
{
int i 0;
//趟数
for(i 0;i sz-1;i)
{
//一趟冒泡排序
int j 0;
for(j 0;j sz-1-i;j)
{
if(arr[j] arr[j 1])
{
int tmp arr[j];
arr[j] arr[j 1];
arr[j 1] tmp;
}
}
}
}
void printf_arr(int arr[],int sz)
{
int i 0;
for(i 0;i sz;i)
{
printf(%d,arr[i]);
}
printf(\n);
}
int main()
{
int arr[] {9,8,7,6,5,4,3,2,1,0};//降序
//实现排序排成升序
int sz sizeof(arr) / sizeof(arr[0]);
printf_arr(arr,sz);
bubble_sort(arr,sz);
printf_arr(arr,sz);
return 0;
}运行结果如图 这个代码还可以优化一下代码如下
#include stdio.h
int count 0;
void bubble_sort(int*arr,int sz)
{
int i 0;//趟数
for(i 0;i sz;i)
{
//一趟冒泡排序
int flag 1;
int j 0;
for(j 0;j sz-1-i;j)
{
count;
if(*(arr j) *(arr j 1))
{
int tmp *(arr j);
*(arr j) *(arr j 1);
*(arr j 1) tmp;
flag 0;//不是有序
}
}
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);int i 0;for(i0; isz; i){printf(%d , arr[i]);}return 0;
}运行结果如下图
五、二级指针
一级指针变量也是变量是变量就有地址那一级指针变量的地址存放在哪⾥存放在⼆级指针中。 二级指针的介绍如下图
#include stdio.h
int main()
{
int a 10;
int*p a;
int**pp p;
**pp 20;//两次解引用才能拿到初始变量a,依次解引用只能拿到一级指针p的地址。
printf(%d\n,a);
return 0;
}运行结果如下图
六、指针数组
指针数组是指针还是数组 指针数组是存放指针的数组即它本质上是数组。 指针数组的每一个元素都是用来存放地址指针的指针数组的每一个元素是地址又可以指向一块区域。
七、指针数组模拟二维数组
代码如下
#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;
}运行结果如下图 parr[i]是访问parr数组的元素parr[i]找到的数组元素指向了整型⼀维数组parr[i][j]就是整型一维数组中的元素。 注上述虽然模拟出二维数组但是每一行的地址是不连续的不算真正上的二为数组。