08、C语言——指针

指针

一、指针的基本用法

  1、指针变量定义

    定义的格式:

        类型名 *指针变量名;

          int *p;

  2、指针变量的引用

    “&”取地址运算符,通过&运算符可以取出普通变量的地址【&内容变量=地址值】

    “*”指针运算符,*可以取出指针变量所指向的普通变量的值,(间接引用普通量)【*地址变量 = 内容值】

    指针变量的特殊意义:*p放在赋值号左边是写操作,如果放在赋值号右边是读操作

  3、注意事项

    1)可以通过赋值使一个指针变量“指向”某一普通变量(指针变量=&普通变量)

    2)在C语言中正确的做法是先让指针变量指向一个确定的存储单元后,再通过该指针变量引用它所指向的存储单元

         int *p;
        *p = 200;
        此操作很危险,指针变量定义且初始化后才可以使用

    3)变量名(普通变量、指针变量)都表示其存储单元内的值

    4)若指针变量p指向变量a,即将变量a的地址赋给了指针变量p

      int a=20,*p=&a;
      A、*p  <=>  a              等价都表示内容值
      B、  p  <=>  &a             等价都表示地址值 
      C、&*p  <=>  &a  <=>  p       等价都表示地址值
      D、*&a  <=>    *p   <=>   a       等价都表示内容值
      E、(*p)++   a++             (*p)++ 表达式的值是*p的内容,此时p指针后移
        (*p)--   a--
         ++(*p)  ++a   ++*p         ++(*p)表达式的值是*p的内容加1,同时p指针后移
         --(*p)  --a    --*p

    5)所有的指针变量在内存中分配的字节数相同

    6)指针变量必须定义且初始化之后才可以使用

    7)指针变量专门用存地址,禁止将一个整型值直接赋给一个指针变量

    8)若数组做为形参,则将数组名做指针变量来处理

        int fun(int a[10]) <=> int fun(int *a) = int fun(int a[])

二、指向数组的指针变量

  1、指向数组元素的指针变量

    int a[10], *p;
    p=&a[1];

  2、指向一维数组的指针变量

    int a[10];
    int *p;
    p=a;

  3、注意事项

    1)在c语言中规定:数组名代表数组的首地址,而且是一个地址常量

    2)当指针变量指向数组中的某一个元素时,指针变量加1后指向数组的下一个元素,指针变量减1时指向数组中前一个元素

    3)当指针变量指向数组时,下标运算([])用于数组也可用于指针变量后

      int a[N],*p=a;
          p+i     <=>     a+i    <=>     &a[i]
        *(p+i)    <=> *(a+i)    <=>    a[i]    <=>    p[i]
         p++、 ++p    <=>     p+=1、 p=p+1
         p-- 、--p <=> p-=1 、p=p-1          *p++ <=> *(p++) 先标地址,取旧地址内容值,地址向下加          *++p <=> *(++p) 先把地址向下加1,把移动后的内容值取出来          (*p)++; ++(*p) <=> ++*p      指针没有移动,但是指针所指的内容值加1          (*p)--;--(*p) <=> --*p

   4)若两个指针变量指向同一个数组,则这两个指针变量可以进行大小比较

   5)在形参中的数组实际上是一个指针变量,并不是真正的数组,因为该“数组名”的值是可以改变的,而真正的数组名的值是不能改变的

   6)若形参是数组或指针变量,则在函数中可以通过该形参改变实参的值


三、指向多维数组的指针变量

  1、指向多维数组元素的指针变量

      int a[10][10];
      int *p;
      p=a;

  2、指向由m个元素组成的一维数组的指针变量

    定义格式:

      类型名 (*指针变量名)[m];

        int (*p)[m];

  3、多维数组元素的两种指针变量的定义格式

   

        int *p;        列指针变量
        int (*p)[m];    行指针变量

  4、注意事项 

    1)只有列指针才是“真正”指向元素,即指向某一个元素的存储单元

    2)一维数组名表示的是列指针,二维数组名表示的行指针 

    3)注:若a是一个二维数组,则有:

       a+i是行指针,即指向的是一整行,若对它加1则指向下一行
       *(a+i)和a[i]一样,都是一个列指针即指向的是一个元素
       *(a+i)+j和a[i]+j一样,都表示元素a[i][j]的地址,即与&a[i][j]等价。
       *(*(a+i)+j)、*(a[i]+j)、(*(a+i))[j]和a[i][j]一样,都表示元素a[i][j]

    4)注:

      int w[2][3]
      *(w+1)[2]是元素,先计算[]后计算(),而[]是施加在()上
      *(w+1)[2]表示的元素的值是w[3][0]


