C语言指针

主要内容

  1. 地址和指针
  2. 变量的指针和指向变量的指针变量
  3. 数组的指针和指向数组的指针变量
  4. 字符串的指针和指向字符串的指针变量
  5. 函数的指针和指向函数的指针变量★
  6. 返回指针值的函数
  7. 指针数组和指向指针的指针

地址和指针

  1. 在计算机中所有数据都存放在存储器中。
  2. 主存储器中的一个字节称为一个内存单元,通过内存单元的编号能正确地访问内存单元,内存单元的编号也称为地址
  3. 指针:通常内存单元的地址称为指针
  4. 内存单元存放的数据是存储单元的内容 

变量的指针和指向变量的指针变量

  1. 在C语言中,一种数据类型或数据结构往往占有一组连续的内存单元
  2. 指针是一个数据结构的首地址,它“指向”一个数据结构
  3. 允许用一个变量来存放指针,这种变量称为指针变量
  4. 指针变量的值就是某个数据结构的地址(指针)
  5. 指针是一个地址,是常量
  6. 指针变量可以存放不同的指针值,是变量
  7. 变量的指针就是变量的地址,存放某变量地址的变量称为指向某变量的指针变量
  8. 在程序中用“*”符号表示“指向”。  
  9. 如果已定义i_pointer为指针变量,
  10. 则*i_pointeri_pointer所指向的变量
             

int i; i=3;

*i_pointer=3;  //都可以给i赋值

定义指针变量

  1. 定义指针变量的一般形式为:              类型说明符  *指针变量名;
  2. 例如:
int *p1;      //p1 是指向整型变量的指针变量
float *p2;    //p2 是指向浮点型变量的指针变量
char *p3;    //p3 是指向字符型变量的指针变量

指针变量的引用

两个与指针使用有关的运算符:
1 &:取地址运算符。
例如, &a 取得变量 a 的地址。
2 )*:指针运算符(或称“间接访问”运算符)取得指针变量指向的内容。
例如 *p取得指针变量p所指向的变量的值。
给指针变量赋值可以有两种方法:
1 )定义的同时赋值,如:
      int a;       
      int *p=&a;   // 定义时初始化,取得 a 的地址赋给指针变量 p
2 )定义后赋值,如:
      int a;
      int *p;
      p=&a;   // 取得变量 a 的地址赋给指针变量 p
指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量

以下的赋值是不合法的:

    int *p;

    p=100;   // p为指针变量,100为整数,不合法  

//【例10. 1】指针变量的使用。
1    #include <stdio.h>
2    void main()
3    {   int a,b;
4        int *pointer_1, *pointer_2;    //定义指针变量
5        a=100;b=10;
6        pointer_1=&a;   //指针变量pointer_1指向a
7        pointer_2=&b;  //指针变量pointer_2指向b
8        printf("%d,%d\n",a,b);
  printf("%d,%d\n",*pointer_1, *pointer_2);    
  //通过指针变量取得变量的值
10    }

                           

如果已执行了语句“ pointer_1=&a ;”,那么有以下说法:
1 pointer_1 等价于  &a
2 )* &a 等价于  *pointer_1  等价于  a
3 &*pointer_1 等价于  &(*pointer_1) 等价于  pointer_1 等价于  &a
“&”和“*”运算符的优先级相同,它们按自右至左结合
4 (*pointer_1)++ 等价于  a++
5 )* pointer_1++ 等价于  *(pointer_1++)
因为“ ++” 和“ *” 为同一优先级,而结合方向为自右至左
//【例10. 2】输入整数a和b,按从大到小的顺序输出a和b。
#include <stdio.h>
void main()
{    int *p1,*p2,*p,a,b;
    printf("请输入两个整数:");
    scanf("%d,%d",&a,&b);
    p1=&a;p2=&b;  //指针变量指向变量
    if(a<b)
    {    p=p1;p1=p2;p2=p;} 
//指针变量交换指向
    printf("%d,%d\n",a, b);
    printf("%d,%d\n",*p1, *p2);
} 

               

