10.3.4指向多维数组的指针和指针变量
1、多维数组的地址
设有整型二维数组a[3][4]如下:
它的定义为: int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}
设数组a的首地址为1000,各下标变量的首地址及其值如图所示。
从二维数组的角度来看,a是二维数组名,a代表整个二维数组的首地址,
也是二维数组0行的首地址,等于1000。a+1代表第一行的首地址,等于1008。如图:
a,a[0],*(a+0),*a,&a[0][0]是相等的
2、指向多维数组的指针变量
二维数组指针变量说明的一般形式为: 类型说明符 (*指针变量名)[长度]
10.4 字符串的指针指向字符串的针指变量
10.4.1字符串的表示形式
在C语言中,可以用两种方法访问一个字符串
1) 、用字符数组存放一个字符串,然后输出该字符串。
例10.24
#include<stdio.h>
int main(void)
{
char string[]="I love China!";
printf("%s\n",string);
}
说明:和前面介绍的数组属性一样,string是数组名,它代表字符数组的首地址
2) 、用字符串指针指向一个字符串。
例10.25
#include<stdio.h>
int main(void)
{
char *string="I love China!";
printf("%s\n",string);
}
字符串指针变量的定义说明与指向字符变量的指针变量说明是相同的。
只能按对指针变量的赋值不同来区别。对指向字符变量的指针变量应赋予该字
符变量的地址。
如: char c,*p=&c;
char *s="C Language";
例10.26 输出字符串中n个字符后的所有字符。
#include<stdio.h>
int main(void)
{
char *ps = "this is a book";
int n=10;
ps=ps+n;
printf("%s\n",ps);
}
说明:
在程序中对ps初始化时,即把字符串首地址赋予ps,当ps= ps+10之后,
ps指向字符“b”,因此输出为"book"。
例10.27 在输入的字符串中查找有无‘k’字符。
#include<stdio.h>
int main(void)
{
char st[20],*ps;
int i;
printf("input a string:\n");
ps=st;
scanf("%s",ps);
for(i=0;ps[i]!='\0';i++)
if(ps[i]=='k')
{
printf("there is a'k' in the string\n");
break;
}
if(ps[i]=='\0')
printf("Thers is no 'k' in the string\n");
}
例10.29 把字符串指针作为函数参数的使用。要求把一个字符串的内容
复制到另一个字符串中,并且不能使用strcpy函数。
#include<stdio.h>
void cpystr(char *pss,char *pds)
{
while((*pds=*pss)!='\0')
{
pds++;
pss++;
}
}
int main(void)
{
char *pa="CHINA",b[10],*pb;
pb=b;
cpystr(pa,pb);
printf("string a=%s\nstring b=%s\n",pa,pb);
}
在本例中,程序完成了两项工作:一是把pss指向的源字符串复制到pds所
指向的目标字符串中,二是判断所复制的字符是否为`\0',若是则表明源字
符串结束,不再循环。否则,pds和pss都加1,指向下一字符。
10.4.2使用字符串指针变量与字符数组的区别
1.、字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串
本身是存放在以该首地址为首的一块连续的内存空间中并以‘\0’作为串的结束。
字符数组是由于若干个数组元素组成的,它可用来存放整个字符串。
2.、对字符串指针方式
char *ps="C Language";
可以写为: char *ps; ps="C Language";
而对数组方式: static char st[]={"C Language"};
不能写为: char st[20]; st={"C Language"};
而只能对字符数组的各元素逐个赋值。
10.5 函数指针变量
在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所
占内存区的首地址。我们可以把函数的这个首地址(或称入口地址)赋予一个
指针变量,使该指针变量指向该函数。然后通过指针变量就可以找到并调用
这个函数。我们把这种指向函数的指针变量称为“函数指针变量”。
函数指针变量定义的一般形式为:
类型说明符 (*指针变量名) ();
其中“类型说明符”表示被指函数的返回值的类型。“(* 指针变量名)”表示“*”后
面的变量是定义的指针变量。最后的空括号表示指针变量所指的是一个函数。
例如: int (*pf)(); 表示pf是一个指向函数入口的指针变量,
该函数的返回值(函数值)是整型。
例10.31
#include<stdio.h>
int max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
int main(void)
{
int max(int a,int b);
int(*pmax)();//定义一个指向函数的指针变量*pmax
int x,y,z;
pmax=max;
printf("input two numbers:\n");
scanf("%d%d",&x,&y);
z=(*pmax)(x,y);
printf("maxmum=%d\n",z);
}
10.6 指针型函数
在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的
函数称为指针型函数。
定义指针型函数的一般形式为:
类型说明符 *函数名(形参表)
{
…… /*函数体*/
}
其中函数名之前加了“*”号表明这是一个指针型函数,即返回值是一个指针。
类型说明符表示了返回的指针值所指向的数据类型。
例10.32 本程序是通过指针函数,输入一个1~7之间的整数,输出对应的星期名。
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int i;
char *day_name(int n);
printf("input Day No:\n");
scanf("%d",&i);
if(i<0)exit(1);
printf("Day No:%2d->%s\n",i,day_name(i));
}
char *day_name(int n)
{
static char *name[]={ "Illegal day",
"Monday",
"Tuesdy",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"};
return((n<1||n>7)?name[0]:name[n]);
}
本例中定义了一个指针型函数day_name,它的返回值指向一个字符串。
该函数中定义了一个静态指针数组name。name数组初始化赋值为八个字符串,
分别表示各个星期名及出错提示。形参n表示与星期名所对应的整数。
主函数中,把输入的整数i作为实参,在printf语句中调用day_name函数并把i值
传送给形参n。day_name函数中的return语句包含一个条件表达式,n值若大于
7或小于1则把name[0]指针返回主函数输出出错提示字符串“Illegal day”。否则
返回主函数输出对应的星期名。主函数中的第7行是个条件语句,其语义是,
如输入为负数(i<0)则中止程序运行退出程序。exit是一个库函数,exit(1)表示发
生错误后退出程序,exit(0)表示正常退出。
10.7 指针数组和指向指针的指针
10.7.1指针数组的概念
指针数组说明的一般形式为:
类型说明符 *数组名[数组长度]
其中类型说明符为指针值所指向的变量的类型。
例如: int *pa[3]
表示pa是一个指针数组,它有三个数组元素,每个元素值都是一个指针,
指向整型变量。
例10.33 通常可用一个指针数组来指向一个二维数组。指针数组中的每
个元素被赋予二维数组每一行的首地址,因此也可理解为指向一个一维数组。
#include<stdio.h>
int main(void)
{
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *pa[3]={a[0],a[1],a[2]};
int *p=a[0];
int i;
for(i=0;i<3;i++)
printf("%d,%d,%d\n",a[i][2-i],*a[i],*(*(a+i)+i));
for(i=0;i<3;i++)
printf("%d,%d,%d\n",*pa[i],p[i],*(p+i));
}
例10.34 指针数组作指针型函数的参数。
在本例主函数中,定义了一个指针数组name,并对name 作了初始化赋值。
其每个元素都指向一个字符串。然后又以name作为实参调用指针型函数
day_name,在调用时把数组名name赋予形参变量name,输入的整数i作为
第二个实参赋予形参n。在day_ name函数中定义了两个指针变量pp1和pp2,
pp1被赋予name[0]的值(即*name),pp2被赋予name[n]的值即*(name+ n)。
由条件表达式决定返回pp1或pp2指针给主函数中的指针变量ps。
最后输出i和ps的值。
#include<stdio.h>
#include<stdlib.h>
char *day_name(char *name[],int n)
{
char *pp1,*pp2;
pp1=*name;
pp2=*(name+n);
return((n<1||n>7)?pp1:pp2);
}
int main(void)
{
static char *name[]={"Illegal day",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday"};
char *ps;
int i;
char *day_name(char *name[],int n);
printf("input Day No:\n");
scanf("%d",&i);
if(i<0)exit(1);
ps=day_name(name,i);
printf("Day No:%2d-->%s\n",i,ps);
}
例10.35 输入5个国名并按字母顺序排列后输出。现编程如下:
#include"string.h"
#include<stdio.h>
int main(void)
{
void sort(char *name[],int n);
void print(char *name[],int n);
static char *name[]={"CHINA","AMERICA","AUSTERALIA","FRANCE","GERMAN"};
int n=5;
sort(name,n);
print(name,n);
}
void sort(char *name[],int n)
{
char *pt;
int i,j,k;
for(i=0;i<n-1;i++)
{
k=i;
for(j=i+1;j<n;j++)
if(strcmp(name[k],name[j])>0)k=j;
if(k!=i)
{
pt=name[i];
name[i]=name[k];
name[k]=pt;
}
}
}
void print(char *name[],int n)
{
int i;
for(i=0;i<n;i++)
printf("%s\n",name[i]);
}
本程序定义了两个函数,一个名为sort完成排序,其形参为指针数组name,
即为待排序的各字符串数组的指针。形参n为字符串的个数。另一个函数名
为print,用于排序后字符串的输出,其形参与sort的形参相同。主函数main
中,定义了指针数组name 并作了初始化赋值。然后分别调用sort函数和print
函数完成排序和输出。值得说明的是在sort函数中,对两个字符串比较,采
用了strcmp函数,strcmp函数允许参与比较的字符串以指针方式出现。
name[k]和name[j]均为指针,因此是合法的。字符串比较后需要交换时,
只交换指针数组元素的值,而不交换具体的字符串,这样将大大减少时间的
开销,提高了运行效率。
10.7.2指向指针的指针
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为
指向指针的指针变量。
指针数组的元素只能存放地址。
10.7.3main函数的参数