四、指向字符串的指针变量

  字符串常量——C语言对字符常量是按首地址处理字符串常量

    char str[]="abcd"    <=>   char str[]={"abcd"}
    char *p="abcd" ,不等价char *p={"abcd"}
    str="abcd"    不合法,常量不能放于赋值号左边
    p="abcd"     合法

  


五、指向函数的指针变量

  1、定义格式:

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

  2、注意事项:

    1)在定义指向函数的指针变量时,要注意有两个小括号必须要有,不需要定义形参

    2)单独的函数名代表该函数的首地址(函数的入口地址)

    3)函数的指针变量只能指向函数的入口处(函数的首地址)

    4)给指向函数的指针变量赋值时,只写函数名即可,不必写参数

六、返回指针的函数

  定义格式:

    类型名 *函数名(形参列表)
    {

    };

七、指针数组

  指针数组——一个数组的所有元素均为指针类型(地址)

  定义格式:

    类型名 *数组名[常量表达式];

      int *p[M];

  注意:

    1)要注意它和定义指向由m个元素组成的一维数组的指针变量之间的区别

      类型名 *数组名[常量表达式];

        int *p[M]; 

      类型名 (*指针名)[常量表达式m];

        int (*P)[M];

    2)它的每个元素都是一个指针类型(地址),即它的每个元素都相当于一个指针变量

 代码实现的过程:

/*
	2017年6月30日19:25:12
	功能:指针函数和指向函数的指针
*/
int add(int x, int y)
{
 return x+y;											//return返回调用函数最终的计算结果
}

# include <stdio.h>
int main(void)
{
 int x, y;
 int total1, total2, total3;
 int (*p)(int x, int y);
 printf("Input x & y;");
 scanf("%d%d", &x, &y);
 p = add;											//p指向函数add;
 total1 = add(x, y);
 total2 = (*p)(x, y);								// *p必须带()否则会出错;
 total3 = p(x, y);									//p指向函数add;
 printf("1. %d + %d = %d
", x, y, total1);
 printf("2. %d + %d = %d
", x, y, total2);
 printf("3. %d + %d = %d
", x, y, total3);

return 0;
}

/*
总结:
  1.定义函数指针之后,必须首先将一函数名(代表该函数的入口地址)赋给函数指针,然后才能通过函数指针间接调用这个函数。
    函数指针变量名  = 函数名;
    在C语言中,函数名本身就是指向该函数的指针,因此可以用来函数指针进行赋值。函数名虽然是指针,但它是指针常量而不是指针变量,因而不能改变它的值。
  2.在利用函数指针来间接调用其所指向的函数时,该函数的定义必须存在,否则将出现错误。
  3.一个函数指针既可以指向用户自定义的函数,也可以指向C语言的标准函数。

	在VC++6.0中显示的结果:
	----------------------
	Input x & y;11 11
	1. 11 + 11 = 22
	2. 11 + 11 = 22
	3. 11 + 11 = 22
	----------------------
注意:
	1、C语言中, 函数名本身就代表着该函数的入口地址。通过这个入口地址可以找到该 函数,该入口地址称为函数的指针。我们可以定义一个指针变量,使它的值等于函数的入口地址, 那么通过这个指针变量也可以调用此函数,这个指针变量称为指向函数的指针,简称为函数指针。
	2、定义形式如下:
	   数据类型 (*函数指针名) (形参);

	3、指针函数与指向函数的指针是两个完全不同的概念,前者是函数,后者是指针,但是,指针函数的原型与函数指针的定义在格式却很相似,仅差一对圆括号。
	   例如:
		int (*fun) (int x, int y);
		fun是一个指向函数的指针变量,所指函数返回值的类型为int类型,所指函数有两个整型参数。*fun两侧的圆括号不能省略,fun先与“*”结合,表明fun是指针变量;(*fun)后面的(int x, int y),表明指针fun指向函数,所指函数有两个整型参数。(*fun)前面的int,表明fun所指函数的返回值的类型为int类型。
		int *fun(int x, int y);
		fun是一个指针函数,该函数返回值的类型为“int *”类型,该函数有两个整型参数。fun先与其后的(int x, int y)结合,表明fun是一个函数,该函数有两个整型参数;fun前面的“int *”,表明函数fun的返回值是int类型的指针。	
*/

  

八、指向指针的指针变量

  指向指针的指针变量——用来存放指针变量地址的指针变量

  定义格式:

     类型名 **指针变量名;

     int **p;

  

九、空指针

  指针变量可以有空值,即指针变量不指向任何变量,不指向任何有用的存储单【在系统中已将null定义为0,即null的值为0】

    int *p=null;
    此时p的值为空指针,即p不指向任何有用的存储单元,尽管null的值为0。
    但我们不能认为p指向了地址为0的存储单元。

十、小总结

  1、c语言有两种变量:

        变量(普通变量)存储内容值,常量都是内容值,只能存放在普通变量中;

        地址变量(指针变量)存储地址值;

   2、*的三种用法:

      乘法运算符

      定义指针变量的标志

      指针运算符

   3、三种运算符之间的关系   

      &与*互逆

      *与[]等价

      &与[]互逆

代码分析解释:

1、由于指针所指向的内容是地址, 所以指针的运算实际上是地址的运算。指针有它自己特有的运算规律,与一般的整数是有区别的。
2、间接存取运算:
				& 取地址运算符  * 取值运算符
3、二者可以看作一对互逆运算符。在指针定义的时候“表示”“指向”, 在使用指针运算的时候,“*”表示取该指针变量所指向变量的值。
	例如:
	int n =2, * p;
	p = &n;
	&(*p) 等效于p, (因为p = &n,则*p = n, 则&(*p) = )其结果为(*p)的地址,即n的地址;
	*(&n)等于n, 即地址(&n)所存放的值, 其结果就是2。
 
4、在进行指针运算时,要注意p = &n 与 *p = n 这两个表达式的区别:
	p = &n :是把变量n的地址赋给指针变量p,从而使p指向n,这时*p和n取值相同。
	*p  = n :是将变量n的值赋给p当前所指向的变量。(因p指向变量n,实际上就是将变量n的值赋给其自身,如*p=3 是将3赋给n)
	所以应严格区分p、 *p、和&p三者的区别:
	p:是指针变量,其内容是地址量。
	*p:是指针变量所指向的变量,其内容是变量的值。
	&p:是指针变量本身所占据的存储地址。

  

   4、二维数组的关系图 

 

      5、指针类型的几种定义

      类型名 (*指针变量名)();  ——定义指向函数的指针变量

      类型名 普通变量名;        ——定义普通变量

      类型名 数组名[];        ——定义数组变量

      类型名 *指针变量名;       ——定义指针变量

      类型名 函数名()        ——定义用户自定义函数
      {....}

      类型名(*指针变量名)[M];     ——定义行指针变量

 指针的一些含义:

# include <stdio.h>

void main(void)
{
	 int n = 5, * p;
	 p = &n;
	 printf("%d
", &n);
	 printf("%d
", p);     //p = &n;
	 printf("%d
", &(*p)); //p = &n,则*p = n,即&(*p) = &n;
	 printf("%d
", *(&p)); //【个人理解:&p表示指针变量p的地址,则*(&p)=p】
	/* 以上四个表达式输出的是同样的值,都是n的地址值 */

	 printf("%d
", &p);// &p表示指针变量p的地址;
	/* 该表达式输出的是p变量的地址值 */

	 printf("%d
", n);
	 printf("%d
", *p); // *p = n;
	 printf("%d
", *(&n)); *(&n) = n;
	/* 以上三个表达式输出的是同样的值:5 */
}

  

原文地址:https://www.cnblogs.com/wxt19941024/p/6939567.html