⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 6_指针.txt

📁 一些c的经典案例
💻 TXT
📖 第 1 页 / 共 3 页
字号:
将变量i的值赋给由指针pa指向的a[]的数组单元
用指针输出数组a中的所有元素,同时指针pa指向a[]的下一个单元
......
......数组名和数组指针变量作函数参数
     在第五章中曾经介绍过用数组名作函数的实参和形参的问题。
在学习指针变量之后就更容易理解这个问题了。 数组名就是数组的
首地址,实参向形参传送数组名实际上就是传送数组的地址, 形参
得到该地址后也指向同一数组。 这就好象同一件物品有两个彼此不
同的名称一样。
    同样,指针变量的值也是地址, 数组指针变量的值即为数组的
首地址,当然也可作为函数的参数使用。
float aver(float *pa);
main(){
  float sco[5],av,*sp;
  int i;
  sp=sco;
  printf("\ninput 5 scores:\n");
  for(i=0;i<5;i++) scanf("%f",&sco[i]);
  av=aver(sp);
  printf("average score is %5.2f",av);
}
float aver(float *pa)
{
  int i;
  float av,s=0;
  for(i=0;i<5;i++) s=s+*pa++;
  av=s/5;
  return av;
}指向多维数组的指针变量
本小节以二维数组为例介绍多维数组的指针变量。一、多维数组地址的表示方法
    设有整型二维数组a[3][4]如下:    0   1   2   3
    4   5   6   7
    8   9  10  11    设数组a的首地址为1000,各下标变量的首地址及其值如图所示。
在第四章中介绍过, C语言允许把一个二维数组分解为多个一维数
组来处理。因此数组a可分解为三个一维数组,即a[0],a[1],a[2]。
每一个一维数组又含有四个元素。
    例如a[0]数组,含有a[0][0],a[0][1],a[0][2],a[0][3]四个
元素。 数组及数组元素的地址表示如下:
    a是二维数组名,也是二维数组0行的首地址,等于1000。a[0]是
第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与
a[0]等效的, 它表示一维数组a[0]0 号元素的首地址。 也为1000。
&a[0][0]是二维数组a的0行0列元素首地址,同样是1000。因此,a,
a[0],*(a+0),*a,&a[0][0]是相等的。同理,a+1是二维数组1行的
首地址,等于1008。a[1]是第二个一维数组的数组名和首地址,因此
也为1008。 &a[1][0]是二维数组a的1行0列元素地址,也是1008。因
此a+1,a[1],*(a+1),&a[1][0]是等同的。 由此可得出:a+i,a[i],
*(a+i),&a[i][0]是等同的。 此外,&a[i]和a[i]也是等同的。因为
在二维数组中不能把&a[i]理解为元素a[i]的地址,不存在元素a[i]。
C语言规定,它是一种地址计算方法,表示数组a第i行首地址。由此,
我们得出:a[i],&a[i],*(a+i)和a+i也都是等同的。另外,a[0]也
可以看成是a[0]+0是一维数组a[0]的0号元素的首地址, 而a[0]+1则
是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a[i]的j号
元素首地址,它等于&a[i][j]。由a[i]=*(a+i)得a[i]+j=*(a+i)+j,
由于*(a+i)+j是二维数组a的i行j列元素的首地址。该元素的值等于
*(*(a+i)+j)。
[Explain]#define PF "%d,%d,%d,%d,%d,\n"
main(){
    static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    printf(PF,a,*a,a[0],&a[0],&a[0][0]);
    printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
    printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
    printf("%d,%d\n",a[1]+1,*(a+1)+1);
    printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));
}二、多维数组的指针变量
    把二维数组a 分解为一维数组a[0],a[1],a[2]之后,设p为指向
二维数组的指针变量。可定义为:          int (*p)[4]    它表示p是一个指针变量,它指向二维数组a 或指向第一个一维
数组a[0],其值等于a,a[0],或&a[0][0]等。而p+i则指向一维数组
a[i]。从前面的分析可得出*(p+i)+j是二维数组i行j 列的元素的地
址,而*(*(p+i)+j)则是i行j列元素的值。
二维数组指针变量说明的一般形式为:    类型说明符  (*指针变量名)[长度]      其中“类型说明符”为所指数组的数据类型。“*”表示其后的
变量是指针类型。 “长度”表示二维数组分解为多个一维数组时,
一维数组的长度,也就是二维数组的列数。应注意“(*指针变量名)”
两边的括号不可少,如缺少括号则表示是指针数组(本章后面介绍),
意义就完全不同了。
[Explain]main(){
    static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int(*p)[4];
    int i,j;
    p=a;
    for(i=0;i<3;i++)
        for(j=0;j<4;j++) printf("%2d  ",*(*(p+i)+j));
}'Expain字符串指针变量的说明和使用
     字符串指针变量的定义说明与指向字符变量的指针变量说明是
