©作者:末央&
©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦
一、数组名
什么是数组名?例如以下
1.概念
int arr[10];
//arr就是数组名;
那么数组名在内存中的地址有什么特殊的地方吗,可以看看。
总结:数组名是数组首元素的地址,即arr[0]的地址
2.sizeof和&里面的数组名
这里相对于我们上面总结的可以理解"数组名是数组首元素的地址"是两个例外
sizeof
int arr[10];
printf("%d\n", sizeof(arr));
&
int arr[10];
printf("arr[0]%p\n", &arr[0]);
printf("arr %p\n", &arr);
这里值得注意的是arr和arr[0]的地址是一样的,那么&arr和&arr[0]还有区别吗?我们不妨在上面基础上再修改一下代码。
int arr[10];
printf("arr[0]%p\n", &arr[0]+1);
printf("arr %p\n", &arr+1);
结合我们上期的知识,知道指针加减一个整数取决于他的指针类型,&arr[0]的指针类型是int,&arr的指针类型是一个数组指针(后期会讲),那么那么前者+1就是跳过一个int(4个字节),后者+1就是跳过一个数组(40个字节)
这里还要注意的是我们为什么可以进行直接的指针+1-1运算,因为我们数组在内存中是连续存放的,如果不是连续存放的就有可能访问到我们没有权限访问的空间。
总结:sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
二、使用指针访问数组
我们通常访问数组都是以数组下标的方式来访问数组的,例如:
int arr[10] = { 0 };
int i;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
但是我们也可以这样写:
int arr[10] = { 0 };
int i = 0;
int* p = arr;
for (i = 0; i < 10; i++)
{
printf("%d\n", p[i]);
}
为什么指针也可以替代数组名的位置了,其实不管是数组访问还是指针访问都可以化成这样的形式:*(数组名/指针变量名+变量/常量)
那也可以这样写:
int arr[10];
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));
}
i[p]和i[arr]也可以,编译器
会把数组名[变量]转换为*
(数组名+变量)形式这里的[变量]
相当于a+b中的+号如果是-变量则是减号,支持加
法交换律
三、一维数组传参本质
看以下代码
1.
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;
为什么这里的sz2是1而不是和sz1一样是10呢,这就涉及到一维数组传参的问题了
我们刚刚在讲数组名的时候不是讲了除了sizeof和&里面的数组名以外,其他全是首元素地址。所有这里传参arr本质上就是传的首元素地址
又因为sizeof(arr) 计算的是⼀个地址的⼤⼩(单位字节)⽽不是数组的⼤⼩(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。
所以首元素地址只有4个字节(int类型),4/4=1
四、指针数组
1.概念
指针数组到底是数组还是指针,指针是形容词数组是名词。所以指针数组本质上还是数组.其次整形数组是存放整形的数组,字符数组是存放字符的数组,那么指针数组实际上就是存放指针的数组
实例(模拟二维数组)
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");
要注意的是,上述代码只是模拟二维数组,实际上并不是真正的二维数组,因为他的行并不是连续存储的。而是通过指针找到每一行的首元素地址来进行访问。
再回忆一下我们之前说的p[i]=(p+i)这是一维数组用指针访问,那么二维数组是不是也可以触类旁通的写成:(*(arr+i)+j)
五、手脑并用
来来来,咱们直接上代码
nt main()
{
int aa[2][5] = {10,9,8,7,6,5,4,3,2,1};
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
小提示:这里明显涉及到我们上面讲的&数组面和前几篇文章讲的指针加减整数运算的概念问题。
好了,我们直接上图来看看吧
这里字有点丑哈,请谅解
那么结果就是:1 6