int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0]
指针p指向了数组arr[0]的地址,第一个元素的地址被取出,其实arr数组名也是数组第一个元素的地址。这里我们做一下测试:可以看出,数组名就是数组首元素的地址。
有的同学会发出疑问了,如果是这样的话,有个地方就说不通了,用sizeof(arr)时得出的结果并不是一个元素的比特位那这是为什么呢?其实数组名就是首元素的地址并没有问题,但是它有两个例外。第一个就是sizeof(arr),此时arr代表的是整个数组,计算的是整个数组的大小,单位是比特。第二个例外是取地址arr:&arr,这个时候arr表示的是整个数组,取出的是整个数组的地址。整个数组的地址和数组首地址不是一个意思。除了这两个情况,其他的arr都指数组首元素的地址。
我们来聊一下&arr。这三种打印出来都是一样的,都是数组首元素的地址,前两个就算了,前面说过了,数组名就是数组首元素地址,但是&arr不是指整个数组吗,那为什么会这个样子。(注意:16进制24就是10进制的40)arr与arr+1和&arr[0]与&arr[0]+1都是相差四个字节,而&arr与&arr+1却差了40个字节,这是因为arr与&arr[0]都是数组首元素的地址,+1就跳过一个元素,&arr是整个数组的地址,+1就是跳过一个数组。
2.使用指针访问数组:
有了前面知识的铺垫我们可以很好的理解指针访问数组了
#include <stdio.h>
int main()
{
int arr[10] = {0};
//输⼊
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));
}
return 0;
}
上面代码能理解就可以进一步,我们既然可以用arr[i]访问数组元素,那么我们也应该可以指针p访问数组元素。
#include <stdio.h>
int main()
{
int arr[10] = {0};
//输⼊
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", p[i]);
}
return 0;
}
这里我们用了p[i]代替了*(p+i)也是可以的,那么同理arr[i]就是*(arr+i),说明编译器在实现访问数组元素时是先得到数组首元素地址加上偏移量求出元素的地址,最后解引用来访问的。
3.一维数组传参:
#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;
}
我们可以看出来test函数没有获取完整的数组元素个数。其实我们前面说了除了两个例外,arr就是数组首元素的地址,所以本质上数组传参传过去的是数组首元素的地址。因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的,所以我们可以在传递参数时,再把数组元素个数传过去。所以一维数组的传参可以用数组形式也可以用指针形式。
4.冒泡排序:
之前的文章其实提过冒泡,这章我们把代码优化优化。
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);
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
比普通的冒泡优化了一个地方,就是如果有一趟没交换的话,说明此时已经有序了,不需要再重复操作,提高程序效率。
5.二级指针:
指针变量是变量,只要是变量内存就会分配空间,那么指针的地址是什么呢?指针的地址就是二级指针。
如图ppa就是二级指针,保存的是指针p的地址。ppa解引用得到的就是p的值,也就是a的地址,再对p解引用就是a的值。
6.指针数组:
指针数组是指针还是数组呢,其实这并不难分别,就像字符指针是指针,整形指针是指针,字符数组是数组,整形数组是数组一样,指针数组当然是数组了。指针数组就是把指针存入数组里。
指针数组的每个元素又是地址,又可以指向一块区域。
本章阐述了数组名,二级指针,指针数组等相关问题,加深自己的印象的同时能给大家带来一点点的帮助当然是更好不过的了嘿嘿。