Discuz教程网

C语言案例教程 - 第六章:指 针

[复制链接]
authicon 09927306 发表于 2011-1-8 13:29:41 | 显示全部楼层 |阅读模式
本帖最后由 09927306 于 2011-1-8 18:35 编辑

第6章:指针
【例6-1】
当变量或数组定义后,就可以用&运算符来查看它们的地址。


  1.    main()
  2.           { int a=1;
  3.             float b=2;
  4.             double c=3;
  5.             int d[6];
  6.             printf("address of a is %p\\n",&a);
  7.             printf("address of b is %p\\n",&b);
  8.             printf("address of c is %p\\n",&c);
  9.             printf("address of array d is %p\\n",d);
  10.             printf("address of d[0] is %p\\n",&d[0]);
  11.             printf("address of d[1] is %p\\n",&d[1]);
  12.           }
复制代码


在printf()函数中,用%p来控制地址量的输出,可以得到4位十六进制数表示的地址。也可以用%x控制输出地址量。它们的差别在于:%p输出的地址固定为4位,不足4位的补以前导0,而%x则不加前导0。程序运行结果如下(不同的机器配置,输出的地址值也不同,仅作参考):

address of a is FFC6

address of b is FFC8

address of c is FFCC

address of array d is FFD4


address of d[0] is FFD4

address of d[1] is FFD6
【例6-2】
使用指针访问变量示例。


  1.     main()
  2.           { int a,*p=&a;
  3.             scanf("%d",p);         /*等价于scanf("%d",p);*/
  4.             (*p)++;                    /*等价于a++;*/
  5.             printf("%d\\n",p[0]);    /*等价于printf("%d\\n",a);*/
  6.           }
复制代码


注意,在(*p)++中,由于“*”和“++”优先级相同,结合性均为从右到左,因此括号是必须的。若写成*p++就表示先取a的值,然后将p指向下一个数据单元,而下一个数据单元中的值是不确定的,从而造成输出结果为不定值。
【例6-3】
通过将指针加减一个整数来移动指针示例。


  1.    #include <stdio.h>
  2.         main()
  3.           { int a=10,b=20,c=30,d=40;
  4.             int *pb=&b;
  5.             printf("%d,%d,%d,%d,%d\\n",*(pb-1),*pb,*(pb+1),*(pb+2));
  6.           }
复制代码


程序运行时,int型指针pb中存放的是同类型变量b的地址FF02,即pb指向变量b。pb+1表示pb的值在FF02的基础上增加2(字节),结果为FF04,这是变量c的首地址,因此,*(pb+1)表示访问变量c的值。同样,*(pb–1)表示访问FF00即变量a的值,*(pb+2)表示访问FF06即变量d的值。程序运行结果如下:


10,20,30,40
【例6-4】
指针被赋值后,指针的指向发生变化的示例。


  1.      #include <stdio.h>
  2.         main()
  3.           { int a=10,b=20;
  4.             float x=2.5;
  5.             int *p=&a;
  6.             printf("%d",*p);
  7.             p++;
  8.             printf("%d",*p);
  9.             p++;
  10.             printf("%d\\n",*p);
  11.           }
复制代码


程序运行时,在进行p++运算前,p指向变量a;在进行第一次p++运算后,p的值增加了2字节,结果指向了变量b;在进行了第二次p++运算后,p的值又增加了2字节,结果指向了变量x,而变量x占用4字节存储单元,所以,当用*p来访问时,将得到错误结果。编译系统并不具备纠正此类错误的能力,因此在移动指针时,一定要保证存储单元中数据类型的一致性。程序运行结果如下:

10
20
0
【例6-5】
两个同类型指针相减示例。


  1.         #include <stdio.h>
  2.         main()
  3.           { float x[10];
  4.             float *p,*q;
  5.             p=&x[0];
  6.             q=&x[5];
  7.             printf("q-p=%d\\n",q-p);
  8.           }
复制代码


指针p指向数组元素x[0],指针q指向数组元素x[5],其间相差5个数据单元,即5个元素,因此程序的运行结果如下:


q-p=5
【例6-6】
用指针及移动指针来实现一维数组的输入和输出。


  1. #include <stdio.h>
  2. main()
  3. { int a[10];
  4. int *p=a;
  5. for (;p<a+10;p++)
  6. scanf("%d",p);
  7. for (p=a;p<a+10;p++)
  8. printf("%d",*p);
  9. printf("\\n");
  10. }
复制代码


在该程序中,当定义了指向数组a的指针p后,在scanf()执行时,虽然每次循环的输入项都是p,但由于p的值随着p++在不断增加,即p的指向在不断向数组的底部移动,因此能把输入的数据依次保存到各个数组元素中。循环结束后,指针p已指到数组a最后一个元素的后面,因此在输出时,要将p重新移动到数组a的首地址上。
【例6-7】
用数组和指针模拟堆栈。
堆栈是一种先进后出或后进先出的数据结构。堆栈的特点是最先进栈的数据要到最后才能出栈。例如,若干列火车通过一条铁轨入库,最后入库的火车要最先出库。为了模拟堆栈,可以设置一个指向数组的指针,通过指针的移动可以很方便地模拟入栈和出栈。假设堆栈长度为N个整数,程序如下:


  1.         #include <stdio.h>
  2.          #define N 10
  3.          main()
  4.            { int a[N];
  5.              int i,*p=a;
  6.              while (p<a+N)
  7.                scanf("%d",p++);         /* PUSH(入栈) */
  8.              while (p>a)
  9.                printf("%d",*(--p));   /* POP(出栈) */
  10.              printf("");
  11.            }
复制代码


程序的第一个while循环模拟入栈操作,通过将指针逐步向数组的底部移动来顺序输入各个元素值;第二个while模拟出栈操作,通过将指针逐步向数组的顶部移动来反序输出各个元素值,运行情况如下:

1
2
3
4
5
6
7
8
9
10↙

10
9
8
7
6
5
4
3
2
1
【例6-8】
定义一个int型二维数组a[M][N],按存储结构定义数组指针p,利用指针按行的顺序输入数据,并按矩阵形式输出。其中,数组元素a[j]可以用*(&a[0][0]+i*N+j)、*(a[0]+i*N+j)、*(*a+i*N+j)、*(p+i*N+j)或p[i*N+j]等形式来访问。程序如下:


  1.        #define M 5
  2.         #define N 4
  3.         main()
  4.          { int a[M][N],*p=a[0],i,j;
  5.            for (;p<a[0]+20;p++)
  6.              scanf("%d",p);
  7.            p=a[0];
  8.            for(i=0;i<M;i++)
  9.             { for(j=0;j<N;j++)
  10.                 printf("%d  ",p[i*N+j]);
  11.               printf("\\n");
  12.             }
  13.          }
复制代码


【例6-9】
用行指针和指针移动的方法求二维数组a[M][N]各行的平均值,并将各行平均值依次存放在数组b[M]中。程序如下:


  1.         #define M 5
  2.         #define N 4
  3.         main()
  4.           { static int a[M][N],(*pa)[N]=a,i,j;
  5.             float b[M],*pb=b,s;
  6.             for (i=0;i<M;i++)
  7.               for (j=0;j<N;j++)
  8.                 scanf("%d",&pa[i][j]);
  9.             for (i=0;i<M;i++)
  10.            { s=0;
  11.             for(j=0;j<N;j++)
  12.                   s+=pa[i][j];
  13.                 pb[i]=s/N;
  14.               }
  15.             for(i=0;i<M;i++)
  16.               printf("%f",pb[i]);
  17.           }
复制代码


【例6-10】
用指针数组和指针移动的方法求二维数组a[M][N]各行的最大值,并将各行最大值依次存放在数组b[M]中。



  1.         #define M 5
  2.         #define N 4
  3.         main()
  4.           { static int a[M][N],*pa[M]={a[0],a[1],a[2],a[3],a[4]},i,j;
  5.             float b[M],*pb=b,s;
  6.             for (i=0;i<M;i++)
  7.               for (j=0;j<N;j++)
  8.                 scanf("%d",&pa[i][j]);
  9.             for (i=0;i<M;i++)
  10. { s=pa[0][0];
  11. for(j=0;j<N;j++)
  12.                   if(s<pa[i][j]) s=pa[i][j];
  13.                 pb[i]=s;
  14.               }
  15.             for(i=0;i<M;i++)
  16.               printf("%f",pb);
  17.           }


