指針(視頻學(xué)習(xí)結(jié)合一本通)視頻為北大c++指針(程序設(shè)計與算法一)

有了指針,就有了自由訪問內(nèi)存空間的手段。


指針的基本概念:

每個變量都被存放在從某個內(nèi)存地址開始的若干字節(jié)中。

指針也叫作指針變量,大小為4個字節(jié)(64位計算機為8個字節(jié))的變量,其內(nèi)容代表一個內(nèi)存地址。

通過指針,能夠?qū)υ撝羔樦赶虻膬?nèi)存空間進行讀寫。

如果把內(nèi)存的每一個字節(jié)都想象成一個房間,那么內(nèi)存地址相當于房間號,而指針里存放的就是房間號。

指針變量的賦值、定義:

類型說明符 *變量名

int *p; p是一個指針,變量p的類型是int*。

char *c;c是一個指針,變量c的類型是char*。

float *d;d是一個指針,變量d的類型是float*。

如何訪問int型變量a前面一個字節(jié)?

int a;

char*p=(char*)&a;

--p;

printf(“%c”,*p);//可能會導(dǎo)致運行出錯

*p=‘A’;//可能會導(dǎo)致運行出錯(可能不讓訪問)

(以上方法是錯誤的)

int *p1,*p2;int n=4;

char *pe1,*pe2;

p1=(int*)100;

p2=(int*)200;

cout<<"1)"<<p2-p1<<endl;

通過指針訪問其指向的內(nèi)存空間:

int *p=(int*)40000;

*p=5000;

int n=*p;

若干=sizeof(int),因為int*p。

指針定義的總結(jié):

T*p;T可以是任何類型,如float,int char。

p的類型是T*。

*p的類型是T。

通過表達式*p可以讀寫從地址p開始的sizeof(T)個字節(jié)。

*是間接引用運算符。

指針用法:

char ch=‘A’;

char *pc=&ch;

&取地址符

指針的作用:

不需要通過變量就可以直接對內(nèi)存空間進行操作。通過指針,程序能訪問的內(nèi)存空間就不僅限于變量所占有的內(nèi)存空間。

指針的互相賦值:

不同類型的指針,如果不經(jīng)過強制類型轉(zhuǎn)換,不可以相互賦值。

int*pn,char*pc,char c=0x65;

pn=pc;//類型不匹配,編譯出錯

pn=*c;//類型不匹配,編譯出錯

pn=(int*)&c;

int n=*pn;//n值不確定

*pn=0x12345678;//編譯沒毛病,但運行會錯誤,可能會導(dǎo)致程序的崩潰

指針的運算:

1.兩個同類型的指針變量可以比較大?。ū容^地址的大小)

地址p1<地址p2? ?==? ?p1<p2? ?值為真

地址p1=地址p2? ?==? ?p1==p2? ?值為真

地址p1>地址p2? ?==? ?p1>p2? ?值為真

2.兩個同類型的指針變量,可以相減

兩個T*類型的指針p1和p2

p1-p2=(地址p1-地址p2)/sizeof(T)

3.指針變量加減一個整數(shù)的結(jié)果是一個指針

p:T*類型的指針

n:整數(shù)類型的變量或常量

p+n:T*類型的指針,指向地址:地址p+n*sizeof(T)

n+p,p-n,*(p+n),*(p-n)含義自明

4.指針變量可以自增自減

T*類型的指針p指向地址n

p++,++p:p指向n+sizeof(T)

p--,--p:p指向n-sizeof(T)

5.指針可以用下標運算符“[? ]”進行運算

p是一個T*類型的指針,n是整數(shù)類型的常量或變量。

p【n】=*(p+n)

空指針:

地址0不能訪問。指向地址0的指針就是空指針。

可以用“NULL”關(guān)鍵字對任何類型的指針進行賦值,NULL實際上就是整數(shù)0。

int *p1=NULL;char *pc=NULL;int *p2=0;

指針可以作為條件表達式使用,如果指針的值為NULL,則相當于假,反之為真。

if(p)等價于if(p!=NULL)。

指針作為函數(shù)參數(shù):

