10-指针(二)-c语言初学系列

指针(二)

返回指针值的函数

指向函数的指针

指针数组

指针与多维数组

指向指针的指针

命令行参数

返回指针值的函数

返回值为指针型数据的函数,定义的一般形式为:

        类型名  * 函数名(参数表);

例如:

             int  *func(int x , int y);

表示函数func的返回值为指向int型数据的指针。

定义注意事项:

函数名前的*只表示范围值为指针型数据

*func两侧没有括号。

程序L11_1.C功能:求两个数中较大的数。

#include <stdio.h>
int *max(int *x , int *y)
{ int *q; 
    if (*x>*y)   q=x;
    else    q=y;
    return q; }
void main()
{ int a,b,*p;
    scanf(“%d,%d”,&a,&b);
    p=max(&a,&b);
printf(“%d,%d,max is %d\n”,a,b,*p);}

举一反三 :使用返回指针值的方法,修改例8.5的函数,使string_copy(char *str1 , char *str2 )的返回值为字符串str1的首地址

指向函数的指针

函数作为一段程序,在内存中也要占据一片存储区域,它有一个起始地址,即函数的入口地址,这个地址就称为函数的指针。

可以定义一个指针变量指向函数,然后通过指针调用函数。

指向函数的指针变量定义的一般形式为:

        类型名   (* 指针变量名)();

例如:

           int  (*p)( ) 

表示p是一个指向函数的指针变量,此函数的返回值为int型。注意,*p两侧的括号不能省略。

定义指向函数的指针变量后,就可以令它等于函数的入口地址。

C语言规定函数名就是函数的入口地址。所以当指向函数的指针变量等于一个函数名时,表示该指针变量指向函数。此时可以通过指向函数的指针变量调用该函数。

   (*指针变量名)(实参表)

指向函数的指针变量主要由两个用途:

调用函数

将函数作为参数在函数间传递。

程序L11_2.C功能:求两个数中较大的数。
#include <stdio.h>
int max(x,y)
int x,y;
{ int z;
   if (x>y)   z=x;
   else    z=y;
   return z; }
void main()
{ int a,b,c;
   int (*p)(int,int );
   p=max; 
   scanf(“%d,%d”,&a,&b);
   c=(*p)(a,b);
   printf(“%d,%d,max is %d\n”,a,b,c); }

比较例11.1和例11.2,我们发现指向函数的指针的定义int (*p)( )和返回指针的函数的定义int *max()非常相似,使用时要特别注意区分。

此外,指向函数的指针变量在使用时要注意:由于这类指针变量等于一个函数的入口地址,所以它们作加减运算是无意义的。

指 针 数 组

C语言规定如果一个数组的元素都是指针类型,则称之为指针数组。指针数组定义的形式为:

              类型名  *数组名[常量表达式];
例如:        int  *a[5] ;

表示指针数组a的每个元素都是指向int型变量的指针变量。

指针数组的主要用于管理同种类型的指针,其中最常用在处理若干个字符串(如二维字符数组)的操作。使用指针数组处理字符串时方便、简洁、效率高。

程序L11_3.C:将多个字符串按字母顺序输出。
void sort(char *str[] , int n)
{ char *temp;    int  i, j , k;
    for (i=0;i<n-1;i++)
       {  k=i;
           for (j=i+1;j<n;j++)
                if (strcmp(str[k] , str[j])>0)
                     k=j;
           if (k != i)
             { temp=str[i]; str[i]=str[k]; str[k]=temp;  }
        }  }
void main()
{int  i , n=4;     char *string[4]={“FORTRAN”,”PASCAL”,”BASIC”,”C”}; 
  sort(string , n);
  for (i=0;i<n;i++)
         printf(“%s\n” , string[i]);  }

可见,两个字符串互换时,只要交换数组中指向这两个字符串的指针即可

使用二维字符数组存放字符串时,数组的列数不小于最长字符串的字符数,所有字符串均占用元素个数相同的一维数组。而使用指针数组处理字符串时,字符串长度可以不等,大大节约了内存空间。这是使用指针数组处理字符串的又一个优点。

指针与多维数组

C语言把二维数组看作是一维数组的集合,即二维数组是一个元素为一维数组的特殊一维数组

不带任何下标的二维数组名表示二维数组的起始地址,进行加法操作时则表示作为其元素的一个一维数组(即二维数组一行)的起始地址。

