我们之前粗粗的讲了如何使用数组存放多个相同类型的数据并进行计算,但是在之前的文章里,我好像强调了无数次数组不要越界,这就意味着我们数组的长度在定义时必须给定,以后不能改变。
这个道理有点类似于for循环for(...)不知道齐全条件时我们使用的while循环;
使用指针可以对一些复杂数据进行处理,对计算机内存分配进行控制,在函数调用时使用指针还可以返回多个值。
首先认识一下老朋友“&”
·scanf("%d",&n)里的&,它是用来获取变量的地主,而他的操作必须是变量:
这就说&不能对没有地址的东西取地址
·&(a+b) X
·&(a++) X
·&(++a) X
&就是一个地址运算符,而*就是间接运算符
int a=12; int b; int *p; int **ptr;
p=&a; //&a 的结果是一个指针,类型是int*,指向的类型是
//int,指向的地址是a 的地址。
*p=24; //*p 的结果,在这里它的类型是int,它所占用的地址是
//p 所指向的地址,显然,*p 就是变量a。
ptr=&p; //&p 的结果是个指针,该指针的类型是p 的类型加个*,
//在这里是int **。该指针所指向的类型是p 的类型,这
//里是int*。该指针所指向的地址就是指针p 自己的地址。
*ptr=&b; //*ptr 是个指针,&b 的结果也是个指针,且这两个指针
//的类型和所指向的类型是一样的,所以用&b 来给*ptr 赋
//值就是毫无问题的了。
**ptr=34; //*ptr 的结果是ptr 所指向的东西,在这里是一个指针,
//对这个指针再做一次*运算,结果是一个int 类型的变量。
其次呢了解一下指针类型:
int p; //这是一个普通的整型变量
int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级比*高,所以P 是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组
int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.
接着我们来看这(zhe)么(mo)道题:
几位同学去玩某密室逃脱游戏,密室门上有一把四位数的数字密码锁,只有在密室中找到开锁密码才能走出密室。密室中整齐地摆放着规格大小完全相同的 26个寄存箱,每个寄存箱上按顺宇都有一个英文字母和一个编号,字母从A到Z,编号从01 到 26。 同学们在密室中认真搜寻,在角落里找到一把钥匙,钥匙上刻着字母P,用这把钥匙打开P寄存箱(编号为 16),里面是一把刻着数字 24 的钥匙,用这把钥匙再打开编号为 24的X寄存箱,里面有一张子条,上面写着 “5342”。用这四个数字去开密码锁,果然打开了,成功逃脱密室。
将以上过程用C语言程序进行表达:
#include<stdio.h>
int main(void)
{
int x;
x=5432;//密码值
int *p=NULL;//定义整形变量p,NULL值为0,代表空指针
p=&x;//将变量x的地址存储在p中
printf("%d\n",x);//通过变量名x输出密码值
//通过变量x的地址输出密码值
printf("%d\n",p,*p);
return 0;
}
我们在程序中定义了变量x来存储密码,再定义一个特殊指针变量p,用于存放变量x的地址。这样一来既可以通过变量名x得到密码值,也可以在不知道变量名的情况下,通过指针变量p所存放的x的地址间接找到密码值。
那我们数组老是要注意不能越界,而指针又有什么要注意的呢
野指针
(1)指针未初始化
#include <stdio.h>
int main()
{
int* p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
(2)指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for (i = 0; i <= 11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
(3)指针指向的空间释放
int* test( )
{
int a = 5;
return &a;
}
int main()
{
int* p = test();
*p = 10;
return 0;
}
欸,若我们要通过函数调用来改变主调函数中某个变量的值,可以把指针作为函数的参数,在主调函数中,将该变量的地址指向该变量的指针作为实参,在被调函数中,用指针类型形参接受该变量的地址,并改变形参所指向变量的值。
在这里,如果我们希望函数调用能将多个计算结果带回主调函数,用return语句是无法实现的,而将指针作为函数的参数就能使函数返回多个值。
具体我们来看下面这道题:
输入年份和天数,输出对应的年、月、日。要求定义和调用函数month_day( int year, int yearday, int *pmonth, int *pyear), 其中year是年,yearday是天数,pmonth和pday指向的变量保存计算得出的月和日。
例如, 输入2000和61,输出2000-3-1。
#include<stdio.h>
void month_day(int year,int yearday,int *pmonth,int *pday);//申明函数
int main(void)
{
int day,month,year,yearday;
scanf("%d %d",&year,&yearday);
month_day(year,yearday,&month,&day);//调用函数
printf("%d-%d-%d\n",year,month,day);
return 0;
}
void month_day(int year,int yearday,int *pmonth,int *pday)
{
int k,leap;
int tab[2][13]
{
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31},
};//定义数组存放(非)闰年每个月的天数
//判断闰年
leap=(year%4==0 && year%100!=0)||year%400==0;
for(k=1;yearday>tab[leap][k];k++)
yearday-=tab[leap][k];
*pmonth=k;
*pday=yearday;
}
在函数main( )中调用函数month_day( )时,将变量month和day的地址作为实参,在被调用函数中使用形参指针pmonth和pday分别接收地址,并改变了形参所指向变量的值。因此,函数main( )中month和day的值也随之改变。
暂时还没有没有几道题,等我去整理整理发出来
罢了~
罢了~