#include<bits/stdc++.h>

using namespace std;

void swap(int *p1,int *p2)//p1 形參

{

int temp=*p1;

*p1=*p2;

*p2=temp;

}

int main(){

int n=3,m=4;//n實參

swap(&n,&m);

cout<<m<<' '<<n<<endl;

return 0;

}

指針和數(shù)組:

數(shù)組的名字是一個指針常量,指向數(shù)組的初始地址。

T a[n];

a的類型是T*

可以用a給T*類型的指針賦值

a是編譯時其值就已經(jīng)確定了的,不能夠?qū)進行賦值

作為函數(shù)形參時,T*p和T p[ ]是等價的

void(int T*p){cout<<sizeof(p)};

void(int T p[ ]){cout<<sizeof(p)};

代碼:

#include<bits/stdc++.h>

using namespace std;

int main(){

int a[200];int *p;

p=a;//p指向數(shù)組a的初始地址,亦指p指向了a[0]

*p=10;//使得a[0]=10

*(p+1)=20;//a[1]=20

p[0]=30;//p[i]和*p[i+1]是等效的,使得a[0]=30

p[4]=40;//a[4]=40

for(int i=0;i<10;i++)//對數(shù)組a的前十個元素進行賦值

*(p+i)=i;

++p;//p指向a[1]

cout<<p[0]<<endl;//輸出1? ? ? p[0]等效于*p,p[0]即是a[1]

p=a+6;//p指向a[6]

cout<<*p<<endl;//輸出6

return 0;

}

翻轉(zhuǎn)

代碼:

#include<bits/stdc++.h>

using namespace std;

void reverse(int *p,int size){

for(int i=0;i<size;i++){

int temp=p[i];

p[i]=p[size-i];

p[size-i]=temp;

}

}

