C语言一维指针的深入理解

指针是C语言中广泛使用的一种数据类型。运用指针编程是C语言最主要的风格之一。

利用指针变量可以表示各种数据结构;能很方便地使用数组和字符串;并能象汇编语言一样处理内存地址,从而编出精练而高效的程序。指针极大地丰富了C语言的功能。

学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是我们是否掌握C语言的一个标志。

C语言为什么有指针以及指针有什么好处?

从大体上讲:指针是 C 语言区别于其他同时代高级语言的主要特征之一。其次因为数组或函数都是连续存放的。通过访问指针变量取得了数组或函数的首地址,也就找到了该数组或函数。这样一来,凡是出现数组,函数的地方都可以用一个指 针变量来表示,只要该指针变量中赋予数组或函数的首地址即可。这样做,将会使程序的概念十分清楚,程序本身也精练,高效。

在C语言中,一种数据类型或数据结构往往都占有一组连续的内存单元。用“地址”这个概念并不能很好地描述一种数据类型或数据结构,而“指针”虽然实际上也 是一个地址,但它却是一个数据结构的首地址,它是“指向”一个数据结构的,因而概念更为清楚,表示更为明确。 这也是引入“指针”概念的一个重要原因。

使用指针可以带来如下的好处:

(1)可以提高程序的编译效率和执行速度,使程序更加简洁。

(2)通过指针被调用函数可以向调用函数处返回除正常的返回值之外的其他数据,从而实现两者间的双向通信。

(3)利用指针可以实现动态内存分配。

(4)指针还用于表示和实现各种复杂的数据结构,从而为编写出更加高质量的程序奠定基础。

(5)利用指针可以直接操纵内存地址,从而可以完成和汇编语言类似的工作。

变量的指针就是变量的地址。存放变量地址的变量是指针变量。即在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个变量的地址或称为某变量的指针。

为了表示指针变量和它所指向的变量之间的关系,在程序中用“*”符号表示“指向”

定义一个指针变量

对指针变量的定义包括三个内容:

  1. 指针类型说明,即定义变量为一个指针变量;
  2. 指针变量名;
  3. 变量值(指针)所指向的变量的数据类型。
int *p2;  /*p2是指向整型变量的指针变量*/
float *p3;  /*p3是指向浮点变量的指针变量*/
char *p4;  /*p4是指向字符变量的指针变量*/

应该注意的是,一个指针变量只能指向同类型的变量,如P3 只能指向浮点变量,不能时而指向一个浮点变量,时而又指向一个字符变量。

指针变量的引用

指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址,决不能赋予任何其它数据,否则将引起错误。在C语言中,变量的地址是由编译系统分配的,对用户完全透明,用户不知道变量的具体地址。

两个有关的运算符:

    • &:取地址运算符;
    • *:指针运算符(或称“间接访问” 运算符)。

设有指向整型变量的指针变量p,如要把整型变量a 的地址赋予p可以有以下两种方式:

1.指针变量初始化的方法:

1 int a;
2 int *p=&a;

2.赋值语句的方法:

int a;
int *p;
p=&a;

不允许把一个数赋予指针变量,故下面的赋值是错误的:

int *p;
p=1000;

通过指针访问它所指向的一个变量是以间接访问的形式进行的,所以比直接访问一个变量要费时间,而且不直观,因为通过指针要访问哪一个变量,取决于指针的值(即指向),例如"*p2=*p1;"实际上就是"j=i;",前者不仅速度慢而且目的不明。但由于指针是变量,我们可以通过改变它们的指向,以间接访问不同的变量,这给程序员带来灵活性,也使程序代码编写得更为简洁和有效。

经典错误:

1.C语言中函数调用,为什么交换了地址,可是所指的值还是不变那???? 

 1 #include<stdio.h>
 2 void swap(int *p1, int *p2);
 3 int main()
 4 {
 5     int a=8, b=10;
 6     int *point1 = &a;
 7     int *point2 = &b;
 8     swap(point1, point2);
 9     printf("%d, %d",a, b);
10 
11     return 0;
12 }
13 void swap(int *p1, int *p2) {
14     int *p;
15     p = p1;
16     *p1 = *p2;
17     p2 = p;
18 
19 }

因为你的 

1 int *p;
2     p = p1;
3     *p1 = *p2;
4     p2 = p;

交换的是  p1和p2 的地址.,不要忘记了,当调用一个函数时.os会为  swap 函数中的  int *a,int *b.开辟内存.你改变的是swap开辟的内存.并没有改变 main中的*point1和*point2内存区域.

我再说清楚点.

