自定义函数,实现杨辉三角,要求使用数组指针做参数
1.9 二维数组和指针
i)二维数组地址
&arr[0][0]: 表示第一个元素的地址,偏移一个数据类型字节大小,列偏移
arr[0]: 等价于一维数组数组名,表示第一行第一个元素的地址,偏移一个数据类型字节大小,列偏移
&arr[0]:等价堆一维数组数组名取地址,表示一行的首编号,偏移一行字节大小,行偏移
arr: 二级地址,表示行偏移,偏移一行字节大小
&arr: 表示整个二维数组的地址,偏移整个二维数组
ii)二维数组和指针
int main(int argc, const char *argv[])
{
int arr[2][3]={11,22,33,44,55,66};
//int *p=arr; 原因:arr是二级地址,p是一级指针,不等价
int (*p)[3]=arr;//p==arr
printf("&p[0][0]=%p\t&p[0][0]+1=%p\n",&p[0][0],&p[0][0]+1);
printf("p[0]=%p\tp[0]+1=%p\n",p[0],p[0]+1);
printf("&p[0]=%p\t&p[0]+1=%p\n",&p[0],&p[0]+1);
printf("p=%p\tp+1=%p\n",p,p+1);
printf("&p=%p\t&p+1=%p\n",&p,&p+1);
}
//arr: 第一行的行地址
//2行3列
//arr+1 第二行行地址
//
//*(arr+1) 地二行第一列的列地址
//*(arr+1)+2 第二行地三列的列地址
//*( *(arr+1)+2 ) 2行3列的元素
//i+1行i+1列的元素: *(*(arr+i)+j)
//&arr[0][0]===arr[0]
//&arr[0]====arr
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
// printf("%d\t",arr[i][j]);
// printf("%d\t",*(*(arr+i)+j));//*(arr+i)-->arr[i]
// printf("%d\t",*(*(&arr[0]+i)+j));
// printf("%d\t",*(arr[i]+j));
// printf("%d\t",p[i][j]);
// printf("%d\t",*(*(p+i)+j));//*(arr+i)-->arr[i]
// printf("%d\t",*(*(&p[0]+i)+j));
// printf("%d\t",*(p[i]+j));
}
printf("\n");
}
//值:arr[i][j]-->*(*(arr+i)+j)-->*(*(&arr[0]+i)+j)-->*(arr[i]+j)
//:p[i][j]-->*(*(p+i)+j)-->*(*(&p[0]+i)+j)-->*(p[i]+j)
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%p\t",&arr[i][j]);
printf("%p\t",*(arr+i)+j);
printf("%p\t",*(&arr[0]+i)+j);
printf("%p\t",arr[i]+j);
printf("%p\t",&p[i][j]);
printf("%p\t",*(p+i)+j);
printf("%p\t",*(&p[0]+i)+j);
printf("%p\t",p[i]+j);
}
printf("\n");
}
//地址:&arr[i][j]-->*(arr+i)+j-->*(&arr[0]+i)+j-->arr[i]+j
//:&p[i][j]-->*(p+i)+j-->*(&p[0]+i)+j-->p[i]+j
return 0;
}
值:arr[i][j]-->*(*(arr+i)+j)-->*(*(&arr[0]+i)+j)-->*(arr[i]+j) -->p[i][j]-->*(*(p+i)+j)-->*(*(&p[0]+i)+j)-->*(p[i]+j)
地址:&arr[i][j]-->*(arr+i)+j-->*(&arr[0]+i)+j-->arr[i]+j -->&p[i][j]-->*(p+i)+j-->*(&p[0]+i)+j-->p[i]+j
1.10 数组指针
本质上就是一个指针,主要用来指向二维数组地址,或者做参数接受二维数组地址。
格式:存储类型 数据类型 (*指针变量名)[常量表达式] ()>[]>*
int arr[2][3];
int (*p)[3]=arr; p=arr
解析:
1.数组指针,指向以3个元素为一行的首地址编号,指向的是一维数组的整体数组的地址
2.() []: 不可以省略
3.常量表达式:需要和二维数组列保持一致
1.11指针数组
本质上是一个数组,每个元素存储的是指针
格式: 存储类型 数据类型 *指针数组名[常量表达式]
int main(int argc, const char *argv[])
{
/*
int a=1,b=2,c=3,d=4;
int *p1=&a,*p2=&b,*p3=&c,*p4=&d;
int *p[4]={&a,&b,&c,&d};
//p[0]=&a
//p[1]=&b
printf("a=%p b=%p c=%p d=%p\n",&a,&b,&c,&d);
for(int i=0;i<4;i++)
{
printf("%d\t",*p[i]);
}
printf("%ld\n",sizeof(p));*/
int a[3]={1,2,3},b[]={4,5,6},c[]={7,8,9};
int *p[3]={a,b,c};
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\t",*(*(p+i)+j));
}
printf("\n");
}
return 0;
}
1.12 字符指针数组
本质上是一个数组,指向多个字符串的地址。
格式: char *指针数组名[常量表达式]
char *p[3]
1> 字符指针数组存储多个字符数组的地址
char str1[]="ASDF",str2[]="abcde",str3[]="12",str4[]="!@#";
char *p[]={str1,str2,str3,str4};
//
printf("%s\t",str1);
*(*p+1)='s';//可以发生更改
int len=sizeof(p)/sizeof(p[0]);
for(int i=0;i<len;i++)
{
printf("%s\n",*(p+i));
}
2> 字符指针数组存储多个字符串常量的地址
char *q[]={"ASDF","abcde","12","!@#"};
// *(*q+1)='s';段错误
len=sizeof(q)/sizeof(q[0]);
for(int i=0;i<len;i++)
{
printf("%s\n",*(q+i));
}
练习主函数:在终端输入,使用字符指针数组
int main(int argc, const char *argv[])
{
//argc: 命令行输入字符串的个数
//argv: 存储命令行输入的每一个字符串
printf("argc=%d\n",argc);
for(int i=0;i<argc;i++)
{
printf("%s\n",*(argv+i));
}
return 0;
}
运行结果:
ubuntu@ubuntu:pointer$ gcc main.c
ubuntu@ubuntu:pointer$ ./a.out aaa bbb ccc
argc=4
./a.out
aaa
bbb
ccc
1.13 指针函数
本质上是一个函数,主要是返回一个地址
格式:存储类型 数据类型 *函数名(参数列表)
char *strcpy(char *dest, const char *src);
需求:
/*返回局部变量的地址:段错误
int *fun()
{
int a=100;
int b=1;
int arr[2];//局部变量 调用fun函数arr分配空间,函数调用结束arr空间释放 0x10-0x17
arr[0]=a;
arr[1]=b;
return arr;//0x10
}*/
解决方法:
/*
*方法1:
int arr[2];//数组定义为全局变量
int *fun()
{
int a=100;
int b=1;
arr[0]=a;
arr[1]=b;
return arr;//0x10
}*/
/*
* 常使用 方法2:
int *fun(int arr[2])//arr=0x20
{
int a=100;
int b=1;
arr[0]=a;
arr[1]=b;
return arr;//0x20
}*/
方法3:
int *fun()//arr=0x20
{
int a=100;
int b=1;
int *p=(int *)malloc(10);//p指向堆区10个字节的首地址 0x10-0x19
*p=a;
*(p+1)=b;
return p;//0x10
}
int main(int argc, const char *argv[])
{
int arr[2];//0x20
int *p=fun();//0x20
printf("a=%d\n",*p);
printf("a=%d\n",*(p+1));
return 0;
}
练习:字符串拷贝,返回拷贝后的地址
char *strcpy(char *dest, char *src)
{
int i;
for(i=0;*(src+i)!='\0';i++)
{
*(dest+i)=*(src+i);
}
*(dest+i)='\0';
return dest;
}
1.14 函数指针
本质上是一个指针,用来指向函数的地址
格式:数据类型 (*指针变量名)(参数列表)
函数名表示函数的首地址,函数是没有办法计算字节
void sum() void (*p)()
void sum(int a,float b) void (*p)(int a,float b)
int sum() int (*p)()
int sum(int a,double b) int (*p)(int a,double b)
#include <string.h>
#include <stdlib.h>
void Sum()
{
int a=100,b=10;
printf("a+b=%d\n",a+b);
}
int main(int argc, const char *argv[])
{
Sum();//0x10 直接使用函数的地址调用函数
(*Sum)(); //通过地址存储的值进行调用函数
(*******Sum)();
printf("SUm=%p\n",Sum);
// printf("sizeof(SUm)=%ld\n",sizeof(Sum));
printf("*Sum=%p\n",*Sum);
printf("**Sum=%p\n",**Sum);
printf("*****Sum=%p\n",*****Sum);
void (*p)()=Sum;//p=Sum
p();//通过函数指针调用函数
(*p)();//通过函数指针指向地址对应的值调用函数
return 0;
}
1.15 函数指针数组
本质上是一个数组,存储多个函数指针
格式: 数据类型 (*数组名[常量表达式])(参数列表)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int add(int a,int b)//100 10
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
int mul(int a,int b)
{
return a*b;
}
int divs(int a,int b)
{
return a/b;
}
int main(int argc, const char *argv[])
{
int a=100,b=10;
//需要使用4个函数指针
int (*p1)(int,int)=add;
int (*p2)(int,int)=sub;
int (*p3)(int,int)=mul;
int (*p4)(int,int)=divs;
//定义一个
double a;
int *p=&a;
int (*p[4])(int,int)={add,sub,mul,divs};
for(int i=0;i<4;i++)
{
int s=(*(p+i))(a,b);
printf("s=%d\n",s);
}
return 0;
}
1.16 多级指针
一级指针存储变量的地址
二级指针存储一级指针的地址
三级指针存储二级指针的地址
....
定义格式: 存储类型 数据类型 ****指针变量名 【注意*个数不限】
注意:无论是几级指针,都是指针,指针在64位操作系统占8字节,32位占4字节
int main(int argc, const char *argv[])
{
int a=100;
int *p=&a;
int **q=&p;
int ***m=&q;
printf("p=%ld q=%ld m=%ld\n",sizeof(p),sizeof(q),sizeof(m));
printf("a=%d *p=%d **q=%d ***m=%d\n",a,*p,**q,***m);
printf("&a=%p p=%p *q=%p **m=%p\n",&a,p,*q,**m);
return 0;
}
1.17 通用类型指针
通用类型指针,可以指向任意一种类型的指针,可以指向任意一块地址,但是在使用时,必须进行类型强转。
格式: void *指针变量名
int a=100;
void *p=&a;
printf("*p=%d\n",*(int *)p);
int arr[3]
memset(arr,0,sizeof(arr));