指针变量作为函数参数

  1. 函数的参数也可以是指针
  2. 它的作用是将一个变量的地址传送到函数中
//【例10. 3】编写用指针变量作参数的函数,将输入的两个整数按从大到小顺序输出
#include <stdio.h>
void swap(int *p1,int *p2)  //指针变量作形参
{    int temp;
    temp=*p1;   //交换p1和p2指向的变量的值
    *p1=*p2;    *p2=temp;
}
void main()
{    int a,b;
    int *pointer_1,*pointer_2;
    printf("请输入两个整数:");
    scanf("%d,%d",&a,&b);
    pointer_1=&a;pointer_2=&b;
    if(a<b) 
        swap(pointer_1,pointer_2);  //指针变量作实参,也可以使用swap(&a,&b);
    printf("%d,%d\n",a,b);
}

//【例10. 4】改变形参指针变量的指向,而实参变量不变。
#include <stdio.h>
void swap(int *p1,int *p2)
{  int *p;
    p=p1;   //改变形参指针变量的指向
    p1=p2;    p2=p;
}
void main()
{    int a,b;
    int *pointer_1,*pointer_2;
    printf("请输入两个整数:");
    scanf("%d,%d",&a,&b);
    pointer_1=&a;pointer_2=&b;
    if(a<b) 
        swap(pointer_1,pointer_2);  //指针变量作实参
    printf("%d,%d\n",*pointer_1,*pointer_2);  //实参指针变量的指向不变
}

swap函数中交换形参p1p2的值,不能交换实参pointer_1pointer_2的值

//【例10. 5】指针变量作参数可以返回多个变化的值。
#include <stdio.h>
void swap(int *p1,int *p2)
{    *p1=100;   //改变形参指针变量的指向
    *p2=200;
}
void main()
{    int a,b;
    int *pointer_1,*pointer_2;
    printf("请输入两个整数:");
    scanf("%d,%d",&a,&b);
    pointer_1=&a;pointer_2=&b;
    if(a<b) 
        swap(pointer_1,pointer_2);  //指针变量作实参,也可以使用swap(&a,&b);
    printf("%d,%d\n",a,b);
}

函数的调用只能得到一个返回值(函数值)

而用指针变量作参数可以返回多个结果

数组的指针和指向数组的指针变量

  1. 数组的指针就是指数组的首地址,数组元素的指针是指数组元素的地址。
  2. 定义一个指向数组元素的指针变量的方法,与定义指针变量的方法相同 

int a[10]//定义a为包含10个整型元素的数组

int *p;   //定义p为指向整型变量的指针

p=&a[0];  //p指向数组的第0个元素a[0]

   

数组的指针

  1. C语言规定,数组名代表数组的首地址,也就是第0号元素的地址

p=&a[0] ; 等价于   p=a ;

int *p=&a[0] ;     等价于    int *p=a;   等价于  int *p; p=&a[0];

通过指针引用数组元素

  1. 如果指针变量p已指向数组中的一个元素,则p+1指向同一数组的下一个元素
  2. 如果p的初值为&a[0],那么:

1p+i 等价于 a+i 等价于 &a[i]

2)*(p+i) 等价于 *(a+i) 等价于 a[i]

         如,*(p+5) 等价于 *(a+5) 等价于 a[5]

3)指向数组的指针变量也可带下标

         p[i] 等价于 *(p+i) 等价于 a[i] 等价于 *(a+i)

4p++ 等价于 p=p+1

        使得指针变量p指向数组的下一个元素  

如果 p=a ,引用数组元素可以有两种方法:
1 下标法 ,采用 a[i] p[i] 的形式访问数组元素
2 指针法 ,采用 *(a+i)或*(p+i)形式 ,用指针方法访问数组元素。
//【例10. 6】输出数组的全部元素。
(1)使用下标法引用数组元素:
#include <stdio.h>
void main()
{  int a[10],i;
   for(i=0;i<10;i++)
     a[i]=i;  //下标法引用数组元素
   for(i=0;i<10;i++)
     printf("%4d",a[i]);  //下标法引用数组元素
   printf("\n");
}