只带一维下标的二维数组名表示作为其元素的一个一维数组(即二维数组一行)的起始地址,对其进行加法操作时表示该一维数组(即二维数组一行)的一个元素的地址。

指向二维数组元素的指针变量

在C语言中指针即是地址,表示结论二的指针变量,即该指针变量等于只带一维下标的二维数组名,它的定义、赋值、引用与指向一维数组元素的指针变量形式相同

      int a[2][3],*p;
      p=a[0];  

此时p指向一维数组a[0]的起始地址,即p、a[0]、&a[0][0]相同。对其进行加法操作时p+1等同于a[0]+1,都指向数组元素a[0][1]。所以*(p+1)等于元素a[0][1]的值。

程序L11_5.C功能:已知二维数组a[2][3],输入输出全部元素。
#include <stdio.h>
void main()
{ int a[2][3],i,j;
   int *p;
/* 用坐标法输入二维数组元素 */
  for(i=0;i<2;i++)  
      for(j=0;j<3;j++)
         scanf(“%d”,&a[i][j]);
/* 用指针法输出二维数组元素 */
p=a[0];             /* 等价于p=&a[0][0]; */
for(;p<=a[0]+5;p++) printf(“%4d”,*p); 
/* p<=&a[1][2]等价于p<=a[0]+5 */     }

程序的输入语句使用的是坐标法表示二维数组元素,输出语句使用的是指针法表示二维数组元素,效果相同,但是坐标法使用了双层循环语句嵌套,所以指针法更为方便。

由此可见,任何一个二维数组a[m][n]的元素a[i][j]的地址,都可以用a[0]+i*n+j来表示。大多数浮点型的多维数组都采用此种方法处理。此外由于这种方法无需知道数组的行数和列数,只要根据数组的元素总数即可进行数组的数据处理。所以它的通用性更好。

指向二维数组中一维数组的指针变量

C 语言规定一种指针变量可以指向作为二维数组元素的一个一维数组(即二维数组的一行),对这种指针变量进行加减操作则指针将在二维数组中的行上移动

类型符 (*指针变量名)[指向的一维数组元素的个数]

那么对于一个由2行3列组成的二维数组a[2][3],如果指针变量p指向这个二维数组中包含3个元素的第一行一维数组,则指针变量p的定义和赋值形式如下:

int a[2][3], (*p)[3];
p=a;

此时p指向二维数组a的起始地址。对其进行加法操作时p+1等同于a+1,指向包含3个元素的一维数组a[1]。所以*(p+1)等于一维数组名a[1],*(p+1)+1等于a[1]+1,所以*(*(p+1)+1)等于a[1][1]。

程序L11_6.C功能:比较指向数组元素的指针变量和指向数组的指针变量的不同。
void main()
{ int a[2][3]={1,2,3,4,5,6};
  int *p1,(*p2)[3]; 
 /* p1指向数组元素,p2指向包含3个元素的一维数组 */
  p1=a[0]; p2=a; 
/* 用指向数组元素的指针变量输出二维数组元素 */
  for(;p1<a[0]+6;p1++)  
      printf(“%4d”,*p1);
 printf(“\n”);
/* 用指向一维数组的指针变量输出二维数组元素 */
for(;p2<a+2;p2++)  
    printf(“%4d”,*(*p2));
printf(“\n”);  }

二维数组a[m][n]的元素a[i][j]的地址,用指向包含n个元素的一维数组的指针变量p表示形式为:*(p+i)+j,即*(*(p+i)+j)等于a[i][j]的值。

指向数组的指针变量在使用时,要注意与元素是指针类型的指针数组的区别。例如:

int (*q)[3],*p[3];

q是指向一个包含3个整型元素的一维数组的指针变量,p是一个由p[0]、p[1]、p[2]共3个指向整型数据的指针组成的一维数组。

指向指针的指针

指针也是变量,因此它也有自己的地址,而该地址又可以赋给另一个指针变量,这另一个指针变量就称为指向指针的指针。

变量的“间接引用”方式又分两种情况:如果在一个指针变量中存放的是一个目标变量的地址,就称为“单级间址”。如果在一个指针变量中存放的是指向目标变量的地址的指针变量的地址,就称“二级间址”。

指向指针的指针

指向指针的指针属于“二级间址”,它定义的一般形式为:

        类型名   ** 指针变量名;
例如:      int  **p;

