目录
一、知识点回顾
也可以先做题,碰到不会的案例再返回来看看对应的知识点~
1. 一维数组传参
传参的关键:参数的含义,参数的类型
#include<stdio.h>
void print_a(int arr[],int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//也可以*(arr + i)
}
}
void print_b(int *arr, int sz)
{
for (int i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));//也可以arr[i]
// *(arr + i),arr是数组首元素的地址,arr+i表示数组第i个元素的地址
}
}
int main()
{
int arr[6] = { 1,2,3,4,5,6 };
print_a(arr, 6);
printf("\n");
print_b(arr, 6);
return 0;
}
print_a(arr, 6) 中传的arr,有两种理解:
①arr本是个一维数组。传一维数组,用一维数组接收。形参用int arr[]
②arr又表示数组首元素的地址。传地址,用指针接收,类型是int* (表示指向int类型)*(arr + i) == arr[i] == *(i+arr) == i[arr]
2. 二维数组传参
传参的关键:参数的含义,参数的类型
解引用关键:区别首行的地址&首元素的地址
#include<stdio.h>
void print_a(int arr[2][3])//二维数组传参,必须写列数
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", arr[i][j]);
}
}
}
void print_b(int(*arr)[3], int row, int clo)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < clo; j++)
{
printf("%d ", *(*(arr + i) + j));
//== printf("%d ", *(arr[i] + j));
//== printf("%d ", (*(arr + i))[j]);
//== printf("%d ", arr[i][j]);
}
}
}
int main()
{
int arr[2][3] = { 1,2,3,4,5,6 };
print_a(arr);//二维数组传参,用二维数组接收
printf("\n");
print_b(arr,2,3);//二维数组传参,用指针接收
return 0;
}
传参传的是二维数组首行(可以看成是一个一维数组)地址&arr,其类型是int(*arr)[3]:
!!!&arr的类型怎么看
arr是二维数组首行的地址。地址用指针接收,且指针指向一个数组,所以是一个数组指针解读 *(*(arr + i) + j) : arr+i表示二维数组第i行的地址;*(arr+i)相当于*(&arr),表示第i行的数组名,第i行的数组名又可以看成是一个一维数组首元素的地址;*(*(arr + i) + j)就是第i行第j个元素的值。
*(*(arr + i) + j) == *(arr[i] + j) == (*(arr + i) )[j] == arr[i][j]
3. sizeof操作符以及strlen字符串计算
详细可以看sizeof操作符与strlen库函数的用法与比较
二、案例实操
1. 二维数组中的sizeof计算
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a[0][0]));
printf("%d \n", sizeof(a[0]));
printf("%d\n", sizeof(a[0] + 1));
printf("%d\n", sizeof(*(a[0] + 1)));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(*(a + 1)));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*(&a[0] + 1)));
printf("%d\n", sizeof(*a));
printf("%d \n", sizeof(a[3]));
return 0;
}
详解:
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); //4*4*3=48
//二维数组的数组名a,单独放在sizeof内部,求的是整个二维数组的大小
printf("%d\n", sizeof(a[0][0])); //4
//a[0][0]表示二维数组第0行第0列这个元素的值,求值的类型的大小--int类型,4个字节
printf("%d\n", sizeof(a[0])); //16
//a[0]表示二维数组第一行的数组名,数组名单独放在sizeof内部,求这一整行(看成一个一维数组)数组的大小。
printf("%d\n", sizeof(a[0] + 1)); //4/8
//a[0]+1,a[0]数组名没有单独放在sizeof内部,表示二维数组首行首元素的地址。+1,表示首行第二个元素的地址
printf("%d\n", sizeof(*(a[0] + 1))); //4
//*(a[0] + 1))表示首行第二个元素的地址,再解引用,表示首行第二个元素的值。
printf("%d\n", sizeof(a + 1)); //4/8
//a二维数组数组名,没有单独放,表示二维数组首行的地址。+1表示第二行的地址
printf("%d\n", sizeof(*(a + 1))); //16
//解引用第二行的地址,拿到第二行数组的数组名。相当于sizeof(a[1]),数组名单独放在sizeof内部。
printf("%d\n", sizeof(&a[0] + 1)); //4/8
//a[0]--二维数组首行的数组名,没有单独放,&a[0]表示首行的地址。+1表示第二行的地址
printf("%d\n", sizeof(*(&a[0] + 1)));//16
//解引用第二行的地址,拿到第二行的数组名。相当于sizeof(arr[1]),数组名单独放在sizeof内部,求整个数组的大小
printf("%d\n", sizeof(*a)); //16
//a--二维数组数组名,没有单独放表示数组首行的地址,*a--拿到二维数组首行数组名。数组名单独放...
printf("%d\n", sizeof(a[3])); //16
//假设有第四行的数组,此时第四行数组的大小是4*4=16
//sizeof操作符()内部的表达式不参与真实运算,实际上没有去越界访问,只是直到表达式的类型而已
return 0;
}
注意事项:
① 区别二维数组中的 a,a[0],*a,&a[0]
a -- 二维数组的数组名
单独放在sizeof内部表示求整个二维数组的大小; 没有单独放在sizeof内部表示二维数组首行的地址
a[0] -- 二维数组首行的数组名
单独放在sizeof内部表示求首行(可看作一维数组)整个数组的大小; 没有单独放在siezof内部表示二维数组首行首元素的地址
&a[0] -- 首行的地址即首行整个数组的地址
*a -- *(二维数组首行的地址),拿到二维数组首行的数组名!!!首行地址≠首行首元素地址 !!!二维数组的首行是一个一维数组 按照二维数组里的一维数组来理解的话:a-二维数组数组名,a[0]-一维数组数组名
② 区别二维数组中的 a+1,a[0]+1,&a[0]+1
a+1 二维数组首行的地址+1->二维数组第二行的地址
a[0]+1 二维数组首行首元素的地址+1->二维数组首行第二个元素的地址
&a[0]+1 &数组名得到二维数组首行的地址,+1->二维数组第二行的地址
2. printf输出值是多少?-- 两个一维数组
#include<stdio.h>
int main()
{
int a[12] = { 1,2,3,4,5,6,7,8,9,10,11,12 }, * p[4], i;
for (i = 0; i < 4; i++)
{
p[i] = &a[i * 3];
}
printf("%d\n",p[3][2]);
return 0;
}
分析:p是一个指针数组, p[3][2]==*(p[3]+2)。p+3是指针数组第四个元素地址&a[9] -> *(a[9]+2)==*(a[11])==12
画个图便于理解:
a[9]一维数组a的第10个元素的值,&a[9]拿到第10个元素的地址,&a[9]+2拿到第12个元素的地址&a[11],再解引用*(&a[11]),最后得到a[11]。a[11]是数组a的第12个元素的值。
结果:12
关键:① 理解二维数组中的等价转换 ②*&a[11]==a[11]
~ 后续继续更新...