point1 保存的是 &a ,point2保存的是  &b,swap函数中a 保存的也是 &a,b保存的也是&b   。 你用交换了 a和b的 地址.有什么用.没有改变原来的地方的地址.

只是改变了你自己的 a 和 b里面的地址.   没有改变那边的 真正的  8 和 10。

如果用了   

1 int temp;
2     temp=*p1;
3     *p1=*p2;
4     *p2=temp;

就是间接去改变那边的值。通过里面 &a,&b,的地址来找到  真是的8,10  然后就改变了。

示例:按大小顺序输出

#include<stdio.h>
void swap(int *p1, int *p2){
    int temp;
    temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}
void exchange(int *a, int *b, int *c){
    if(*a > *b) swap(a, b);
    if(*b > *c) swap(b, c);
    if(*a > *c) swap(a, c);
}
int main()
{
    int a=23, b=34, c=12;
    //printf("%d, %d, %d", a, b, c);
    exchange(&a, &b, &c);
    printf("%d, %d, %d", a, b, c);
    return 0;
}

 

指针运算符

指针运算符有两种:

  • 取地址运算符(&):取地址运算符(&)是单目运算符,其结合性为自右至左,其功能是取变量的地址。在scanf函数及前面介绍指针变量赋值中,我们已经了解并使用了&运算符。
  • 取内容运算符(*):取内容运算符(*)是单目运算符,其结合性为自右至左,用来表示指针变量所指的变量。在*运算符之后跟的变量必须是指针变量。
int a = 5;
int *p = &a;
//当时可能初学者有疑问:不是说*p的值是5吗?怎么这里*p是&a

注意:

指针运算符(*)和指针变量说明中的指针说明符(*)不是一回事。在指针变量说明中,“*”是类型说明符,表示其后的变量是指针类型。而表达式中出现的“*”则是一个运算符用以表示指针变量所指的变量。

 

加减算术运算

对于指向数组的指针变量,可以加上或减去一个整数n。设pa是指向数组a的指 针变量,则pa+n, pa-n, pa++, ++pa, pa--, --pa运算都是合法的。指针变量加或减一个整数n的意义是把指针指向的当前位置(指向某数组元素)向前或向后移动n个位置。应该注意,数组指针变量向前 或向后移动一个位置和地址加1或减1在概念上是不同的。因为数组可以有不同的类型,各种类型的数组元素所占的字节长度是不同的。如指针变量加1,即向后移 动1 个位置表示指针变量指向下一个数据元素的首地址。而不是在原地址基础上加1。

两个指针变量之间的运算

只有指向同一数组的两个指针变量之间才能进行运算,否则运算毫无意义。

1) 两指针变量相减
两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是 两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2 的值为2000H,而浮点数组每个元素占4个字节,所以pf1-pf2的结果为(2000H-2010H)/4=4,表示pf1和 pf2之间相差4个元素。两个指针变量不能进行加法运算。例如,pf1+pf2是什么意思呢?毫无实际意义。

2) 两指针变量进行关系运算
指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:

  • pf1==pf2 表示pf1和pf2指向同一数组元素;
  • pf1>pf2 表示pf1处于高地址位置;
  • pf1<pf2 表示pf2处于低地址位置。


指针变量还可以与0比较。设p为指针变量,则p==0表明p是空指针,它不指向任何变量;p!=0表示p不是空指针。

空指针是由对指针变量赋予0值而得到的。例如:

#define NULL 0
int *p=NULL;

对指针变量赋0值和不赋值是不同的。指针变量未赋值时,可以是任意值,是不能使用的。否则将造成意外错误。而指针变量赋0值后,则可以使用,只是它不指向具体的变量而已。 

一个变量有一个地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。所谓数组的指针是指数组的起始地址,数组元素的指针是数组元素的地址。

一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。一个数组也是由各个数组元素(下标变量)组成的。每个数组元素按其类型不同占有几个连续的内存单元。一个数组元素的首地址也是指它所占有的几个内存单元的首地址。

C语言规定,数组名代表数组的首地址,也就是第0号元素的地址。因此,下面两个语句等价:

 

1 p=&a[0];
2 p=a;

 

引用一个数组元素可以用:

  • 下标法:即用a[i]形式访问数组元素。在前面介绍数组时都是采用这种方法。
  • 指针法:即采用*(a+i)或*(p+i)形式,用间接访问的方法来访问数组元素,其中a是数组名,p是指向数组的指针变量,其处值p=a。

 

posted on 2015-05-15 00:45  liujie037  阅读(477)  评论(0编辑  收藏  举报

导航