表示p是一个指向int型指针变量的指针。

程序L11_6.C功能:使用指向指针的指针
#include <stdio.h>
 void main()
 { int a=3;
   int *p1,**p2;
   p1=&a;
   p2=&p1;
   printf("%d\n",*p1);
   printf("%d\n",**p2);}

程序L11_6.C功能:使用指向指针的指针
#include <stdio.h>
 void main()
 { static char *str[]={"How","are","you"};
   char **p;
   p=str+1; 
   printf("%s\n",*p);
   printf("%c\n",**p);}

命令行参数

用C语言编写一个程序,编译链接后将生成一个可执行文件。这个可执行文件可以在操作系统状态下作为外部命令执行。

C语言允许main函数带两个参数。

带参数的main函数的一般形式为:

    main(int argc,char *argv[ ])
   {   …… }

其中,参数argc为整型,是命令行中参数的个数,命令名也作为一个参数。argv为指向字符串的指针数组,它的元素依次指向命令行中的各个字符串,包括命令名。

程序L11_8.C功能:命令行参数演示
#include <stdio.h>
void main(int argc,char *argv[ ])
{ int i;
    printf("argc=%d\n",argc);
    for(i=1;i<argc;i++)
          printf("%s  ",argv[i]);
    printf("\n");}
运行结果 : 
输入的命令行       L11_8   Beijing  China
则输出为              argc=3
   Beijing  China

argc和argv是习惯上使用的main函数的形参名,实际上,这两个参数可由用户自己命名,但它们的类型是固定的。

 /*-----------------------------------------
   程序L11_9.C:编写一个书名查询函数
   void search(char *bk_list[],char *bk_name,int n)
 -------------------------------------------*/
 #include <stdio.h>
 #include <string.h>
 int string_in(char *str1,char *str2)
 {
  int m=0;
  char *p,*q;
  for (;*str1!='\0';str1++)
     if (*str1==*str2)
{ for(p=str1,q=str2;*q!='\0';p++,q++)
     if (*p!=*q) break;
  if (*q=='\0')
     {m=1;break;}
  }
  return m;
  }
 void search(char *bk_list[],char *bk_name,int n)
 {
  int i;
  for(i=0;i<n;i++)
     if (string_in(bk_list[i],bk_name))
          printf("%s\n",bk_list[i]);
 }
 void main()
 {
  char *books[6]={"边用边学C语言","计算机文化基础","高等数学","C程序设计","Linux基础教程","精讲多练C语言"};
  char name[30];
  gets(name);
  search(books,name,6);
 }

/*---------------------------------------------
  程序L11_10.C功能:输入学生序号后,输出该学生的全部成绩。
 ----------------------------------------------*/
 #include <stdio.h> 
 float *search(float (*p)[4], int n )
 {
  float *pt;
  pt=*(p+n);
  return pt;
 }
  void main()
 {
   static float score[ ][4]={{62,70.5,87,77},{57,89,65,83},{72,78,60,91}};
   float *p;
   int i,m;
   printf("Enter the number of student:");
   scanf("%d",&m);
   printf("The scores of No.%d are:\n",m);
   p=search(score,m);
   for(i=0;i<4;i++) 
      printf("%5.2f\t",*(p+i));
  }

练习

1 修改函数string_cut(char *string,char c),要求返回值为字符串的地址。

编写并验证去掉字符串中前导空格的函数char *head_cls(char *str)。

2 修改例11.9,已知学生库char *name[6] = {“Join”, ”Mary”,”Lily”,”Bob”,”Williams”,”White”};要求根据输入学生姓名查找该学生是第几个。

3 利用main函数可以读取命令行参数,建立文件like.c。当命令行有2个参数时,例如like football ,输出Do you like football? 当命令行有3个参数时,例如like football basketball 时,输出Do you like football or basketball? 当命令行有4个以上参数时,例如like C Vb Foxpro Java 时输出Do you like C,Vb,Foxpro or Java?

ps: 对应ppt模板下载地址如下:

10-指针(二)-自己使用的C语言教程PPT-适合老师备课或者自学.pptx-C文档类资源-CSDN下载


 

 全部课程的PPT已经整理好了,需要的童鞋可以点击下载
总-自己使用的C语言教程PPT-适合老师备课或者自学-15篇PPT合集.zip-C文档类资源-CSDN下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锁住子锁不住

老少爷们向前冲!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值