相同的。只能按对指针变量的赋值不同来区别。 对指向字符变量的
指针变量应赋予该字符变量的地址。如:    char c,*p=&c;表示p是一个指向字符变量c的指针变量。而:    char *s="C Language";则表示s是一个指向字符串的指针变量。把字符串的首地址赋予s。
    请看下面一例。main(){
  char *ps;
  ps="C Language";
  printf("%s",ps);
}
运行结果为:
C Language    上例中,首先定义ps是一个字符指针变量, 然后把字符串的首
地址赋予ps(应写出整个字符串,以便编译系统把该串装入连续的一
块内存单元),并把首地址送入ps。程序中的:    char *ps;
    ps="C Language";等效于:    char *ps="C Language";
输出字符串中n个字符后的所有字符。main(){
  char *ps="this is a book";
  int n=10;
  ps=ps+n;
  printf("%s\n",ps);
}
运行结果为:
    book    在程序中对ps初始化时,即把字符串首地址赋予ps,当ps= ps
+10之后,ps指向字符“b”,因此输出为"book"。
main(){
  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("There is no 'k' in the string\n");
}
本例是在输入的字符串中查找有无‘k’字符。    下面这个例子是将指针变量指向一个格式字符串,用在printf函
数中,用于输出二维数组的各种地址表示的值。但在printf语句中用
指针变量PF代替了格式串。 这也是程序中常用的方法。
main(){
  static int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
  char *PF;
  PF="%d,%d,%d,%d,%d\n";
  printf(PF,a,*a,a[0],&a[0],&a[0][0]);
  printf(PF,a+1,*(a+1),a[1],&a[1],&a[1][0]);
  printf(PF,a+2,*(a+2),a[2],&a[2],&a[2][0]);
  printf("%d,%d\n",a[1]+1,*(a+1)+1);
  printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));
}    在下例是讲解,把字符串指针作为函数参数的使用。要求把一个
字符串的内容复制到另一个字符串中,并且不能使用strcpy函数。函
数cprstr的形参为两个字符指针变量。pss指向源字符串,pds指向目
标字符串。表达式:    (*pds=*pss)!=`\0'
cpystr(char *pss,char *pds){
  while((*pds=*pss)!='\0'){
      pds++;
      pss++; }
 }
main(){
  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,指向下
一字符。在主函数中,以指针变量pa,pb为实参,分别取得确定值后
调用cprstr函数。由于采用的指针变量pa和pss,pb和pds均指向同一
字符串,因此在主函数和cprstr函数中均可使用这些字符串。也可以
把cprstr函数简化为以下形式:    cprstr(char *pss,char*pds)
      {while ((*pds++=*pss++)!=`\0');}
    即把指针的移动和赋值合并在一个语句中。 进一步分析还可发
现`\0'的ASCⅡ码为0,对于while语句只看表达式的值为非0就循环,
为0则结束循环,因此也可省去“!=`\0'”这一判断部分,而写为以
下形式:
      cprstr (char *pss,char *pds)
             {while (*pdss++=*pss++);}    表达式的意义可解释为,源字符向目标字符赋值, 移动指针,
若所赋值为非0则循环,否则结束循环。这样使程序更加简洁。简化
后的程序如下所示。cpystr(char *pss,char *pds){
    while(*pds++=*pss++);
}
main(){
  char *pa="CHINA",b[10],*pb;
  pb=b;
  cpystr(pa,pb);
  printf("string a=%s\nstring b=%s\n",pa,pb);
}使用字符串指针变量与字符数组的区别
    用字符数组和字符指针变量都可实现字符串的存储和运算。 但
是两者是有区别的。在使用时应注意以下几个问题:
1. 字符串指针变量本身是一个变量,用于存放字符串的首地址。而
   字符串本身是存放在以该首地址为首的一块连续的内存空间中并
   以‘\0’作为串的结束。字符数组是由于若干个数组元素组成的,
   它可用来存放整个字符串。2. 对字符数组作初始化赋值,必须采用外部类型或静态类型,如:    static char st[]={“C Language”};