int main(){

int a[5]={1,2,3,4,5};

reverse(a,sizeof(a/sizeof(int));

for(int i=0;i<5;i++)

cout<<*(a+i)<<',';

return 0;

}

動態(tài)數(shù)組:

指針可以動態(tài)申請空間,如果一次申請多個變量空間,系統(tǒng)給的地址是連續(xù)的,就可以當做數(shù)組使用,這就是傳說中的動態(tài)數(shù)組的一種。

#include<bits/stdc++.h>

using namespace std;

int n;

int *a;

int main(){

cin>>n;

a=new int[n+1];

for(int i=1;i<=n;i++)

cin>>a[i];

for(int i=2;i<=n;i++)

a[i]+=a[i-1];

for(int i=1;i<=n;i++)

cout<<a[i]<<' ';

return 0;

}

動態(tài)數(shù)組的優(yōu)點:

在OI中,對于大數(shù)據(jù)可能超空間的情況是比較糾結(jié)的事,用小數(shù)組只能得部分分,大數(shù)組可能爆空間同時又爆零,使用動態(tài)數(shù)組可以在確保小數(shù)據(jù)沒問題的前提下,盡量滿足大數(shù)據(jù)的需求。

指針和字符串:

字符串常量的類型是char*

字符數(shù)組名的類型是char*,就是一個地址。

注意:可以使用字符數(shù)組名或者字符指針輸出一個字符串,而面對一個數(shù)值型數(shù)據(jù)是不能企圖用數(shù)組名輸出它的全部元素的。

如:

int i[10];

……

printf("%d\n",i);

代碼:

#include<bits/stdc++.h>

using namespace std;

int main(){

char*p="please input your name:\n";

cout<<p;

char name[20];

char*pname=name;

cin>>pname;

cout<<"your name is "<<pname;

return 0;

}

字符串指針作函數(shù)參數(shù):

將一個字符串從一個函數(shù)傳遞到另一個函數(shù),可以用地址傳遞的方法,即用字符數(shù)組名作參數(shù)或用指向字符的指針變量做參數(shù)。在被調(diào)用的函數(shù)中可以改變字符串的內(nèi)容,在主調(diào)函數(shù)中可以得到改變了的字符串。

例題:

輸入一個長度最大為100的字符串,以字符數(shù)組的方式存儲,再將字符串倒序儲存,輸出倒序儲存后的字符串(這里以字符指針為函數(shù)參數(shù))

#include<bits/stdc++.h>

using namespace std;

void swapp(char &a,char &b){

char t;

t=a;

a=b;

b=t;

}

void work(char *str){

int len=strlen(str);

for(int i=0;i<=len/2;i++)

swapp(str[i],str[len-i-1]);

}

int main(){

char s[110];

char *str=s;

gets(s);

work(str);

printf("%s",s);

return 0;

}

字符串操作函數(shù):


轉(zhuǎn)自視頻(侵刪)

void指針:

void*p;

可以用任何類型的指針對void指針進行賦值或初始化

double d=1.54;

void*p=&d;

void*p1;

p1=&d;

因sizeof(void)沒有定義,所以對于void*類型的指針p,*p無定義,++p,--p,p+=n,p-=n,p+n,p-n等均無定義。

內(nèi)存操作庫函數(shù)memset:

頭文件cstring中聲明:

void*memset(void*dest,int ch,int n);

將從dest開始的n個字節(jié),都設(shè)置成ch,返回值是dest,ch只有最低的字節(jié)起作用。

內(nèi)存操作庫函數(shù)memcpy:

頭文件cstring中聲明:

void*memcpy(void*dest,void*src,int n);

將地址src開始的n個字節(jié),拷貝到地址dest。返回值是dest。

注意!有缺陷,在dest區(qū)間和src區(qū)間有重疊時可能出問題!

試手:

1.輸入n個數(shù),使用指針變量訪問輸出。

#include<bits/stdc++.h>

using namespace std;

int a[111],n;

int main(){

cin>>n;

for(int i=1;i<=n;i++)

cin>>a[i];

int *p=&a[1];

for(int i=1;i<=n;i++){

cout<<*p<<' ';

p++;

}

return 0;

}

2.無類型指針運用:

#include<bits/stdc++.h>

using namespace std;

int a=10;

double b=3.5;

void *p;

int main(){

p=&a;

cout<<*(int *)p<<endl;

p=&b;

cout<<*(double*)p<<endl;

return 0;

}

3.多重指針:

#include<bits/stdc++.h>

using namespace std;

int a=10;

int *p;

int **pp;

int main(){

p=&a;

pp=&p;

cout<<a<<' '<<*p<<' '<<**pp;

return 0;

}

多重指針除了可以多次間接訪問數(shù)據(jù),OI上主要的應(yīng)用是動態(tài)的多維數(shù)組。

4.訪問數(shù)組

#include<bits/stdc++.h>

using namespace std;

int main(){

int a[5],i,*pa=a;

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

cin>>a[i];

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

cout<<*(pa+i);

return 0;

}

5.行列轉(zhuǎn)換問題

描述:矩陣可以認為是N*M的二維數(shù)組,現(xiàn)在有一個巨大但稀疏的矩陣。

N,M范圍是:1<=N,M<=100000,有K個位置有數(shù)據(jù),K的數(shù)據(jù)范圍是1<=K<=100000。

矩陣輸入的方式是從上到下,從左到右掃描,極路由數(shù)據(jù)的坐標位置和值,這是按照行優(yōu)先的方式保存數(shù)據(jù)的?,F(xiàn)在要求按照列優(yōu)先的方式輸出數(shù)據(jù),即從左到右,從上到下掃描,輸出有數(shù)據(jù)的坐標和值。

輸入格式:

第一行,三個整數(shù)N,M,K;下面有K行,每行三個整數(shù):a,b,c,表示的a行b列有數(shù)據(jù)c,數(shù)據(jù)在int范圍內(nèi),保證是行優(yōu)先的次序。

輸出格式:

一行,K個整數(shù),是按照列優(yōu)先次序輸出的數(shù)。

樣例輸入:

4 5 9

1 2 12

1 4 23

2 2 56

2 5 78

3 2 100

3 4 56

4 1 73

4 3 34

4 5 55

樣例輸出:

73 12 56 100 34 23 56 78 55

樣例解釋:


分析:

由于N,M可能會很大,直接開二維數(shù)組太大,不可行。解決問題的方法有很多種,下面的程序使用了指針和動態(tài)數(shù)組,根據(jù)每一列的實際數(shù)據(jù)個數(shù)來申請該列的空間,使每列的數(shù)組長度不同。算法是O(N+M+K)的時間復(fù)雜度(即程序的運算量)。

參考程序:

#include<cstdio>

using namespace std;

const int LP=100001;

int n,m,k;

int x[LP],y[LP],d[LP];

int c[LP];//每列的數(shù)據(jù)個數(shù)

int *a[LP];//每列一個指針,準備申請數(shù)組

/*這里固定大小為LP的一個指針數(shù)組,占用空間為5*4*LP字節(jié),約2M

還可以在輸入n,m后,在申請動態(tài)數(shù)組,當n,m較小時,占用更小的空間

a[i]表示第i列的指針*/

int main() {

scanf("%d%d%d",&n,&m,&k);

for(int i=1; i<=k; i++) {

scanf("%d%d%d",&x[i],&y[i],&d[i]);//x [i]和y[i]是第i個數(shù)據(jù)所在的行號和列號

c[y[i]]++//統(tǒng)計c數(shù)組中每列數(shù)據(jù)的個數(shù);

}

for(int i=1; i<=m; i++)

a[i]=new int [c[i]];//第i列指針申請數(shù)組空間

for(int i=1; i<=k; i++) {//收集k個數(shù)據(jù)到相應(yīng)的列中

*a[y[i]]=d[i];//數(shù)據(jù)放在相應(yīng)列的數(shù)組中,也可以寫成a[y[i]][0]=d[i]

a[y[i]]++;//數(shù)組指針移到下一個位置

}

for(int i=1; i<=m; i++) {//列優(yōu)先

a[i]-=c[i];//指針回到每列的前面

for(int j=1; j<=c[i]; j++,a[i]++)

printf("%d ",*a[i]);

}

return 0;

}

說明:特別的,可以把指針當數(shù)組名用。

指針與函數(shù):

編寫一個函數(shù),將三個整型變量排序,并將三者中的最小值賦給第一個變量,次小值賦給第二個變量,最大值賦給第三個變量。

#include<bits/stdc++.h>

using namespace std;

void swap(int *x,int*y){

int t=*x;

*x=*y;

*y=t;

}

void sort(int *x,int *y,int *z){

if(*x>*y)swap(x,y);

if(*x>*z)swap(x,z);

if(*y>*z)swap(y,z);

}

int main(){

int a,b,c;

cin>>a>>b>>c;

sort(&a,&b,&c);

cout<<a<<' '<<b<<' '<<c;

return 0;

}

函數(shù)返回指針:

一個函數(shù)可以返回整數(shù)值,字符值,實型值等,也可以返回指針聯(lián)系的數(shù)據(jù)(即地址)。

定義:

類型名*函數(shù)名(參數(shù)列表);

int *a(int a,int b)

a是函數(shù)名,調(diào)用它后得到一個指向整型數(shù)據(jù)的指針(地址)

注意:在*a的兩側(cè)沒有括號;在a的兩側(cè)分別為*運算符和()運算符,由于()的優(yōu)先級高于*,因此a先與()結(jié)合。在函數(shù)前面有一個*,表示此函數(shù)是返回指針類型的函數(shù)。最前面的int表示返回的指針指向整型變量。

例題:

編寫一個函數(shù),用于在一個包含N個整數(shù)的數(shù)組中找到第一個質(zhì)數(shù),若有則返回函數(shù)的地址,否則返回NULL(空指針)。

#include<bits/stdc++.h>

using namespace std;

int n,a[10001];

bool isprime(int n) {

if(n<2)return false;

if(n==2) return true;

for(int i=2; i<=sqrt(n); i++)

if(n%i==0)

return false;

return true;

}

int *find() {

for(int i=1; i<=n; ++i)

if(isprime(a[i]))

return &a[i];

return NULL;

}

int main() {

cin>>n;

for(int i=1; i<=n; i++)

cin>>a[i];

int *p=find();

if(p!=NULL)

cout<<p<<endl<<*p<<endl;

else

printf("can't find!");

return 0;

}

函數(shù)指針和函數(shù)指針數(shù)組:

使用函數(shù)指針調(diào)用函數(shù)示例:

#include<bits/stdc++.h>

using namespace std;

int t(int a){

return a;

}

int main(){

cout<<t<<endl;//顯示函數(shù)地址

int(*p)(int a);//定義函數(shù)指針變量p

p=t;//將t的地址賦給函數(shù)指針p

cout<<p(5)<<","<<(*p)(10)<<endl;

//輸出p(5)是C++的寫法,(*p)(10)是兼容C

return 0;

}

函數(shù)指針的基本操作:

1.聲明函數(shù)指針

注意:一定要這樣聲明!int (*fp)(int)

2.獲取函數(shù)的地址

3.使用函數(shù)指針來調(diào)用函數(shù)

使用typedef定義函數(shù)指針示例:

#include<bits/stdc++.h>

?using namespace std;?

int sum(int a,int b){?

?return a+b;?

}?

typedef int (*LP)(int,int);?

int main(){?

?LP p=sum;

?cout<<p(2,5);?

?return 0;

?}

在軟件開發(fā)編程中,函數(shù)指針的一個廣泛應(yīng)用是菜單功能函數(shù)的調(diào)用,通常選擇菜單的某個選項都會調(diào)用相應(yīng)的功能函數(shù),而且有些軟件的菜單會根據(jù)情況發(fā)生變化(上下文敏感)如果使用switch/case或if語句處理起來會比較復(fù)雜,不利于代碼的維護,可以考慮使用函數(shù)指針數(shù)組方便靈活的實現(xiàn)。

結(jié)構(gòu)體指針:

當一個指針變量用來指向一個結(jié)構(gòu)體變量時,稱之為結(jié)構(gòu)體指針。

定義:

結(jié)構(gòu)體名*結(jié)構(gòu)體指針變量名

char stu {

char name[20];

char sex;

float score;

} *p;

char stu {

char name[20];

char sex;

float score;

} ;

stu *p;

結(jié)構(gòu)體指針變量必須要賦值后才能使用,賦值是把結(jié)構(gòu)體變量的首地址賦予該指針變量,不能把結(jié)構(gòu)名賦予該指針變量。

如p=&stu是錯誤的;

引用結(jié)構(gòu)體指針變量指向的結(jié)構(gòu)體變量的成員的方法如下:

1.指針名->成員名

2.(*指針名).成員名

示例:

#include<bits/stdc++.h>

using namespace std;

struct stu{

char name[20];

char sex;

float score;

}s[3]={{"xiaoming",'f',356},

{"xiaoliang",'f',350},{"xiaohong",'m',0}};

int main(){

stu*p;

printf("Name? ? ? Sex? ? Score\n");

for(p=s;p<s+3;p++)

printf("%-9s%3c%7d\n",p->name,p->sex,p->score);

return 0;

}

這里p++起到了移動指針的作用

自引用結(jié)構(gòu):

自引用結(jié)構(gòu)是實現(xiàn)動態(tài)數(shù)據(jù)結(jié)構(gòu)的基石,包括動態(tài)的鏈表,堆,棧,樹,無不是自引用結(jié)構(gòu)的具體實現(xiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風(fēng)格之一。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu); ...
    朱森閱讀 3,606評論 3 44
  • 在C語言中,五種基本數(shù)據(jù)類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,993評論 0 2
  • 題目類型 a.C++與C差異(1-18) 1.C和C++中struct有什么區(qū)別? C沒有Protection行為...
    阿面a閱讀 7,885評論 0 10
  • //出自51博客:www.Amanda0928.51.com 第一章 一、選擇題 1.B; (typedef ,t...
    Damongggggg閱讀 11,407評論 0 1
  • 計算機二級C語言上機題庫(南開版) 1.m個人的成績存放在score數(shù)組中,請編寫函數(shù)fun,它的功能是:將低于平...
    MrSunbeam閱讀 6,604評論 1 42

友情鏈接更多精彩內(nèi)容