1、多维数组与指针
用指针变量可以指向一维数组中的元素,也可以指向多维数组的元素。一个数组他的数组名就是这个数组的首地址,而指针变量里边存放的恰好就是一个地址。我们只要把这个指针变量里边存放的是一维数组的首地址,那么我们就说这个指针指向的就是这个数组。
下面是一个3行4列的数组,在内存中的存储其实他是线性排列存储的。
#include
void main()
{
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11,12};
printf("a:%d\n",a);
printf("*a:%d\n",*a);
printf("a[0]:%d\n",a[0]);
printf("&a[0]:%d\n",&a[0]);
printf("&a[0][0]:%d\n",&a[0][0]);
printf("a+1:%d\n",a+1);
printf("*(a+1):%d\n",*(a+1));
}
把二维数组a分解为一维数组a[0](我们这个a[0]又指向了四个元素,a[0]里面存放的是一个地址,这个地址有四个元素,那么也就是说它就是一个二维数组,),a[1](同理),a[2](同理)之后(说明这是一个a3x4的一个二维数组,概念就是当我这个一维数组这个元素里边存放的是另一个数组的地址的时候,那他就是一个二维数组,因为我这个元素a[0]还没完,里面还指向一个地址,这个地址是一个数组的地址,那就是二维数组了),设p为指向二维数组的指针变量。可定义为:
int (*p)[4];//它表示p是一个指针变量,它指向包含四个元素的一维数组。若指向第一个一维数组a[0],其值等于a,a[0],或者&a[0][0]等。
//而p+i则指向一维数组a[i];因为p指向的是a的地址。
//从前面的分析可以得出*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值
//怎么理解呢?????????
//因为我们之前解释,如果一维数组里面存放的是另外一个数组的地址那它就是一个二维数组。
//那我们这里p+i也就是说一维数组第几个元素取出他的值(比如是a[i],*(p+i)是一个地址值,**(p+i)才是对应第i行的首个元素值)
也就是相应一个二维数组的一个元素的初始地址,再加上j就是这个二维数组的偏移地址,第几列,然后我们再把总共的取出他的值。
//二维数组指针变量说明的一般形式为:
类型说明符 (*指针变量名)[长度]
其中“类型说明符”为所指数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。(//前面的不是应该声明为行数吗?那行数不用定义吗?)。行数不用定义,这个行数是多少。也就是说一维数组是多少我们的具体长度是看我们给他赋值,赋多少值它自动分配的。所以我们直接给出一个指针,指向它的行数的首地址就可以了。
例子:用指针输出二维数组元素变量的值
#include
void main()
{
int a[3][4]={};
int (*p)[4];//定义一个二维数组的指针,指向二维数组//切记(*p)中的括号一定要带
p=a;//将二维数组的地址指向了这个指针的地址
int i,j;//定为i和j来定义行和列
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf("%2d",*(*(p+i)+j));
}
printf("\n");
}
}
例子:通过输入指定行数和列数打印出二维数组对应任一行任一列元素的值。
#include
void main()
{
int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
int (*p)[4],i,j;
p=a;
printf("i=");
scanf("%d",&i);
while(i>2||i<0)
{
printf("i=");
scanf("%d",&i);
}
printf("j=");
scanf("%d",&j);
while(j>3||i<0)
{
printf("j=");
scanf("%d",&j);
}
printf("a[%d,%d]=%d\n",i,j,*(*(p+i)+j));//经过两次取值
}
2、字符串与指针
例子:定义一个字符数组,对他初始化,然后输出该字符串。(通过字符数组的形式来定义字符串)
#include
void main()
{
char string[]="I Love Fishc.com!";//不定义长度,让编译器自行计算
printf("%s\n",string);//s就是字符串的形式打印,给他一个地址,给他字符串的首地址他就会依次打印直到出现'\0'字符他就停止打印。
}
下面展示了元素依次存放,空格也占用一个元素。在最后还要补充一个'\0',\0这个字符相当于ASCII中的整形0。
图
例子:可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。
#include
void main()
{
char *string="I Love Fishc.com!";//这里定义的是一个字符指针,不再是一个字符串
printf("%s\n",string);
}
例子:将字符串a复制为字符串b
//下标法举例
#include
void main()
{
char a[]="A is a good man!",b[40];
int i;
for(i=0;*(a+i)!='\0';i++)//只要a数组的这个元素不为0,0就是字符串结束的标志
{
*(b+i)=*(a+i);//不为0的话就依次copy过去
}
*(b+i)='\0';//然后最后还应该把他补上0因为我们这个是字符串,如果没有补上的话,他就不知道字符串的结尾是哪里,她就会把内存中相关的我们定义的40个字符嘛,这些随机的数据他都会把它当成字符串给他显示出来直到没有。
printf("String a is:%s\n",a);
printf("String b is:");//2也可以直接打印b
for(i=0;b[i]!='\0';i++)
{
printf("%c",b[i]);//1使用了数组的索引方式打印的
}
printf("\n\n");
}
用指针的方法就是迭代循环里边的传递不同
//下标法举例
#include
void main()
{
char a[]="A is a good man!",*p1,*p2;//定义的两个指针分别指向数组a和数组b,那么我取出p1的值也就相当于取出a的值
int i;
p1=a;
p2=b;
for(;*p1!='\0';p1++,p2++)//++就是递增1,往后边元素,指向后边元素
{
*p2=*p1;//不为0的话就依次copy过去
}
*p2='\0';//然后最后还应该把他补上0因为我们这个是字符串,如果没有补上的话,他就不知道字符串的结尾是哪里,她就会把内存中相关的我们定义的40个字符嘛,这些随机的数据他都会把它当成字符串给他显示出来直到没有。
printf("String a is:%s\n",a);
printf("String b is:");//2也可以直接打印b
for(i=0;b[i]!='\0';i++)
{
printf("%c",b[i]);//1使用了数组的索引方式打印的
}
printf("\n\n");
}
用函数调用实现字符串的赋值
(1)用字符数组作参数。
(2)形参用字符指针变量。
//设一个函数process,在调用他的时候,每次实现不同的功能。
//输入a,b第一次调用process时找最大,第二次找最小,第三次求和。
#include
void main()
{
int max(int,int);
int min(int,int);
int add(int,int);
void process(int,int,int(*fun)());
int a,b;
printf("Enter a and b:");
scanf("%d %d",&a,&b);
printf("max=");
process(a,b,max);
printf("min=");
process(a,b,min);
printf("add");
process(a,b,add);
}
int max(int x,int y)
{
int z;
if(x>y)
{
z=x;
}
else
{
z=y;
}
return z;
}
一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。其概念与以前类似,只是带回的值的类型是指针类型而已。
这种带回指针值的函数,一般定义形式为:
类型名 *函数名(参数列表);
//例如:
int *a(int x,int y);//加上*号表示带回来的是指向整型的指针。如果不带回什么就void
例子:有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩,用指针函数来实现。
#include
void main()
{//用二维数组每一行表示每一个同学,4个列表示4门课程
double score[][4]={
{},{},{},{}};
double *search(double(*pointer)[4],int n);//定义了一个指针函数(他首先是一个函数,因为有一个括号,接着返回指针类型,这个指针还是指向double的指针)
double *p;
int i,m;
printf("PLease enter the number of student:");
scanf("%d",&m);
printf("The scores of No.%d are:",m);
p=search(score,m);//3返回值给p把他的地址给p,然后下边再打印出来。
for(i=0;i<4;i++)//打印第m行的元素值;p代表第m 行的首地址
{
printf("%5.2f\t",*(p+i));
}
printf("\n\n\n")
}
double *search(double(*pointer)[4],int n)
{
double *pt;
pt=*(pointer+n);//1序号加上行数的索引,取出来的就是说某一个学生的一个归于那一行地址的一个索引,然后再返回
return pt;//2返回的是二维数组第n行的首地址
}
对上例中的学生,找出其中有不及格课程的学生及其学生号。(对比一下,把各个成绩提取出来,如果小于60,Ok就把这个数组的指针给返回来,然后接收到指针把他对应的人给打印出来)
//代码
PS:指针函数和函数指针的区别(这两个概念都是简称)
指针函数:是指带指针的函数,即本质是一个函数。
函数指针:是指向函数的指针变量,因而函数指针本身首先是指针变量,只不过该指针变量指向函数。
指针数组(终究还是一个数组)的概念:
一个数组若其元素均为指针类型的数据,称为指针数组,也就说,指针数组中的每一个元素都相当于一个指针变量(也就是一堆指针变量排排站站成一队)。一维指针数组的定义形式为:
类型名 数组名[数组长度];
//例如:
int *name[4];//*表示他是一个指针