2)使用指针法,利用数组名计算地址引用数组元素,编写程序如下:

#include <stdio.h>

void main()

{    int a[10],i;

    for(i=0;i<10;i++)

        *(a+i)=i;   //指针法,利用数组名引用数组元素

    for(i=0;i<10;i++)

        printf("%4d",*(a+i));  //指针法,利用数组名引用数组元素

    printf("\n");

}

(3)使用指针变量指向数组元素,编写程序如下:

#include <stdio.h>

void main()

{    int a[10],i,*p;

    p=a;

    for(i=0;i<10;i++)

        *(p+i)=i;  //指针变量取得数组元素

    for(i=0;i<10;i++)

        printf("%4d",*(p+i));  //指针变量取得数组元素

    printf("\n");

}
1 )指针变量中的值可以改变。

       p++  等价于  p=p+1 //使得指针变量指向下一个数组元素

(2) a 是数组名,它是数组的首地址,是常量

       a++   //错误

通过指针引用数组

【例10. 7】输入并输出数组的全部元素。

编写程序如下

#include <stdio.h>

void main()

{    int *p,i,a[10];

    p=a;

    printf("请输入10个元素:");

    for(i=0;i<10;i++)

        scanf("%d",p++);

    for(i=0;i<10;i++)

      printf("%4d",*p++);

    printf("\n");

}

第一个循环结束后,指针变量p指到数组以后的内存单元,系统并不认为非法。

第二个循环输出的数据为数组以后的内存中的数据。因此为乱码

程序修改如下:

#include <stdio.h>

void main()

{    int *p,i,a[10];

    p=a;

    printf("请输入10个元素:");

    for(i=0;i<10;i++)

        scanf("%d",p++);

    p=a;   //p重新指向a[0]

    for(i=0;i<10;i++)

      printf("%4d",*p++);

    printf("\n");

}

说明:

1)*p++ 等价于 *(p++)

        由于++和*同优先级,结合方向自右而左。

        先取得*p的值,后使得p指向下一个元素。

2)*++p 等价于 *(++p)

        先使得p指向下一个元素,后取得*p的值。

3(*p)++    表示p所指向的元素值加1

4)若p的初值为a,那么:

          *(p++) 等价于 a[0]

          *(++p) 等价于 a[1]

          (*p)++ 等价于 a[0]++

5)若p指向a数组中的第i个元素,那么:

          *(p--) 等价于 a[i--]

          *(++p) 等价于 a[++i]

          *(--p) 等价于 a[--i]

数组作函数参数

数组名可以作为函数的实参和形参
void main()

{    int array[10];

    ……

    ……

    f(array,10);  //数组名作为函数的实参

    ……

}

void f(int arr[],int n)  //数组作为函数形参

{    ……

}

1)将实参数组array的首地址传递给形参数组arr ,形参数组和实参数组共用同一段内存

2)数组形式:

     void f(int arr[],int n)

在编译时也将arr按指针变量处理,相当于:

     void f(int *arr,int n)

数组的指针变量作函数参数

数组指针变量也可以作为函数的参数使用

10. 8】将数组a中的n个整数按相反顺序存放。

分析:

(1)a[0]a[n-1]交换,a[1]a[n-2]交换,直到a[(n-1/2)]a[n-int((n-1)/2)]交换

(2)设变量iji的初值为0j的初值为n-1

(3)a[i]a[j]交换,然后使i的值加1j的值减1,再将a[i]a[j]交换,直到i≥j

#include <stdio.h>

//数组x作为函数的形参

void inv(int x[],int n)

{    int temp,i,j=n-1;

    for(i=0;i<j;i++,j--)

    {    temp=x[i];

         x[i]=x[j];

         x[j]=temp;

    }  //交换对应元素

}

void main()

