C语言 day10 | 我的日常分享

C语言 day10

数组

二维数组的分析(了解)

案例 1:

1
2
3
4
5
6
7
8
9
int arr[3][4];
/*
二维数组名:代表的是二维数组的首行地址,+1跳过一行
对行地址取 `*` 将变成当前行的第0列的列地址`arr[0]=*(arr+0)=*arr` `arr[1]=*(arr+1)`
*/

//例如取出第二行第三列的元素
printf("%d",*(*(arr+1)+2));
// *(*(arr+1)+2)=*(arr[1]+2)=arr[1][2]这就是计算机的方式

二维数组名:代表的是二维数组的首行地址,+1 跳过一行
对行地址取 * 将变成当前行的第 0 列的列地址arr[0]=*(arr+0)=*arr arr[1]=*(arr+1)

案例 2:说出下面分别代表的是啥?

1
2
3
4
5
6
int arr[3][4];

*arr+2;//第0行第2列的列地址
arr[1];//*(arr+1)第1行第0列的列地址
&arr[0]+2;//&*(arr+0)+2=arr+2;第2列的行地址
**arr;//第0行第0列的元素*(*(arr+0)+0)=arr[0][0]

数组指针与二维数组的关系

案例 1:定义一个指针变量,保存二维数组的行地址

1
2
3
4
5
6
7
8
9
#include<stdio.h>
int main(int argc,char *argv[]){
int arr[3][4];

//数组指针
int (*p)[4];//注意:不加()p会先与[]结合这样就不是数组指针了,就变成了指针数组了
p=arr;//p跟arr完全等价,p+1=arr+1跳过一行
return 0;
}

案例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
int main(int argc,char *argv[]){
int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*p)[4]=arr;
int i=0,j=0;
printf("%d\n",sizeof(p));//4 抓住本质,本质就是一个指针变量

for(i=0;i<3;i++){
for(j=0;j<4;j++){
// printf("%d ",*(*(p+i)+j));
printf("%d ",p[i][j]);//p完全等价于arr
}
printf("\n");
}
return 0;
}

运行结果:
图片


任何维度数组,在物理存储上都是一维的

我们可以通过一维来访问多维数组,因为内存条是一维的,地址是连续的

案例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<stdio.h>
int main(int argc,char *argv[]){
int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
//int *p=*arr;
int *p=&arr[0][0];
int i=0;

for(i=0;i<3*4;i++){
printf("%d ",*(p+i));
}
printf("\n");
for(i=0;i<3*4;i++){
printf("%d ",p[i]);
}

return 0;
}

运行结果:
图片


多级指针

1 级指针 保存 0 级指针变量的地址(普通变量)
2 级指针 保存 1 级指针变量的地址
3 级指针 保存 2 级指针变量的地址
····
n 级指针 保存 n-1 级指针变量的地址

图片


指针作为函数的参数

  1. 如果想要在函数内部,修改函数外部变量的值,就需要将函数外部变量的地址,传递给函数(以指针变量作为函数的参数) 【重要重要重要!!!】

  2. 一维数组,作为函数的形参会被优化成指针变量

引入:

案例 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
void my_swap(int a,int b){
printf("a=%d\n",a);
printf("b=%d\n",b);
int temp=0;
temp=a;
a=b;
b=temp;
printf("a=%d\n",a);
printf("b=%d\n",b);
return;
}
int main(int argc,char *argv[]){
int data1=4,data2=5;
my_swap(data1,data2);

printf("data1=%d\n",data1);
printf("data2=%d\n",data2);
return 0;
}

运行结果:
图片

分析:
data1,data2之间的值并未被交换,然而a,b的值交换成功了;因为当函数调用的时候,系统给形参分配内存空间,通过传参将实参传给了局部变量形参,在函数里面操作的只是形参a,b;并不是data1,data2

解决方法:要解决上面的问题,就要给函数传入data1,data2变量的地址

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
void my_swap(int *a,int *b){
printf("a=%d\n",*a);
printf("b=%d\n",*b);
int temp=0;
temp=*a;
*a=*b;
*b=temp;
printf("a=%d\n",*a);
printf("b=%d\n",*b);
return;
}
int main(int argc,char *argv[]){
int data1=4,data2=5;
my_swap(&data1,&data2);

printf("data1=%d\n",data1);
printf("data2=%d\n",data2);
return 0;
}

运行结果:
图片

分析:交换成功!

案例 2:在函数内部更改 p 的指向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
void my_set(int **tem_p){
//注意形参是二级指针,用一级指针也没问题,但是类型不匹配会有警告,最好不要这样干
static int num=100;
*tem_p=&num;
}

int main(int argc,char *argv[]){

int *p=NULL;

my_set(&p);
printf("%d\n",*p);
return 0;
}

一维数组名作为函数的参数

1. 如果函数内部想要操作(读、写)外部数组的元素,请将外部数组的数组名传递给函数