复制代码

上一章:C语言案例教程 - 第五章 数组和字符串
下一章:C语言案例教程 - 第七章 程序的模块结构和C函数






上一篇:C语言案例教程 - 第五章 数组和字符串
下一篇:白盒测试覆盖标准
authicon  楼主| 09927306 发表于 2011-1-8 13:30:31 | 显示全部楼层
本帖最后由 09927306 于 2011-1-8 18:36 编辑

【例6-11】
编一个程序,把字符串t复制到字符串s中(不使用strcpy()函数)。
为了体现对比效果,我们分别用数组和指针两种方法来编制该程序。
用字符型数组实现时,只要不断改变数组的下标,顺序地从数组t中读出各个字符,每读出一个字符t,就通过s=t把它存放到s数组的对应元素中,当遇到t数组中的’\0’字符时,赋值表达式s=t的值为0,控制while结束复制过程。程序如下:


  1.         #include <stdio.h>
  2.         main()
  3.           { char s[16],t[]="I am a student.";
  4.             int i=0;
  5.             while (s[i]=t[i])
  6.               i++;
  7.             printf("%s",s);
  8.             printf("%s\n",t);
  9.           }
复制代码


用字符型指针实现时,可以通过指针的加1运算,即用*s1++=*t1++同时完成移动指针、赋值和循环测试三重功能。程序如下:


  1.         #include <stdio.h>
  2.         main()                       
  3.           { char s[16],t[]="I am a student.",*s1=s,*t1=t;
  4.             while (*s1++=*t1++)
  5.                     ;
  6.             printf("%s",s);
  7.             printf("%s\n",t);
  8.           }
复制代码


【例6-12】
编一个程序计算从键盘输入的一个字符串的长度(不使用strlen函数)。
将输入的字符串存放在数组str中,通过移动指针和计数,就可以得到字符串的长度。程序如下:


  1.         #include <stdio.h>
  2.         main()
  3.           { int n=0;
  4.             char str[80],*s=str;
  5.             gets(str);
  6.             for (n=0;*(s++);n++);  /*移动指针和计数*/
  7.             printf("The length of string is %d",n);
  8.           }
复制代码


【例6-13】
从给定的字符串"I am a student"中,取出子串"student"。
用一个字符型指针a指向该字符串,然后将指针移动到第8个字符的位置上,如果用"%c"控制,就能输出a所指的字符;如果用"%s"控制,就能输出从第8个字符开始直到字符串末尾的子串。程序如下:


  1.         #include <stdio.h>
  2.         main()
  3.           { char *a="I am a student";
  4.             a=a+7;
  5.             printf("%c",*a);
  6.             printf("%s\n",a);
  7.           }
复制代码


程序运行结果如下:

s
student
【例6-14】
用选择法对给定的10个字符串按从小到大的顺序排序,并按5个一行分2行输出。
定义一个能存放10个字符串的二维字符型数组s[10][80],再定义一个指向s的字符型指针数组ch[10],使其每个元素指向一个字符串,并从键盘输入这些字符串存入字符型数组。在选择排序中,通过指针将每个字符串作为一个整体进行比较,在需要交换时,只交换指针数组元素的指向,并不交换数组中的字符。排序完成后,按指针数组元素的顺序输出各个字符串。


  1.         #include <stdio.h>
  2.         #include <string.h>
  3.         main()
  4.          { static char s[10][80],*ch[10]
  5.            char *temp;
  6.            int i,j,k;
  7.            for(i=0;i<10;i++)
  8.              ch[i]=s[i];   
  9.            for(i=0;i<10;i++)
  10.              gets(s[i]);
  11.            for (i=0;i<9;i++)
  12.              { k=i;
  13.                for (j=i+1;j<10;j++)
  14.                  if (strcmp(ch[k],ch[j])>0)
  15.                     k=j;
  16.                temp=ch[k]; ch[k]=ch[i]; ch[i]=temp;
  17.              }
  18.            for (i=0;i<10;i++)
  19.             { printf("%s",ch[i]);
  20.               if ((i+1)%5==0)
  21.                 printf("\n");
  22.             }
  23.          }
复制代码


