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的專欄