案例 1:为什么同样的数组总大小不一样?

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
void my_input_array(int arr[5],int n){
printf("B:%d\n",sizeof(arr));
}
int main(int argc,char *argv[]){

int arr[5]={0};
printf("A:%d\n",sizeof(arr));
return 0;
}

运行结果:
图片

分析:因为系统会自动把void my_input_array(int arr[5],int n){优化为void my_input_array(int *arr,int n){,所以B:4输出的是指针的字节数 4.

一维数组,作为函数的形参会被优化成指针变量

案例 2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
void my_input_array(int arr[5],int n){
int i=0;
printf("请输入5个int类型数据:\n");
for(i=0;i<n;i++){
// scanf("%d",&*(arr+i));
// scanf("%d",&arr[i]);
scanf("%d",arr+i);
}
}
void my_printf_array(int arr[5],int n){
int i=0;
for(i=0;i<n;i++){
printf("%d ",arr[i]);
printf("%d\n",*(arr+i));
}
}
int main(int argc,char *argv[]){

int arr[5]={0};
int n=sizeof(arr)/sizeof(arr[0]);

//获取键盘输入
my_input_array(arr,n);
//遍历数组元素
my_printf_array(arr,n);

return 0;
}

运行结果:
图片


二维数组名作为函数的参数

  1. 如果想要在函数内部,修改函数外部变量的值,就需要将函数外部变量的地址,传递给函数(以指针变量作为函数的参数) 【重要重要重要!!!】
  2. 二维数组名,作为函数的形参,会被优化成数组指针
    1
    2
    3
    4
    5
    6
    7

    int arr1[5]--->int *p1
    int arr2[3][4]--->int (*p2)[4]
    int arr3[3][4][5]--->int (*p3)[4][5]
    int arr4[3][4][5][6]--->int (*p4)[4][5][6]
    ·········..........·········

    案例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #include<stdio.h>
    void my_printf_two_array(int arr[3][4],int row,int col){
    printf("B:%d\n",sizeof(arr));
    }
    int main(int argc,char *argv[]){

    int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    int row=sizeof(arr)/sizeof(arr[0]);//行数
    int col=sizeof(arr[0])/sizeof(arr[0][0]);//列数

    printf("A:%d\n",sizeof(arr));
    my_printf_two_array(arr,row,col);

    return 0;
    }
    运行结果:
    图片

分析:当二维数组作为函数的参数时,会被优化成数组指针 即,
void my_printf_two_array(int arr[3][4],int row,int col){
变成
void my_printf_two_array(int (*arr)[4],int row,int col){

案例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdio.h>
void my_printf_two_array(int (*arr)[4],int row,int col){
int i=0,j=0;
for(i=0;i<row;i++){
for(j=0;j<col;j++){
// printf("%d ",*(*(arr+i)+j));
printf("%d ",arr[i][j]);
}
printf("\n");
}
}
int main(int argc,char *argv[]){

int arr[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int row=sizeof(arr)/sizeof(arr[0]);//行数
int col=sizeof(arr[0])/sizeof(arr[0][0]);//列数

my_printf_two_array(arr,row,col);

return 0;
}

运行结果:
图片


指针作为函数的返回值

案例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
int* get_addr(void){
// int num=1000;
static int num=1000;

return &num;
}
int main(int argc,char *argv[]){
int *p=NULL;
p=get_addr();
printf("%d\n",*p);
return 0;
}

运行结果:
图片


函数名,代表的是函数的入口地址

案例1:

1
2
3
4
5
6
7
8
#include<stdio.h>
int my_add(int a,int b){
return a+b;
}
int main(int argc,char *argv[]){
printf("%p\n",my_add);
return 0;
}

运行结果:
图片

案例2:定义一个指针变量,保存函数的入口地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
int my_add(int a,int b){
return a+b;
}
int main(int argc,char *argv[]){
//按照定义指针变量的三部曲走,再复杂的也可以
// int (*p)(int a,int b);
int (*p)(int,int)=NULL;
p=my_add;

printf("my_add=%p\n",my_add);
printf("p=%p\n",p);

//函数的调用:函数入口地址 + ()
printf("%d\n",my_add(10,20));
printf("%d\n",p(30,40));

//对函数指针变量取*无意义
printf("%d\n",(*p)(30,40));
(*******printf)("hello\n");
return 0;
}

运行结果:
图片


指针函数的应用-函数指针作为函数的形参

案例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
int my_add(int a,int b){
return a+b;
}
int my_sub(int a,int b){
return a-b;
}
int my_mul(int a,int b){
return a*b;
}

//定义一个函数实现上面三个函数的功能
int my_calc(int a,int b,int (*fun_pointer)(int,int)){
return fun_pointer(a,b);
}
int main(int argc,char *argv[]){
printf("%d\n",my_calc(10,20,my_add));
printf("%d\n",my_calc(10,20,my_sub));
printf("%d\n",my_calc(10,20,my_mul));

return 0;
}

运行结果:
图片