【例6-15】
指定10个字符串,顺序从各个字符串中取出第1、第2、…、第10个字符,形成一个新的字符串。
用初始化的方法定义一个字符型指针数组,通过循环顺序取出各字符串对应位置上的字符存入另一个一维字符型数组中。程序如下:


  1. main()
  2.       { char *str[11]={"Icon","saw","memory","array","across","furcate",
  3.        "hypercube","independent","incurvate","indeterminate","indifferent"};
  4.         char s[12];
  5.         int i;
  6.         for(i=0;i<11;i++)
  7.           s[i]=str[i][i];
  8.         s[i]='\0';
  9.         printf("%s\n",s);
  10.       }
复制代码


程序运行结果如下:

Iamastudent
【例6-16】
用二级指针访问二维数组。
如果有如下定义:


  1.        int a[3][4];
  2.        int *p[3],**p;
  3.        p[0]=a[0];p[1]=a[1];p[2]=a[2];
  4.        pp=p;
复制代码


其中,一级指针p是一个指针数组,它的3个元素分别指向二维数组a的对应行;二级指针pp指向一级指针p,即存放p的首地址。因此,若用二级指针pp来表示一级指针各个元素的地址,则有:*pp=p[0],*(pp+1)=p[1],*(pp+2)=p[2]。
若用二级指针来表示数组a的各个元素,则有:**p=a[0][0],**(pp+1)=a[1][0],**(pp+2)=a[2][0],(*(pp+i)+j)=pp[j]=a[j]。于是,可以编制用二级指针访问二维数组的程序如下:


  1.         #include <stdio.h>
  2.         main()
  3.           { static int a[5][4];
  4.             static int *p[5],**pp;
  5.             int i,j;
  6.             p[0]=a[0];p[1]=a[1];p[2]=a[2];p[3]=a[3];p[4]=a[4];
  7.             pp=p;
  8.             for (i=0;i<5;i++)
  9.               for(j=0;j<4;j++)
  10.                 scanf("%d",pp[i]+j);
  11.             for (i=0;i<5;i++)
  12.               { for(j=0;j<4;j++)
  13.                 printf("%5d",*(*(pp+i)+j));
  14.                 printf("\n");
  15.               }
  16.           }
复制代码


【例6-17】
用二级指针访问一维数组。

  1.         #include <stdio.h>
  2.         main()
  3.           { static int a[5]=1,2,3,4,5;
  4.             static int *pa[5]=&a[0],&a[1],&a[2],&a[3],&a[4];
  5.             int **P,i;
  6.             p=pa;
  7.             for (i=0;i<5;i++)
  8.               { printf("%d",**P);
  9.                 p++;
  10.               }
  11.             printf("\n");
  12.           }
复制代码


【例6-18】
编制程序利用动态内存分配存放n个整数的一维数组,n的值在程序运行过程中指定,然后从键盘输入任意n个整数存入该数组中,并计算其各元素的平方和。
先通过scanf()获得n的值,用calloc()申请能存放n个int型数的动态内存。如果申请成功,就得到动态内存的首地址,将该地址存放在指针p中,通过移动指针存入n个整数,再通过移动指针取出各个数并计算它们的平方和。


  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. main()
  4.      { int n,s,i,*p;
  5.        printf("Enter the dimension of array:");
  6.        scanf("%d",&n);
  7.        if((p=(int *)calloc(n,sizeof(int)))==NULL)
  8.         { printf("Not able to allocate memory.\n");
  9.           exit(1);
  10.         }
  11.        printf("enter %d values of array:\n",n);
  12.        for(i=0;i<n;i++)
  13.          scanf("%d",p+i);
  14.        s=0;
  15.        for(i=0;i<n;i++)
  16.           s=s+*(p+i)*(*(p+i));
  17.        printf("%d\n",s);
  18.        free(p);
  19.      }
复制代码


由于动态内存是一个没有名字、只有首地址的连续存储空间,相当于一个无名的一维数组,只能通过指针存取。由于程序申请得到的动态内存的首地址被存放在指针p中,只能通过移动p来存取各个元素。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1314学习网 ( 浙ICP备10214163号 )

GMT+8, 2025-5-3 17:44

Powered by Discuz! X3.4

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表