{    int i,a[10]={3,7,9,11,0,6,7,5,4,2};

    printf("The original array:\n");

    for(i=0;i<10;i++)

        printf("%4d",a[i]);

    printf("\n");

    inv(a,10);        //数组名作为函数的实参

    printf("The array has benn inverted:\n");

    for(i=0;i<10;i++)

        printf("%4d",a[i]);

    printf("\n");

}

用数组作为函数的形参和实参

#include <stdio.h>

 //指针变量x作为函数的形参

void inv(int *x,int n)

{    int temp,*i,*j;

    i=x;   j=x+n-1;

    for(;i<j;i++,j--)

    {    temp=*i;

         *i=*j;

         *j=temp;

    }    //交换对应元素

}

void main()

{    int i,a[10]={3,7,9,11,0,6,7,5,4,2};

    printf("The original array:\n");

    for(i=0;i<10;i++)

        printf("%4d",a[i]);

    printf("\n");

    inv(a,10);    //数组名作为函数的实参

    printf("The array has benn inverted:\n");

    for(i=0;i<10;i++)

        printf("%4d",a[i]);

    printf("\n");

}

用指针变量作为函数的形参,数组名作为函数调用的实参

实参与形参对应关系的四种形式

实参为指针变量

#include <stdio.h>

//实参是指针变量,

//采用下标法引用数组元素

void inv(int *x,int n)

{    int temp,i,j=n-1;

    for(i=0;i<j;i++,j--)

    { temp=x[i];x[i]=x[j];x[j]=temp; } 

//交换对应元素

}

void main()

{    int i,arr[10]={3,7,9,11,0,6,7,5,4,2},*p;

    p=arr;

    printf("The original array:\n");

    for(i=0;i<10;i++,p++)

        printf("%4d",*p);

    printf("\n");

    p=arr;    //指针变量指向数组的a[0]

    inv(p,10); 

//指针变量作为实参,也可以写为inv(a,10);

    printf("The array has benn inverted:\n");

    for(p=arr;p<arr+10;p++)

        printf("%4d",*p);

    printf("\n");

}

10. 9】用选择法对10个整数由大到小排序。

#include <stdio.h>

void sort(int *x,int n) 

//也可以写为 void sort(int x[],int n)

{    int i,j,k,t;

    for(i=0;i<n-1;i++)

    {    k=i;

        for(j=i+1;j<n;j++)

            if    (x[j]>x[k])    k=j;

        if(k!=i)

        { t=x[i];x[i]=x[k];x[k]=t;}

    }

}

void main()

{    int *p,i,a[10]={3,7,9,11,0,6,7,5,4,2};

    printf("The original array:\n");

    for(i=0;i<10;i++)

        printf("%4d",a[i]);

    printf("\n");

    p=a;    //指针变量指向数组的a[0]

    sort(p,10);    //指针变量作为函数实参,也可以写为sort(a,10);

    printf("The array has benn sorted:\n");

    for(p=a,i=0;i<10;i++)

    {    printf("%4d",*p);p++;}

    printf("\n");

}

指向多维数组的指针和指针变量

  1. 多维数组元素的地址
  2. 设有整型二维数组定义如下:            int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
  3. 假设数组a的首地址为1000 ,如图。

指向多维数组的指针

  1. 可以把一个二维数组分解为多个一维数组
  2. 分解为三个一维数组,即a[0]a[1]a[2]。每一个一维数组包含有四个元素。
一维数组 a[0] ,包含 a[0][0] a[0][1] a[0][2] a[0][3]

                          

  1. 从二维数组的角度来看:
  2. a是二维数组名,代表整个二维数组的首地址,也就是二维数组第0行的首地址,为1000
  3. a+1代表第一行的首地址,为1016

2a[0]是第0行一维数组的数组名和首地址,值为1000

* (a+0)      等价于      *a        等价于      a[0]  等价于   &a[0][0]

3a+1是二维数组第1行的首地址,其值为1016

a[1] 是第 1 行一维数组的数组名和首地址,其值也为 1016
a[1]      等价于     *(a+1)      等价于       &a[1][0]

4)可得出:

        * (a+i)    等价于     a[i]      等价于      &a[i][0]

