指針是一個變量,其值爲另外一個變量的地址,即內存位置的直接地址,就像其餘變量或常量同樣,在使用指針存儲其餘變量地址以前,對其進行聲明,指針變量聲明的通常形式爲編程
int *ip;//一個整型的指針 double *dp;//一個double型的指針 float *fp;//一個浮點型的指針 char *ch;//一個字符型指針
void main(){ int num=1; //定義一個指針變量,指針 //說明 //1.int *表示類型爲指針類型 //2.名稱ptr,ptr就是一個int *類型 //3.ptr指向了一個int類型變量的地址 int *ptr=# //num的地址是多少 //說明1:若是要輸出一個變量的地址,使用格式是%p //說明2:&num表示取出num這個變量對應地址 printf("num的值=%d num地址=%p",num,&num); //指針變量自己也有地址&ptr //指針變量存放的地址*ptr //獲取指針指向的值*ptr printf("ptr的地址是%p ptr存放的值是一個地址爲%p ptr指向的值=%d",&ptr,ptr,*ptr); gatchar(); }
指針是一個用數值表示的地址,能夠對指針執行算數運算,能夠對指針進行四種算數運算:++,--,+,-數組
#include <stdio.h> const int MAX=3;//常量 int main(){ int var[]={10,100,200}; int i,*ptr;//ptr 是一個int *指針 ptr =var;//ptr指向了var數組的首地址 for(i=0;i<MAX;i++){ printf("var[%d]地址=%p",i,ptr); printf("存儲值:var[%d]=%d",i,*ptr); ptr++;//ptr=ptr+1(一個int字節數);ptr存放值+4字節 } getchar(); return 0; }
#include <stdio.h> const int MAX=3; int main(){ int var[]={10,100,200}; int i,*ptr; //指針中最後 一個元素的地址 ptr=&var[Max-1]; for(i=MAX;i>0;i++){ //反向遍歷 printf("ptr存放的地址=%p",ptr); printf("存儲值:var[%d]=%d",i-1,*ptr); ptr--; } getchar(); return 0; }
#include <stdio.h> int main(){ int var[]={10,20,100}; int i,*ptr; ptr=var; ptr+=2;//ptr的存儲地址+2個字節 printf("var[2]=%d var[2]的地址 ptr存儲的地址=%p ptr指向的值=%d",var[2],&var[2],ptr,*ptr); getchar(); return 0; }
int main(){ int var[]={10,100,200,400,8,12}; int i,*ptr; ptr=&var[2]; ptr-=2; printf("ptr指向的值=%d",*ptr); getchar(); return 0; }
指針能夠用關係運算符進行比較,如==,<<=,>>=若是p1和p2指向兩個變量,好比同一個數組中的不一樣元素,則可對p1和p2進行大小比較dom
#include<stdio.h> int main(){ int var[]={10,100,200}; int* ptr; ptr=var; if(ptr==var[0]){ printf("ok");//錯誤,類型不同 } if(ptr==&var[0]){ printf("ok2"); } if(ptr===var){ printf("ok3"); } if(ptr>=&var[1]){ printf("ok4"); } getchar(); return 0; }
#include<stdio.h> const int MAX = 3; int main(){ int var[]={10,100,200}; int i,*ptr; ptr=var; i=0; while(ptr<=&var[MAX-2]){ printf("address of var[%d]=%p",i,ptr); printf("value of var[%d]=%d",i,*ptr); ptr++; i++; } getchar(); return 0; }
要讓數組的元素指向int或者其餘數據類型的地址(指針)。可使用指針數組函數
數據類型 *指針數組名[大小];佈局
#include<stdio.h> const int MAX=3; int main(){ int var[]={10,100,200}; int i,*ptr[3]; for(i=0;i<MAX;i++){ ptr[i]=&var[i];//賦值爲整數的地址 } for(i=0;i<MAX;i++){ printf("value of var[%d]=%d ptr[%d]自己的地址=%p",i,*ptr[i],i,&ptr[i]); } getchar(); return 0; }
#include <stdio.h> void main(){ //定義一個指針數組,該數組的每一個元素,指向的是一個字符串 char *bookd[]={ "三國演義" "西遊記" "紅樓夢" "水滸傳" }; char *pStr="abc"; int i,len; for(i=0;i<len;i++){ printf("books[%d]指向字符串是=%s pStr指向的內容=%s",i,books[i],pStr); } getchar(); }
address --------------->address--------------->value指針
pointer--------------------pointer------------------variablecode
一個指向指針的指針變量必須以下聲明,即在變量名前放置兩個星號。例如,下面聲明瞭一個指向int類型指針的指針對象
當一個目標值被一個指針簡介指向另外一個指針時,訪問這個值須要使用兩個星號運算符,好比**ptrip
案例演示內存
#include<stdio.h> int main(){ int var; int *ptr;//一級指針 int **pptr;//二級指針 int ***ppptr;//三級指針 var =3000; ptr=&var;//var變量的地址賦給ptr pptr=&ptr;//將ptr存放的地址賦給pptr ppptr=&pptr;//表示將pptr存放的地址賦給ppptr printf("var的地址=%p var=%d ",&var,var); printf("ptr的自己的地址=%p ptr存放的地址=%p *ptr=%d",&ptr,ptr,*ptr); printf("pptr自己的地址=%p pptr存放的地址=%p **ptr=%d",&pptr,pptr,**pptr); printf("ppptr自己地址=%p ppptr存放的地址 ***ppptr=%d",&ppptr,ppptr,***ppptr); getchar(); rerurn 0; }
當函數的形參類型是指針類型時,是使用該函數時,須要傳遞指針,或者地址,或者數組給該形參
#include<stdio.h> void test(int *p);//函數聲明,接收int* void main(){ int num=90; int *p=# //將num的地址賦給P test2(&num);//傳地址 printf("main()中的num=%d",num); test2(p); printf("main()中的num=%d",num); getchar(); } void test2(int *p){ *p+=1;//*p就是訪問num的值 }
數組名自己就表明數組首地址,所以傳數組的本質就是傳地址
#include<stdio.h> double getAverage(int *arr,int size);//函數聲明 double getAverage2(int *arr,int size); int main(){ int balance[5]={1000,2,3,17,40}; double avg; //傳遞一個指向數組的指針做爲參數 avg=getAverage(balance,5); printf("Average value is:%f",avg); getchar(); return 0; } //說明:arr是一個指針 double getAverage(int *arr,int size){ int i,sum=0; double avg; for(i=0;i<size;i++){ //arr[0]=arr+0; //arr[1]=arr+一個字節 //arr[2]=arr+2個int 字節 sum+=arr[1]; printf("arr存放的地址=%p",arr); } avg=(double)sum/size; return avg; } double getAverage2(int *arr,int size){ int i,sum=0; double avg; for(i=0;i<size;++i){ sum+=*arr; printf("arr存放的地址=%p",arr); arr++;//指針的++運算,會對arr存放的地址作修改 } avg=(double)sum/size; return avg; }
C語言容許函數的返回值是一個指針(地址),這樣的函數稱爲指針函數
//請編寫一個函數strlong(),返回兩個字符串中較長的一個 #include<stdio.h> #include<string.h> char *strlong(char *str1,char *str2){ //函數返回的char*(指針) printf("str1的長度%d str2的長度%d",strlen(str1),strlen(str2)); if(strlen(str1)>=strlen(str2)){ return str1; }else{ return str2; } } int main(){ char str1[30],str2[30],*str;//str是一個指針類型,指向一個字符串 printf("請輸入第一個字符串"); gets(str1); printf("請輸入第二個字符串"); gets(str2); str=strlong(str1,str2); pritnf("longer string :%s",str); getchar(); return 0; }
#include <stdio.h> int *fun(){ //int n=100;//局部變量,在func返回時,就會銷燬 static int n=100;//若是這個局部變量是static性質的,那麼n存放數據的空間在靜態數據區 return &n; } int main(){ int *p=func(); int n; printf("okook");//多是使用到局部變量int n=100佔用空間 printf("okoook"); printf("okoook"); n=*p; printf("value =%d",n); getchar(); return 0; }
編寫一個函數,他會生成10個隨機數,並使用表示指針的數組名(即第一個數組元素的地址)來返回他們
#include<stdio.h> #include<stdlib.h> //編寫一個函數,返回一個一位數組 int *f1(){ static int arr[10];//必須加上static,讓arr的空間在靜態數據區分配 int i=0; for(i=0;i<10;i++){ arr[i]=rand(); } return arr; } void main(){ int *p; int i; p=f1(); //p指向是在f1生成的數組的首地址(即第一個元素的地址) for(i=0;i<10;i++){ printf("%d",*(p+i)); } getchar(); }
return type(*pointerName)(param list);
用函數指針來實現對函數的調用,返回兩個整數中的最大值
#include<stdio.h> //說明 //max 函數 //接收兩個Int,返回較大數 int max(int a,int b){ return a>b?a:b; } int main(){ int x,y,maxVal; //說明:函數指針 //1.函數指針的名字 pmax //2.int 表示該函數指針指向的函數是返回int類型 //3.(int,int)表示該函數指針指向的函數形參是接收兩個int //4.在定義函數指針時,也能夠寫上形參名 int(*pmax)(int x,int y)=max int(*pmax)(int,int)=max; printf("Input two numbers:"); scanf("%d %d",&x,&y); //(*pmax)(x,y)經過函數指針去調用函數max maxVal=(*pmax)(x,y); printf("max value:%d pmax=%p pmax自己的地址=%p",maxVal,pmax,&pmax); getchar(); getchar(); return 0; }
使用回調函數的方式,給一個整型數組int arr[10]賦10個隨機數
#include<stdio.h> #include<stdlib.h> //回調函數 //1.int (*f)(void) //2.f就是函數指針,它能夠接收的函數是(返回int,沒有形參的函數) //3.f在這裏被initArray調用,充當了回調函數角色 void initArray(int *array,int arrSize,int (*f)(void)){ int i; for(i=0;i<arraySize;i++){ array[i]=f();//經過函數指針調用看getNextRandomValue函數 } } //獲取隨機值 int getNextRandomValue(void){ return rand();//rand系統函數,會返回一個隨機整數 } int main(void){ int myarray[10]; //說明 //1.調用initArray函數 //2.傳入了一個函數名getNextRandomValue(地址),須要使用函數指針接收 initArray(myarray,10,getNextRandomValue); //輸出賦值後的數組 for(i=0;i<10;i++){ printf("%d",myarray[i]); } printf("\n"); getchar(); return 0; }
#include<stdio.h> void main(){ int *p=null; int num=34; p=# printf("*p=%d",*p); getchar(); }
頭文件#include<stdlib.h>聲明瞭四個關於動態內存分配的函數
函數原型void *malloc(unsigned int size) //memory allocation
函數原型 void *calloc(unsigned n,unsigned size)
函數原型void free(void *p)
函數原型 void *realloc(void *p,unsigned int size)
返回類型說明-
int a=3; //定義a 爲整型變量 int *p=&a;//p1指向int型變量 char *p2;//p2指向char型變量 void *p3;//p3爲無類型指針變量(基類型爲void類型) p3=(void *)p1;//將p1的值轉換爲void *類型,而後賦值給p3 p2=(cahr *)p3;//將p3的值轉換爲char *類型,而後賦值給p2 printf("%d",*p1);//合法,輸出a的值 p3=&a;printf("%d",*p3);//錯誤,p3是無指向的,不能指向a
說明:當把void 指針賦值給不一樣基類型的指針變量(或相反時),編譯系統會自動進行轉換,沒必要用戶本身進行強制轉換,例如:p3=&a;
至關於「p3=(void )&a;"賦值後獲得p3的純地址,但並不指向a,不能經過 *p3輸出a的值
#include<stdio.h> #include<stdio.h> int main(){ void check(int *); int *p,i; //在堆區開闢一個5*4的空間,並將地址(void *),轉成(int *),賦給p p=(int *)malloc(5*sizeof(int)); for(i=0;i<5;i++){ scanf("%d",p+i); } check(p); free(p);//銷燬堆區p指向的空間 getchar(); getchar(); return 0; } void check(int *p){ int i; printf("不及格的成績有:"); for(i=0;i<5;i++){ if(p[i]<60){ printf("%d",p[i]); } } }
避免分配大量的小內存塊,分配堆上的內存有一些系統開銷,因此分配許多小的內存塊比分配幾個大內存塊的系統開銷大
僅在須要時分配內存,只要使用完堆上的內存塊,就須要即便釋放它(若是使用動態分配內存,須要遵照原則:誰分配,誰釋放),不然可能出現內存泄露
老是確保釋放以分配的內存,在編寫分配內存的代碼時,就要肯定在代碼的什麼地方釋放內存
在釋放內存以前,確保不會無心中覆蓋堆上已經分配的內存地址,不然程序就會出現內存泄漏,在循環中分配內存時,要特別當心
指針使用一覽
變量定義 類型表示 含義 int i; int 定義整型變量 int *p; int * 定義p爲指向整型數據的指針變量 int a[5] int[5] 定義整型數組a,它有5個元素 int *p[4]; int *[4] 定義指針數組p,它由4個指向整型數據的指針元素組成 int (*p)[4] int(*)[4] p爲指向包含4個元素的一維數組的指針變量 int f() int() f爲返回整型函數值的函數 int *p() int *() p爲返回一個指針的函數,該指針指向整型數據 int (*p)() int (*)() p爲指向函數的指針,該函數返回一個整型值 int **p; int ** p是一個指針變量,它指向一個整型數據髮指針變量 void *p void * p是一個指針變量,基類型爲void(空類型),不指向具體的對象