C语言学习笔记(十)--指针

来源:岁月联盟 编辑:猪蛋儿 时间:2011-11-21

1变量指针

 

变量的指针就是指向变量的地址,专门用来存放变量地址的变量称为指针变量。

 

1.1指针变量的定义

 

指针变量是专门用来存放地址的变量,C语言将它定义为指针类型。指针变量也是变量,但指针变量中存放的不是变量的值,而是地址。

 

定义指针变量的一般格式是:

 

类型标示符*指针变量名;

 

例如:

 

int *pa,*pb;

 

float *q;

 

注:1这种语句仅仅是定义了指针变量,并没有明确的声明指向某一具体变量。

 

2指针变量前面的“*”代表该变量的类型是指针型的变量,因此它的变量名实pa和pb,而不是*pa、*pb;

 

1.2指针变量的赋值与引用

 

和普通变量一样,指针变量只有赋值之后才有意义,指针变量中存放的是变量的地址,所以就不允许用户随意为其赋常量值,一般情况下,指针变量可以通过取地址运算符和地址赋值运算来赋值。

 

取地址运算符“&”可以加在变量和数组元素前面来取得他们的内存地址,因为指针变量也是变量,所以该运算符也可以加在指针变量前面取值,例如:

 

int n1,n2;

 

int *p1,*p2,*p3;

 

float x,*p4,y;

 

p1=&n1;

 

p2=&n2;

 

p3=p2;

 

又上可知,指针变量的赋值方式是:

 

指针变量名=&变量名;

 

指针变量名=另一个已经赋值的指针变量;

 

指针变量的类型必须保证与其存放的变量类型是一致的,但有一个是例外的,就是C语言中允许出现空指针,也就是值是0的指针,含义是指针无指向,常用来判断返回指针的函数是否成功的标志。

 

当指针变量指向基本变量以后,就可以利用间接访问的方法来访问数据,此时使用取内容运算符“*”来访问数据,该运算符是通过指针变量来访问它所指向的变量时使用的运算符,基本格式为:

 

*指针变量

 

一旦将变量的地址赋值给指针变量后,那么*指针名和变量名是等价的,除非改变指针变量的指向,否则对指针的修改都会影响变量的值。例如:

 

int x,y1,*pi;

 

double d;

 

pi=&x;

 

x=1;

 

/*此时执行下面语句*/

 

y1=*pi+9;

 

实际上等价于:y1=x+9;

 

下面是使用指针变量的例子代码:

 

 

#include "stdio.h" 

main() { 

     int num=12, *pt;      /*定义一个指向int型数据的指针变量pt */ 

     float pi=3.14, *pf;       /*定义一个指向float型数据的指针变量pf */ 

     char ch='m', *pc;     /*定义一个指向char型数据的指针变量pc */ 

     pt=#               /*取变量num的地址,赋值给pt */ 

     pf=π      /*取变量pi的地址,赋值给pf */ 

     pc=&ch;       /*取变量ch的地址,赋值给pc */ 

     printf("num=%d, *pt=%d/n", num, *pt); 

     printf("pi=%4.2f, *pf=%4.2f/n", pi,*pf); 

     printf("ch=%c, *pc=%c/n", ch, *pc); 

  } 

指针交换:

 

 

#include "stdio.h" 

main(){ 

   int a,b; 

   int *p1,*p2,*p; 

   p1=&a; p2=&b; 

   scanf("%d%d",p1,p2); 

   if (a<b){ 

      p=p1;p1=p2;p2=p; }               /*交换的是地址不是地址里面的内容*/ 

   printf("the max is %d./n",*p1);  

内容交换:

 

 

#include "stdio.h" 

main() {  

  int a,b,t; 

   int *p1,*p2; 

   p1=&a; p2=&b; 

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

   if (a<b){ 

    t=*p1;* p1=*p2;*p2=t;}               /*交换的是地址里面的内容不是地址*/ 

   printf("the max is %d./n",*p1);  

2指针变量的运算

 

指针也就是地址,指针变量也可以进行某些运算。

 

2.1&和*运算

 

&是取地址运算符,功能是取变量的地址。

 

*是取值运算符,功能是取指针变量保存的地址所在的内存内容。

 

如:

 

int a;

 

int *p;

 

p=&a;

 

此时*p与a是相同的,表示同一个变量,简单的讲,*和&是互逆的运算。

 

2.2++和--运算

 

在C语言中,指针也可以进行自加和自减运算以及与整数做加减运算。但指针运算与整数运算不同,它与指针所执行的变量大小有关.

 

在指针的应用中,经常会出现指针的加1或减1与*运算符相结合的情况,例如:

 

*p++含义是访问指针p指向的数据,然后指针变量后移一个元素的位置。

 

*(p++)含义是指针变量后移一个元素的位置,然后访问元素。

 

假设p指向整型变量a,那么有以下结论:

 

1(*p)++与a++等价;

 

2*(p++)与*p++都能得到变量a的值,但p已经不再指向a;

 

3*p+1与a+1等价;

 

4(*p)++与*p++是不同的。

 

2.3比较运算符

 

一般情况下,当两个相同类型的指针变量被正确赋值后,就可以对指针变量进行比较运算。相同类型的指针变量的运算关系包括:>、<、>=、<=、==、!=。例如比较两个相同类型的指针,如果他们相等,就说明他们指向同一个地址。

 

在比较时,高地址大于低地址。

 

指向不同数据类型的指针之间进行比较关系运算是没有意义的。但是一个指针可以和NULL(0)做等或不等的关系运算,用来判断该指针是否为空。

 

2.4减法运算

 

C语言运行两个类型相同的指针变量进行相减,操作结果是两个指针之间的元素个数,实际上是两个指针地址相减之差再除以数据类型的长度。

 

指针运算例子代码:

 

 

#include "stdio.h" 

main(){ 

  int a=10,b=30,*p1=&a,*p2=&b;   /*定义指针变量,同时给指针变量初始化*/ 

  printf("%d  %d  %d  %d  %x  %x  %x  

          %x/n",a,b,*p1,*p2,p1,p2,&p1,&p2);  /*输出数据,比较观察数据之间的联系*/ 

  a++;(*p2)++;           /*变量和指针指向的变量的自加运算比较*/ 

  printf("%d  %d  %d  %d  %x  %x  %x  

           %x/n",a,b,*p1,*p2,p1,p2,&p1,&p2); 

  *p1++;*p2--;                 /*自加(减)运算与指向运算的优先级比较*/ 

  printf("%d  %d  %d  %d  %x  %x  %x  

           %x/n",a,b,*p1,*p2,p1,p2,&p1,&p2); 

   a=123;*p2=99;b=88;  /*对指针变量的赋值*/ 

   printf("%d  %d  %d  %d  %x  %x  %x  

           %x/n",a,b,*p1,*p2,p1,p2,&p1,&p2); 

  p1++;p2++;    /*地址改变以后,数据值与地址的变化*/ 

   printf("%d  %d  %d  %d  %x  %x  %x  

             %x/n",a,b,*p1,*p2,p1,p2,&p1,&p2); 

   printf("%d  %d/n",p1-p2,p2-p1);  /*指针变量的相减*/ 

 } 

3指针变量作为函数的参数

 

在函数部分我们知道可以使用return语句返回函数值,这种方式只能返回一个数据,但使用指针可以实现对数据的间接访问,用指针作为函数的参数,返回后就可以修改多个值了。

 

例子:调用函数,计算两个数相加和相减的值,并在main函数中打印。

 

 

#include "stdio.h" 

void  fun ( int x , int y,int *pa,int *ps ) {               /*两个数交换,形参为指针*/ 

int add=0 , sub=0 ; 

*pa=x+y ;  

*ps=x–y ;}                                    /*指针内容改变*/ 

main ( ){ 

int a , b , add=0 , sub=0 ; 

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

printf ( " a=%d , b=%d /n " , a , b ) ; 

fun ( a , b,&add,&sub) ; 

printf ( " %d + %d =%d /n " , a , b , add ) ; 

printf ( " %d – %d =%d /n " , a , b , sub ) ;} 

在利用指针作为函数的参数是,要了解在调用函数中如何正确的使用指针变量才可以改变参数的值,例如要交换两个数据的值,可以由3种方式:

 

3.1以普通变量作为参数完成交换:

 

void swap1(int x,int y){

 

int temp;

 

temp=x,x=y,y=temp;

 

}

 

这种调用仅仅是在函数中将数据交换了,当函数调用结束,返回到主函数中时,形参内存被释放,实际并没有交换。

 

3.2以指针变量作为参数实现数据交换:

 

void swap1(int *p1,int *p2){

 

int *p;

 

p=p1,p1=p2;p2=p;

 

}

 

这种交换同样实现不了功能,调用结束后仅仅是实现了两个指针指向的交换,而并没有实现真正的数据交换。

 

3.3交换指针变量所指向的内容:

 

void swap4(int *p1,int *p2){

 

int temp;

 

temp=*p1,*p1=*p2,*p2=temp;

 

}

 

这样才算实现了真正的数据交换。

 

4指针与一维数组

 

数组是一组相同类型数据的集合,数组中各个元素在内存占据连续的存储单元,每个内存单元都有相应的地址。数组所在内存单元的首地址称为数组的指针,数组元素所在内存单元的首地址称为数组元素的指针,数组指针和数组元素指针是两个不同的概念。

 

4.1指向一维数组元素的指针

 

不带方括号的数组名就是该数组的指针,可以把数组名或者第一个元素的地址赋值给指针。例如以下几个语句是合法的:

 

int a[5],*p,*q;

 

p=a; //保存数组的首地址

 

q=&a[3]; //保存数组中第四个元素的地址

 

由于数组名代表一维数组的首地址,也就是第0个元素的地址,因此以下两条语句是等价的:

 

p=a;

 

p=&a[0];

 

4.2用指针访问一维数组元素

 

指针指向数组之后,就在指针和数据之间建立了联系。可以通过指针访问数组的各个元素,当然也可以使用下标访问数组元素,但是使用指针访问能使程序占用内存更少,运行速度更快。以下代码借助指针实现了数组元素的输入和输出:

 

 

#include "stdio.h" 

main(){ 

  int arr [10], *pa=arr, i;  

  printf("Input 10 numbers: "); 

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

    scanf("%d", pa+i);  /*使用指针变量来输入数组元素的值*/ 

  printf("array[10]: "); 

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

   printf("%d  ", *(pa+i)); /*使用指向数组的指针变量输出数组*/ 

  printf("/n"); 

由于指针是变量,在元素的处理过程中,可以通过对地址的运算,直接得到元素的地址,然后访问数据元素,上面的代码也可以写成:

 

 

#include "stdio.h" 

main(){ 

  int arr [10], *pa=arr;  

  printf("Input 10 numbers: "); 

  for(;pa<arr+10;pa++) 

    scanf("%d", pa);    /*使用指针变量来输入数组元素的值*/ 

  printf("array[10]: "); 

  pa=arr; 

  for(;pa<arr+10;pa++) 

   printf("%d  ", *pa); /*使用指向数组的指针变量输出数组*/ 

  printf("/n"); 

这种访问方式也成为指针法访问数组中的元素,能够提高程序质量。在使用指针时应特别注意指针的越界问题,注意指针变量的变化。

 

例子:使用指针变量统计输入数据中的正数个数。

 

 

#include "stdio.h" 

main() {  

   int  a[10]; 

   int  i,*p,count=0; 

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

    scanf("%d",a+i); 

   printf("/n"); 

   for(p=a;p<a+10;p++) {                /*指针可以移动10次*/ 

      if (*p>0) { 

          count ++; 

          printf("%d",*p); 

          if (count % 4==0) printf("/n"); 

      }  

    } 

 

 

摘自 letthinking的专栏

图片内容