5a[0] 等价于 a[0]+0,是一维数组a[0]的第0号元素的首地址

a[0]+1则是a[0]1号元素的首地址,a[0]+2a[0]2号元素的首地址

可以得出:

a[i]+j 是一维数组 a[i] 的第 j 号元素的首地址
a[i]+j  等价于  &a[i][j]

6a[i]  等价于  *(a+i)a[i]+j   等价于  *(a+i)+j

*(a+i)+j是二维数组ai行第j列元素的首地址,

*(*(a+i)+j) 等价于 *(a[i]+j)    等价于   a[i][j]

10. 10】输出二维数组的有关值。

#include <stdio.h>

void main()

{   int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

   printf("%d,%d\n",a, a+1);

   printf("%d,%d,%d,%d\n", a[0], *a, *(a+0), &a[0][0]);

   printf("%d,%d,%d\n", a[1], *(a+1), &a[1][0]);

   printf("%d,%d\n",a[1],*(a+1));

   printf("%d,%d,%d\n", a[1]+0, a[1]+1, a[1]+2);

   printf("%d,%d,%d\n", *(a+1)+0, *(a+1)+1, *(a+1)+2);

   printf("%d,%d,%d\n", *(a[1]+0), *(a[1]+1), *(a[1]+2));

   printf("%d,%d,%d\n", *(*(a+1)+0), *(*(a+1)+1), *(*(a+1)+2));

}

指向多维数组的指针变量

  1. 指向二维数组指针变量定义的一般形式为:
  2. 类型说明符  (*指针变量名)[长度]
  3. 类型说明符:为所指向数组的数据类型
  4. *:表示变量是指针变量
  5. [长度]:表示一维数组的长度,也就是二维数组的列数             –int (*p)[4]
  6. p是一个指针变量,指向包含4个元素的一维数组。

10. 11】利用指向数组的指针变量,按行列方式输出二维数组。

#include <stdio.h>

void main()

{   int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

   int (*p)[4];

   int i,j;

   p=a;   //指针指向而为数组的第0行

   for(i=0;i<3;i++)

   {   for(j=0;j<4;j++)

         printf("%4d",*(*(p+i)+j)); 

//*(*(p+i)+j) 相当于p[i][j],相当于 *(*(a+i)+j),相当于 a[i][j]

      printf("\n");

   }

}

字符串的指针和指针变量

可以用两种方法访问一个字符串 :
(1)用字符数组存放和处理字符串

10. 12】定义并初始化一个字符数组,然后输出字符串。

#include <stdio.h>

void main()

{   char string[]="I love China!";

   printf("%s\n",string);

}

string是数组名,它表示字符数组的首地址

(2)用字符指针指向一个字符串。

 通过定义字符指针变量指向字符串中的字符 

10. 13】定义指向一个字符串的字符指针变量。

#include <stdio.h>

void main()

{  char *string=”I love China!”;

  printf("%s\n",string);

}
  • 在程序中定义了一个字符指针变量string,用字符串常量“I love China!”初始化
  • 实际是把字符串第0个元素的地址赋给指针变量string

char *string=”I love China!”;

指向字符串的指针变量的定义,赋给指针变量地址例如:
         char c,*p=&c;
表示 p 是一个指向字符变量 c 的指针变量

10. 14】输出字符串中第n个字符后的所有字符。

#include <stdio.h>

void main()

{   char *ps="This is a book.";

   int n=10;

   ps=ps+n; //ps指向第n个字符

   printf("%s\n",ps);

}

10. 15】用指针变量的方法,求字符串的长度。

#include <stdio.h>

void main()

{   char *ps,str[100];

   int n;

   printf("Input a string:\n");

   gets(str);

   ps=str;

   while(*ps!='\0')

      ps++;  //指针变量指向下一个字符

   n=ps-str;

   printf("The length is %d \n",n);

}

字符串指针作函数参数

可以用字符数组名或者指向字符串的指针变量作函数参数 , 将字符串的地址从一个函数传递给另一个函数。
在被调用函数中改变字符串的内容,也就改变了主调函数中的字符串