而对字符串指针变量则无此限制,如:    char *ps="C Language";
3. 对字符串指针方式    char *ps="C Language";可以写为:    char *ps;
    ps="C Language";
而对数组方式:    static char st[]={"C Language"};不能写为:    char st[20];
    st={"C Language"};而只能对字符数组的各元素逐个赋值。
     从以上几点可以看出字符串指针变量与字符数组在使用时的区
别,同时也可看出使用指针变量更加方便。
    前面说过,当一个指针变量在未取得确定地址前使用是危险的,
容易引起错误。但是对指针变量直接赋值是可以的。因为C系统对指
针变量赋值时要给以确定的地址。因此,    char *ps="C Langage";或者    char *ps;
    ps="C Language";都是合法的。
函数指针变量
    在C语言中规定,一个函数总是占用一段连续的内存区, 而函
数名就是该函数所占内存区的首地址。 我们可以把函数的这个首地
址(或称入口地址)赋予一个指针变量, 使该指针变量指向该函数。
然后通过指针变量就可以找到并调用这个函数。 我们把这种指向函
数的指针变量称为“函数指针变量”。
函数指针变量定义的一般形式为:    类型说明符  (*指针变量名)();      其中“类型说明符”表示被指函数的返回值的类型。“(* 指针
变量名)”表示“*”后面的变量是定义的指针变量。 最后的空括号
表示指针变量所指的是一个函数。例如:    int (*pf)();
    表示pf是一个指向函数入口的指针变量,该函数的返回值(函数
值)是整型。
    下面通过例子来说明用指针形式实现对函数调用的方法。
int max(int a,int b){
  if(a>b)return a;
  else return b;
}
main(){
  int max(int a,int b);
  int(*pmax)();
  int x,y,z;
  pmax=max;
  printf("input two numbers:\n");
  scanf("%d%d",&x,&y);
  z=(*pmax)(x,y);
  printf("maxmum=%d",z);
}   从上述程序可以看出用,函数指针变量形式调用函数的步骤如下:1. 先定义函数指针变量,如后一程序中第9行 int (*pmax)();定义
   pmax为函数指针变量。
2. 把被调函数的入口地址(函数名)赋予该函数指针变量,如程序中
   第11行 pmax=max;
3. 用函数指针变量形式调用函数,如程序第14行 z=(*pmax)(x,y);
   调用函数的一般形式为:    (*指针变量名) (实参表)  
使用函数指针变量还应注意以下两点:a. 函数指针变量不能进行算术运算,这是与数组指针变量不同的。
   数组指针变量加减一个整数可使指针移动指向后面或前面的数组
   元素,而函数指针的移动是毫无意义的。
b. 函数调用中"(*指针变量名)"的两边的括号不可少,其中的*不应
   该理解为求值运算,在此处它只是一种表示符号。
指针型函数
    前面我们介绍过,所谓函数类型是指函数返回值的类型。 在C
语言中允许一个函数的返回值是一个指针(即地址), 这种返回指针
值的函数称为指针型函数。
定义指针型函数的一般形式为:    类型说明符 *函数名(形参表)  
    {  
        ……          /*函数体*/
    }  
    其中函数名之前加了“*”号表明这是一个指针型函数,即返回
值是一个指针。类型说明符表示了返回的指针值所指向的数据类型。
如:
    int *ap(int x,int y)
    {
      ......       /*函数体*/
    }    表示ap是一个返回指针值的指针型函数, 它返回的指针指向一
个整型变量。
    下例中定义了一个指针型函数 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)表示正常退
出。
     应该特别注意的是函数指针变量和指针型函数这两者在写法和
意义上的区别。如int(*p)()和int *p()是两个完全不同的量。int
 (*p)()是一个变量说明,说明p 是一个指向函数入口的指针变量,
该函数的返回值是整型量,(*p)的两边的括号不能少。int *p() 则
不是变量说明而是函数说明,说明p是一个指针型函数,其返回值是
一个指向整型量的指针,*p两边没有括号。作为函数说明, 在括号
内最好写入形式参数,这样便于与变量说明区别。 对于指针型函数
定义,int *p()只是函数头部分,一般还应该有函数体部分。
main(){
  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",
                        "Tuesday",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -