vlambda博客
学习文章列表

指针,C语言指针完全攻略_1

内存与地址


#include <stdio.h>int main(void){ char c='A'; int a=100; printf("a=%d\n",a);//输出变量a的值 printf("&a=%x\n",&a);//输出变量a的地址 printf("c=%c\n",c); printf("&c=%x\n",&c); return 0;}

程序某次的运行结果为:

指针变量的定义

类型 * 变量名;

例如:

 
   
   
 
  1. int *pa;

 
   
   
 
  1. int *pa,*pb;

表示定义了两个指针变量 pa、pb。而:

int *pa,pb;

则仅有 pa 是指针变量,而 pb 是整型变量。

 
   
   
 
  1. int *pi,a,b; //等价于inta,b,*pi;

表示定义了一个整型指针变量 pi 和两个整型变量 a 和 b。

2) 在使用已定义好的指针变量时,在变量名前面不能加 *。例如:

 
   
   
 
  1. int *p,a;

  2. *p=&a; //错误,指针变量是p而不是*p

而如下语句是正确的。

 
   
   
 
  1. int a,*p=&a; //正确

 
   
   
 
  1. int a,b,*pa,*pb;

  2. char *pc,c;

则:

 
   
   
 
  1. pa=&a;//正确。pa基类型为int,a为int型变量,类型一致

  2. pb=&c;//错误。pb基类型为int,c为char型变量,类型不一致

  3. pc=&c;//正确。pc基类型为char,c为char型变量,类型一致

  4. *pa=&a;//错误。指针变量是pa而非*pa

4) 变量名是一合法标识符,为与普通变量相区分,一般指针变量名以字母 p(pointer)开头,如 pa、pb 等。

5) 由于是变量,故指针变量的值可以改变,也即可以改变指针变量的指向。

 
   
   
 
  1. char c1,*pc,c2;//定义了字符变量c1、c2和字符指针变量pc

则如下对指针变量的赋值语句均是正确的。

 
   
   
 
  1. pc=&c1; //pc指向c1

  2. pc=&c2; //pc不再指向c1,而指向c2

6) 同类型的指针变量可以相互赋值。

 
   
   
 
  1. int a,*p1,*p2,b;//定义了两个整型变量a,b;两个整型指针变量为p1,p2

  2. float *pf;

以下赋值语句均是正确的。

 
   
   
 
  1. p2=p1; //p2也指向a,即p1和p2均指向a

 
   
   
 
  1. pf=p1;//错误。p1,pf虽然都是指针变量,但类型不同,不能赋值

  2. pf=&b; //错误。指针变量pf的基类型为float,b类型为int,不相同

 
   
   
 



图 2 指针指向变量

指针变量的引用

 
   
   
 
  1. p=&a;

 
   
   
 
  1. printf("a=%d\n",a); //通过名字,直接访问变量a空间(读取)

  2. *p=6;//等价于a=6;间接访问a对应空间(存)

“野”指针

本节中,把没有合法指向的指针称为“野”指针。因为“野”指针随机指向一块空间,该空间中存储的可能是其他程序的数据甚至是系统数据,故不能对“野”指针所指向的空间进行存取操作,否则轻者会引起程序崩溃,严重的可能导致整个系统崩溃。

例如:

 
   
   
 
  1. int *pi,a; //pi未初始化,无合法指向,为“野”指针

  2. *pi=3; //运行时错误!不能对”野”指针指向的空间做存入操作。该语句试图把 3 存入“野”指针pi所指的随机空间中,会产生运行时错误。

  3. a=*pi; //运行时错误!不能对”野”指针指向的空间取操作。该语句试图从“野”指针pi所指的空间中取出数据,然后赋给变量a同样会产生运行时错误。

正确的使用方法:

 
   
   
 
  1. pi=&a;//让pi有合法的指向,pi指向a变量对应的空间

  2. *pi=3;//把3间接存入pi所指向的变量a对应的空间

指针与数组

一维教组和指针

在 C 语言中,指针变量加 1 表示跳过该指针变量对应的基类型所占字节数大小的空间。指向数组元素的指针,其基类型为数组元素类型,指针加 1 表示跳过一个数组元素空间,指向下一个数组元素。

例如:

 
   
   
 
  1. int *p,a[10];

  2. p=a; //相当于 p=&a[0];

 
   
   
 
  1. for (p=a;p<a+N;p++) //用p的移动范围控制循环次数

  2. printf ("%d\t",*p);

 
   
   
 
  1. int *p,a[10],i;

  2. p=a;

#include <stdio.h>#define N 10int main (void){ int *p,a[N],i; p=a; //p初始指向a[0] printf("Input the array:\n"); for(i=0;i<N;i++) //用整型变量i控制循环次数 scanf ("%d",p++); //指针P表示地址,不能写成&P printf ("the array is :\n"); for(p=a;p<a+N;p++) //用p的移动范围控制循环次数 printf("%d\t", *p); return 0;}

补充说明:

输入输出循环控制方法有多种,不管采用哪种,必须准确确定起点和终点的表达式。

1) 输入若采用p的移动范围确定循环次数,则代码如下。

 
   
   
 
  1. for(p=a;p<a+N;p++)

  2. scanf("%d",p);

这时,for 语句之前的 p=a; 语句可以去掉。

2) 输出若采用移动指针变量 p 控制循环的执行,因为执行完输入操作后,p 已不再指向数组首元素,而是越界的 a[N] 初始位置,故必须重新给 p 赋值,让其指向数组的首元素, 代码如下。

 
   
   
 
  1. p=a; //重新赋值,让p指向数组首元素

  2. for(i=0;i<N;i++)

  3. printf ("%d\t",*p++);