10. 16】用字符串指针作函数参数,实现字符串的复制。

#include <stdio.h>

void cpystr(char *pss,char *pds) //字符指针变量做函数形参

{   while((*pds=*pss)!='\0')

   {   pds++;pss++;   }

}

void main()

{   char *pa="CHINA",b[10],*pb;

   pb=b;

   cpystr(pa,pb);

//字符串指针变量做函数实参,也可以写为cpystr(pa,b)

   printf("string a=%s\nstring b=%s\n",pa,pb);

}

虽然函数参数传递是单向值传递,但是由于传递的指针变量的值(即地址),所以psspa指向同一字符串,pdspb指向同一字符串。

5 )可以把指针的移动和赋值合并在一个语句中, cpystr 函数简化为:
•      void cpystr(char *pss,char *pds)
      {   while((*pds++=*pss++)!='\0');}
6 '\0' ASCⅡ 码值为 0 while 表达式非 0 就循环,为 0 则结束循环,因此也可省略“ != '\0'” 。简化为
•      void cpystr(char *pss,char *pds)
      {   while (*pdss++=*pss++);   }
函数参数可以是字符串数组名,也可以是字符指针变量。有以下几种情况:
①实参和形参均为数组
②实参和形参均为字符指针变量
③实参为数组名,形参为字符指针变量
④实参为字符指针变量,形参为数组

字符指针变量和字符数组的讨论

字符数组和字符指针变量的区别:

1)字符指针变量是变量,用于存放字符串的首地址,而字符串本身是存放在以该地址为首的一块连续内存空间中。

字符数组由若干个数组元素组成的,每个元素中存放一个字符,整个数组可以存放一个字符串,数组名是字符串的首地址,是常量

2 )对字符指针变量赋初值:
•      char *ps="C Language";      // 合法
也可以写为:
•      char *ps;
      ps="C Language";   // 合法
而对字符数组赋初值:
•      char str[20]={"C Language"};   // 合法
不能写为:
•      char str[20];
      str={"C Language"};   // 不合法
因为数组名是一个常量,不能给常量赋值
3 )当一个指针变量在未取得确定地址前使用是很危险的。因为指针变量的默认值指向的内存不一定是本程序的存储空间。随意修改容易引起错误。例如:
•      char *ps;
      scanf("%s", ps);   // 可能引起错误
可以改为:
–     char *ps, str[20];
      ps=str;
      scanf("%s", ps);

函数的指针和指向函数的指针变量★

  1. C语言中,一个函数总是占用一段连续的内存空间,而函数名就是函数所占内存区的首地址
  2. 函数的首地址(或称入口地址)称为函数的指针
  3. 把函数的指针赋予一个指针变量,使该指针变量指向该函数 ,即指向函数的指针变量
  4. 指向函数的指针变量定义的一般形式为:         –类型说明符  (*指针变量名)(函数参数表列);
  5. 类型说明符:表示被指向函数的返回值类型
  6. *:表示后面定义的变量是指针变量
  7. 小括号:表示指针变量所指的是函数。
  8. (*指针变量名)”两边的括号不能少,否则就成了指针函数 
  9. 函数参数表列只写出各个形式参数的类型即可,也可以与函数原型的写法相同。例如                      int (*pf)(int,int);
  10. pf是一个指向返回值类型为int的函数的指针变量,并带有两个int类形参数

用函数指针变量调用函数

  1. 可以通过函数名调用函数,也可以通过函数指针变量调用函数。形式为:                                         (*指针变量名) (实参表)

10. 17】编写函数求两个形参中较大值。用函数指针变量调用函数。

#include <stdio.h>

int max(int x,int y)

{   if(x>y)return x;

   else return y;

}

void main()

{   int a,b,c;

   int (*pmax)(int,int);  //定义指向int类型函数的指针变量pmax

   pmax=max;   //指针变量指向函数max

   printf("Input two numbers:\n");

   scanf("%d,%d",&a,&b);

   c=(*pmax)(a,b);  //通过指针变量调用函数

   printf("max=%d\n",c);

}

用指向函数的指针作函数参数

  1. 函数的参数可以是指向函数的指针
  2. 用指向函数的指针作函数参数,传递的是函数的地址
  3. 若要在每次调用函数时完成不同操作,可以用指向函数的指针作为函数的参数。
  4. 每次调用时,使该指针指向不同的函数即可

10. 18】设一个函数f,在每次调用时可以实现不同功能:第一次调用,求两个数中较大者;第二次调用,求两个数中较小者;第三次调用,求两个数的和。

#include <stdio.h>

int max(int x,int y)  //求最大

{   if(x>y)   return x;

   else   return y;

}

int min(int x,int y)  //求最小

{   if(x<y)   return x;

   else      return y;

}

int sum(int x,int y)  //求最和

{   return x+y;

}

void f(int x,int y,int (*p)(int,int))

{   int result;

   result=(*p)(x,y);   //调用p指向的函数

   printf("%d\n",result);

}

void main()

{   int a,b;

   printf("Input two numbers:\n");

   scanf("%d,%d",&a,&b);

   printf("max=");

   f(a,b,max);  //max函数的入口地址传给形参指针变量

   printf("min=");

   f(a,b,min);  //min函数的入口地址传给形参指针变量

   printf("sum=");

   f(a,b,sum);  //sum函数的入口地址传给形参指针变量

}

返回指针值的函数

  • 一个函数可以返回一个整型值、实型值、字符值等,也可以返回一个指针值(即地址)
  • 返回指针值的函数也称为指针型函数

函数名之前加“*”号表明这是一个指针型函数,即返回值是一个指向类型说明符数据类型的指针

10. 19】输入一个17之间的整数,输出对应的星期名。通过调用指针函数实现。

#include <stdio.h>

char name[8][20]={"Illegal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};

char *day_name(int n)  //函数返回值为指向字符的指针

{   if (n<1||n>7)

      return name[0];      //返回第0行第0列字符的地址

   else

      return name[n];      //返回第n行第0列字符的地址

}

void main()

{   int i;

   char *ps;

   printf("Input Day No:\n");

   scanf("%d",&i);

   ps=day_name(i);  //函数返回值为指向第i行的第0个字符的地址

   printf("%s\n",ps);

}

1)特别注意函数指针变量和指针型函数的区别。int(*p)()”和“int *p()”完全不同  

int (*p)() :是一个变量定义, p 是一个指向返回值为 int 类型的函数的指针变量。
int *p() :是一个函数说明, p 是一个指针型函数,其返回值是一个指向 int 类型数据的指针。

指针数组和指向指针的指针

  1. 指针数组和指向指针的指针变量能够存储另一个指针变量的地址的变量
  2. 指针数组:一个元素都为指针类型的数
  3. 指针数组的每一个元素相当于一个指针变量
类型说明符 *数组名 [ 数组长度 ]
int *pa[3];

指针数组

int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

int *pa[3]={a[0],a[1],a[2]};

10. 20】利用指针数组输出二维数组。

#include <stdio.h>

void main()

{   int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};

   int *pa[3];

   int i,j;

   for(i=0;i<3;i++)

      pa[i]=a[i];  //pa[i]指向一维数组a[i][0]

   for(i=0;i<3;i++)

   {   for(j=0;j<4;j++)

      printf("%4d",*(*(pa+i)+j));  // *(*(pa+i)+j) ó p[i][j] ó a[i][j]

      printf("\n");

   }

}

区别

指针数组和二维数组指针变量的区别
二维数组指针变量是单个变量, int (*p)[3];
p 表示一个指向二维数组的指针变量二维数组的列数为 3
指针数组表示多个指针元素的数组 , int *p[3];
p 表示一个指针数组,三个元素 p[0] p[1] p[2] 均为指针变量。

10. 21】用指针数组改写10. 19】的程序。

#include <stdio.h>

char *day_name(char *name[],int n)  //指针数组作为函数形参

{   char *pa1,*pa2;

   pa1=*name;

   pa2=*(name+n);

   return (n<1||n>7)? pa1:pa2;

}

void main()

{   static char *name[]={"Illegal day", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};   //name数组的每个元素指向一个字符串

   char *ps;

   int i;

   printf("Input Day No:\n");

   scanf("%d",&i);

   ps=day_name(name,i);  //指针数组作函数实参

   printf("%s\n",ps);

}

10. 22】5个国名按字母顺序排列后输出。

#include <stdio.h>

#include <string.h>

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]);

}

void main()

{    static char *name[]={"China","America","France","German","Australia"};

    int n=5;

    sort(name,n);  //调用排序函数

    print(name,n);

}

指向指针的指针

如果一个指针变量存放的是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量,简称为指向指针的指针
定义指向指针的指针变量的一般形式为:
         类型说明符  **指针变量名 ;
** :表示指向指针的指针,
类型说明符:表示指针变量所指的指针变量指向的数据类型。
char **p;
1 char **p;     等价于 char *(*p);
          p 是指向一个字符指针变量的指针变量。
2 )** p ó *(*p)
         *p 取得 p 指向的指针变量
         * (*p) 取得 p 指向的指针变量指向的变量的值。

10. 23】用指向指针的指针输出一维数组。

#include <stdio.h>

void main()

{    int a[5]={1,3,5,7,9};

    int *num[5]={&a[0], &a[1], &a[2], &a[3], &a[4]};

//每个元素是一个指针

    int **p,i;

    p=num;    //p指向num数组的第0个元素

    for(i=0;i<5;i++)

    {    printf("%4d",**p); //**p取得变量的值

        p++;    //p指向num数组的下一个元素

    }

    printf("\n");

}
**p :输出数组 a 中的元素。
   * p ó num[i] ó &a[i]
     ** p ó *&a[i]  ó a[i]

指针数组

10. 24】用指向指针的指针输出若干字符串。

#include <stdio.h>

void main()

{   char *name[]={"Basic","Visual Basic","C","Visual C++","Pascal","Delphi"};

   char **p;

   int i;

   for(i=0;i<6;i++)

   {   p=name+i;  //  p ó &name[i]

      printf("%s\n",*p);   // *p ó name[i]

   }

}

程序也可以改写为:

#include <stdio.h>

void main()

{    char *name[]={"Basic","Visual Basic","C","Visual C++","Pascal","Delphi"};

    char **p;

    int i;

    p=name;  //p指向num数组的第0个元素

    for(i=0;i<6;i++)

    {    printf("%s\n",*p);

        p++;  //p指向name数组的下一个元素

    }

}

指针数组作main函数的形参

  1. main函数一般不带参数
  2. 实际上,main函数也可以带参数(形参)
  3. main只能有两个参数,经常命名为argcargv
argc (第一个)必须是整型变量
argv (第二个)必须是指向字符串的指针数组
  • main函数头可写为:
void main (int argc,char *argv[])
  • main函数是由操作系统调用,所以main函数的参数值从操作系统命令行获得
  • 把实参传送到main函数的形参中。
  • 命令行的一般形式为:
  • 命令名 参数1 参数2 …… 参数n
  • argc:获得命令行中参数的个数
  • argv(指针数组):每一个元素指向命令行中的一个字符串
  • file1 Beijing Tianjin Shanghai Chongqing

10. 25】输出命令行的参数。该程序文件名为eg1025.c

#include <stdio.h>

void main(int argc,char *argv[])

{ while(  argc-->1)

    printf("%s\n",   *++argv);

}

10. 26】编写实现echo命令的程序,文件名为echo.c

许多操作系统提供的echo命令的作用是实现“参数回送”,

echo后面的各参数(字符串)在同一行上输出。

编写程序如下:

#include <stdio.h>

void main(int argc,char *argv[])

{  while(--argc>0)

  printf("%s%c",  *++argv,(argc>1)?' ':'\n');

}
  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值