指針
-
指針是什么
為了了解指針的概念,我們先來(lái)看一個(gè)小故事。
話說(shuō)福爾摩斯派華生到威爾爵士居住的城堡去取回一個(gè)重要的數(shù)據(jù)。白天,在書(shū)房里,威爾爵士當(dāng)著福爾摩斯和華生的面親自將數(shù)據(jù)鎖在了書(shū)柜中編號(hào)為3010的抽屜,用手電筒一照,只見(jiàn)里面有一張紙條,上面赫然寫(xiě)著6個(gè)大字:地址2000。華生眼前一亮,迅速的找到了編號(hào)為2000的抽屜,取出了重要的數(shù)據(jù)123,完成了任務(wù)。
可以用下圖描述幾個(gè)數(shù)據(jù)之間的關(guān)系。
說(shuō)明:
(1)數(shù)據(jù)藏在一個(gè)內(nèi)存地址單元中,地址是2000.
(2)地址2000又由Pointer單元所指認(rèn),Pointer單元的地址為3010.
(3)123的直接地址是2000,123的間接地址是3010,3010中存的是直接地址2000.
(4)稱Pointer單元為指針變量,2000是指針變量的值。
由此可見(jiàn),指針變量是一種特殊的變量,它存放的不是數(shù)據(jù),而是另一種變量的地址。這個(gè)存放數(shù)據(jù)的變量被稱為指針變量所指向的目標(biāo)變量。**由于通過(guò)指針變量中的地址可以直接訪問(wèn)它指向的目標(biāo)變量,常把指針變量簡(jiǎn)稱為指針。
**
指針變量是一種存放地址的特殊變量,其特殊性表現(xiàn)在類(lèi)型和值上。從變量角度講,指針變量也具有變量的要素:
(1)指針變量的命名,與一般變量命名相同,遵循c語(yǔ)言的命名規(guī)則。
(2)指針變量的類(lèi)型,是指針變量所指向的變量的類(lèi)型,而不是自身的類(lèi)型。
(3)在實(shí)驗(yàn)樓的環(huán)境中,指針變量在內(nèi)存中占用8個(gè)字節(jié)。
-
指針變量
通過(guò)指針變量訪問(wèn)整數(shù)類(lèi)型
#include<stdio.h>
int main()
{
int a=100,b=10;
int *pointer_1,*pointer_2; //定義指向整型數(shù)據(jù)的指針變量pionter_1,pionter_2
pointer_1=&a; //把變量a的地址賦給指針變量pointer_1
pointer_2=&b;
printf("a=%d,b=%d\n",a,b);
printf("%p,%p\n",pointer_1,pointer_2); //輸出a和b在內(nèi)存中的地址
printf("*pointer_1=%d,*pointer_2=%d\n",*pointer_1,*pointer_2);//輸出變量a和b的值
return 0;
}
運(yùn)行結(jié)果:
代碼中如果指針打印出為負(fù)數(shù),則需要將打印的類(lèi)型%d調(diào)整為%ld才可以正常輸出。調(diào)整成%p去匹配指針型最佳。
程序分析:
(1)在開(kāi)頭處定義了兩個(gè)指針變量point_1和point_2。但此時(shí)他們并未指向任何一個(gè)變量,只是提供兩個(gè)指針變量,規(guī)定他們可以指向整形變量,至于指向哪一個(gè)整形變量,要在程序語(yǔ)句中指定。程序第6,7兩行的作用就是使point_1指向a,point_2指向b,此時(shí)point_1的值為&a(即a的地址),point_2的值為&b。
(2)第10行輸出*point_1和*point_2的值,其中的“*”表示“指向”。*point_1表示“指針變量point_1所指向的變量”,也就是變量a。*point_2表示“指針變量point_2所指向的變量”,也就是變量b。從運(yùn)行結(jié)果來(lái)看他們也就是100和10.
(3)程序中有兩處出現(xiàn)*point_1和*point_2,但是兩者含義不同。程序第5行的*point_1和*point_2表示定義兩個(gè)指針變量*point_1和*point_2。它們前面的“*”只是表示該變量是指針變量。程序最后10行中的printf函數(shù)中的*point_1和*point_2則表示指針變量point_1和point_2所指向的變量。
- 定義指針變量
定義指針變量的一般形式為
類(lèi)型名 * 指針變量名
如
int * point_1,* point_2;
上面定義的、基類(lèi)型為int的指針變量point_1和point_2只能用來(lái)指向整形的變量。
注意:我們?cè)谶@里再次強(qiáng)調(diào)一遍,在定義指針變量時(shí)要注意,指針變量前面的“*”表示該變量的類(lèi)型為指針型變量。指針變量名是point_1和point_2,而不是*point_1和*point_2。這是和定義整形或?qū)嵭妥兞坎煌?。上面程?行和7行是不能寫(xiě)成* point_1=&a;和 *point_2=&b;的。因?yàn)閍的地址是賦給指針變量point_1,而不是賦值給* point_1(即變量a)。
- 引用指針變量
(1)給指針變量賦值。如:
p=&a; //把a(bǔ)的地址賦給指針變量p
指針變量p的值是變量a的地址,p指向a。
(2)引用指針變量指向的變量。
如果已經(jīng)執(zhí)行p=&p即指針變量p指向了整形變量a,則
printf("%d\n";,*p);其作用是以整數(shù)形式輸出指針變量p所指向的變量的值,即變量a的值。
如果有以下賦值語(yǔ)句:
*p=1;
表示將整數(shù)1賦給p當(dāng)前所指向的變量,如果p指向變量a,則相當(dāng)于把1賦給a,即a=1;.
(3)引用指針變量的值。如:
printf("%o\n";,p);
作用是以八進(jìn)制數(shù)形式輸出指針變量p的值,如果p指向了a,就是輸出了a的地址,即&a。
注意:比較地址運(yùn)算符&和指針運(yùn)算符*的差異:

- 程序舉例
編寫(xiě)程序10-2,輸入兩個(gè)整數(shù),按先大后小的順序輸出a和b。
解題思路:用指針的方法來(lái)處理這個(gè)問(wèn)題。不交換整形變量的值,而是交換兩個(gè)指針變量的值。
編寫(xiě)程序:
#include<stdio.h>
int main()
{
int *p1,*p2,*p,a,b;
printf("please enter two integer number:");
scanf("%d,%d",&a,&b);
p1=&a;
p2=&b;
if(a<b)
{
p=p1;p1=p2;p2=p; //使p1和p2的值互換
}
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
return 0;
}
運(yùn)行結(jié)果:

程序分析
輸入23和42,由于a<b,將p1和p2交換,交換前后的情況如下圖

注意:a和b的值并未交換,他們?nèi)匀槐3衷?,但p1和p2的值改變了。p1的值原來(lái)為&a,后來(lái)變?yōu)?amp;b。這樣輸出* p1和* p2時(shí),實(shí)際上輸出變量b和a的值,所以先輸出42,然后輸出23.
程序中p=p1;p1=p2;p2=p;這個(gè)語(yǔ)句是我們之前使用過(guò)的方法,兩個(gè)變量的值交換要利用第三個(gè)變量。實(shí)際上學(xué)到指針我們可以用更加簡(jiǎn)潔的方法把p=p1;p1=p2;p2=p;改為p1=&b,p2=&a,這樣就不需要定義中間變量p,使得程序更加簡(jiǎn)潔。
#include <stdio.h>
int main()
{
int *p1,*p2,a,b;
a=rand();
b=rand();
p1=&a;
p2=&b;
printf("p1=%p,p2=%p\n",p1,p2);
printf("*p1=%d,*p2=%d\n",*p1,*p2);
printf("a=%d,b=%d\n",a,b);
if (a<b){
p1=&b;
p2=&a;
}
printf("*p1=%d,*p2=%d\n",*p1,*p2);
}
- 指針變量作為函數(shù)參數(shù)
函數(shù)的參數(shù)不僅可以是整形,浮點(diǎn)型等數(shù)據(jù),也可以是指針類(lèi)型。他的作用是將一個(gè)變量的地址傳送到另一個(gè)函數(shù)中。
編寫(xiě)程序10-3,要求實(shí)現(xiàn)的功能和10-2相同,只不過(guò)這次我們采用函數(shù)來(lái)處理,而且用指針類(lèi)型的數(shù)據(jù)做函數(shù)的參數(shù)。
#include<stdio.h>
int main()
{
void swap(int * point_1,int * point_2);
int *p1,*p2,*p,a,b;
printf("please enter two integer number:");
scanf("%d,%d",&a,&b);
p1=&a;
p2=&b;
if(a<b)
swap(p1,p2);
printf("max=%d,min=%d\n",a,b);
return 0;
}
void swap(int * point_1,int * point_2)
{
int temp;
temp=* point_1; //使*p1和*p2互換
* point_1=* point_2;
* point_2=temp;
}
運(yùn)行結(jié)果為:

程序分析:
swap是用戶自定義函數(shù),它的作用是交換兩個(gè)變量(a和b)的值。swap函數(shù)的兩個(gè)形參point_1和point_2是指針變量。程序運(yùn)行時(shí),先執(zhí)行main函數(shù),輸入a和b的值(我們輸入的是23和34),然后將a和b的地址分別賦給int 指針變量p1和p2,使p1指向a,p2指向b,見(jiàn)下圖a,接著執(zhí)行if語(yǔ)句,由于a<b,因此執(zhí)行swap函數(shù)。注意實(shí)參p1和p2是指針變量,在函數(shù)調(diào)用時(shí),將實(shí)參變量的值傳送給形參變量,采取的依然是“值傳遞”方式。因此虛實(shí)結(jié)合后形參point_1的值是&a,point_2的值為&b,見(jiàn)下圖b。這時(shí)p1和point_1都指向變量a,p2和point_2都指向變量b。接著執(zhí)行swap函數(shù)的函數(shù)體,使* point_1和* point_2的值互換,也就是使a和b的值互換。互換后的情況見(jiàn)圖c。函數(shù)調(diào)用結(jié)束后,形參point_1和point_2不復(fù)存在(已釋放),情況如圖d,最后在main函數(shù)中輸出的a和b的值已經(jīng)是經(jīng)過(guò)交換的值。
**使用指針變量作為函數(shù)參數(shù),其本質(zhì)在于通過(guò)指針去直接完成相應(yīng)的操作。而一般的變量作為函數(shù)參數(shù)時(shí),在函數(shù)調(diào)用過(guò)程中,傳入的變量作為臨時(shí)變量存在,在調(diào)用完成后,會(huì)被釋放除函數(shù)返回值外,其他變量均不發(fā)生變化,而指針變量是通過(guò)地址直接進(jìn)行相應(yīng)的操作,調(diào)用完成時(shí)只是釋放指針變量。
**
如將swap函數(shù)改為下面的形式:
void swap(int x ,int y)
{
int temp;
temp=x;
x=y;
y=temp;
}
如果在main函數(shù)中調(diào)用swap函數(shù):
swap(a,b);
在函數(shù)調(diào)用時(shí),a的值傳送給x,b的值傳送給y,執(zhí)行完swap函數(shù)后,x和y的值是互換了,但并未影響到a和b的值。在函數(shù)結(jié)束時(shí),變量x和y釋放了,main函數(shù)中的a和b并未互換。也就是說(shuō),這種單向的值傳遞,形參值的改變不能使實(shí)參的值隨之改變。
為了使在函數(shù)中改變了的變量值能被主調(diào)函數(shù)main所用,不能采取上述的把要改變的變量作為參數(shù)的辦法,而應(yīng)該用指針變量作為函數(shù)參數(shù),在函數(shù)執(zhí)行過(guò)程中使指針變量所指向的變量值發(fā)生變化,函數(shù)調(diào)用結(jié)束后,這些變量值依然保留了下來(lái)。
如果想通過(guò)函數(shù)調(diào)用得到n個(gè)要改變的值,可以這樣做:
(1)在主調(diào)函數(shù)中設(shè)n個(gè)變量,用n個(gè)指針變量指向它們;
(2)設(shè)計(jì)一個(gè)函數(shù),有n個(gè)指針形參,在這個(gè)函數(shù)中改變n個(gè)形參的值;
(3)在主調(diào)函數(shù)中調(diào)用這個(gè)函數(shù),在調(diào)用時(shí)將這n個(gè)指針變量作實(shí)參,將他們的地址傳給該函數(shù)的形參。
(4)在執(zhí)行該函數(shù)的過(guò)程中,通過(guò)形參指針變量,改變它們所指向的n個(gè)變量的值;
(5)主調(diào)函數(shù)中就可以使用這些改變了值的變量了。
通過(guò)指針引用數(shù)組
可以用一個(gè)指針變量指向一個(gè)數(shù)組元素。例如:
int a[10]={1,2,3,4,5,6,7,8,9,10};
int *P;
p=&a[0];
p=&a[0];使指針變量p指向a數(shù)組的第0號(hào)元素。
在c語(yǔ)言中,數(shù)組名(不包括形參數(shù)組名,形參數(shù)組并不占據(jù)實(shí)際的內(nèi)存單元)代表數(shù)組中首元素(即序號(hào)為0的元素)的地址。因此,下面兩個(gè)語(yǔ)句等價(jià):
p=&a[0]; //p的值是a[0]的地址
p=a; //p的值是數(shù)組a首元素(即a[0])的地址
注意:數(shù)組名不代表整個(gè)數(shù)組,只代表數(shù)組首元素的地址。上述p=a;的作用是“把a(bǔ)數(shù)組的首元素的地址賦給指針變量p”,而不是“把數(shù)組a各元素的值賦給p”。
- 引用數(shù)組元素時(shí)指針的運(yùn)算
在指針指向數(shù)組元素時(shí),可以對(duì)指針進(jìn)行以下運(yùn)算:
- 加減一個(gè)整數(shù),如
p+1;或者p-1; - 自加運(yùn)算,如
p++或者++p - 自減運(yùn)算,如
p--或者--p
分別說(shuō)明如下:
(1)如果指針變量p已指向數(shù)組中的一個(gè)元素,則p+1指向同一數(shù)組中的下一個(gè)元素,p-1指向同一數(shù)組中的上一個(gè)元素。
注意: 執(zhí)行p+1時(shí)并不是將p的值(地址)簡(jiǎn)單地加1,而是加上一個(gè)數(shù)組元素所占用的字節(jié)數(shù)。例如,數(shù)組元素是float型,每個(gè)元素占4個(gè)字節(jié),則p+1意味著使p的值加4個(gè)字節(jié),以使它指向下一個(gè)元素。p+1所代表的地址實(shí)際上是p+1*d,d是一個(gè)數(shù)組元素所占的字節(jié)數(shù)。若p的值是2000,則p+1的值不是2001而是2004。
(2)如果p的初值為&a[0],則p+i和a+i就是數(shù)組元素a[i]的地址,或者說(shuō),他們指向a數(shù)組序號(hào)為i的元素,見(jiàn)下圖,這里注意的是a代表數(shù)組首元素的地址,a+1也是地址,它的計(jì)算方法同p+1,即它的實(shí)際地址為a+1*d。例如,p+9和a+9的值是&a[9],它指向a[9]。

(3)*(p+i)和*(a+i)是p+i或a+i所指向的元素,即a[i]。例如*(p+5)和*(a+5)就是a[5],三者等價(jià)。
根據(jù)以上敘述,引用一個(gè)數(shù)組元素,可以用下面兩種方法:
(1)下標(biāo)法,如a[i]的形式;
(2)指針?lè)?/strong>,如*(a+1)或*(p+i)。其中a是數(shù)組名,p是指向數(shù)組元素的指針變量,其初值p=a。
程序舉例
有一個(gè)整型數(shù)組a,有10個(gè)元素,要求輸出數(shù)組中的全部元素。
解題思路:引用數(shù)組中各元素的值有3中方法:
(1)下標(biāo)法,如a[i];
(2)通過(guò)數(shù)組名計(jì)算數(shù)組元素地址,找出元素的值;如*(a+i)
#include<stdio.h>
int main()
{
int a[10];
int i;
printf("please enter 10 integer numbers: ");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++)
printf("%d\t",*(a+i)); //通過(guò)數(shù)組名和元素序號(hào)計(jì)算元素地址,再找該元素
return 0;
}
程序中scanf("%d",&a[i]);用&a[i])代表a[i]的地址,因此也可用a+i代表(數(shù)組名代表數(shù)組中首元素(即序號(hào)為0的元素)的地址)scanf("%d",&a[i]);
(3)用指針變量指向數(shù)組元素。分別寫(xiě)出程序,以便我們比較分析。
p=&a[0]; *(p+i)
int main()
{
int a[10];
int *p,i;
printf("please enter 10 integer numbers: ");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(p=a;p<(a+10);p++) //數(shù)組名代表數(shù)組首個(gè)元素的地址
printf("%d\t",*p); //用指針指向當(dāng)前的數(shù)組元素
return 0;
}
3種方法的比較:
(1)第(1)種和第(2)種方法的執(zhí)行效率是相同的。c編譯系統(tǒng)是將a[i]裝換為*(a+i)處理的,即先計(jì)算元素的地址。因此用第(1)和第(2)種方法找數(shù)組元素費(fèi)時(shí)較多。
(2)第(3)種方法比第(1)、第(2)種方法快,用指針變量直接指向元素,不必每次都重新計(jì)算地址,像p++這樣的自加操作是比較快的。這種有規(guī)律的改變地址值(p++)能大大提高執(zhí)行效率。
(3)用下標(biāo)比較直觀,能直接知道是第幾個(gè)元素。例如,a[5]是數(shù)組中序號(hào)為5的元素(注意序號(hào)是從0算起)。用地址發(fā)或者指針變量的方法不直觀,難以很快的判斷出當(dāng)前處理的是哪一個(gè)元素。例如,方法(3)中,要仔細(xì)分析指針變量p的當(dāng)前指向,才能判斷當(dāng)前輸出的是第幾個(gè)元素。有經(jīng)驗(yàn)的程序猿往往喜歡用第(3)種形式,用p++進(jìn)行控制,程序簡(jiǎn)潔、高效。對(duì)于小白用戶最好還是用第(1)種方式,直觀,不易出錯(cuò)。
注意:在使用指針變量指向數(shù)組元素時(shí),有一些問(wèn)題需要注意:
(1)可以通過(guò)改變指針變量的值指向不同的元素。例如:上述第(3)種方法是用指針變量p來(lái)指向元素,用p++使p的值不斷改變從而指向不同的元素。如果不用p變化的方法而用數(shù)組名a變化的方法行不行呢?假如將上述第(3)中方法中的程序的
for(p=a;p<(a+10);p++)
printf("%d\t",*p);
改為
for(p=a;a<(p+10);a++)
printf("%d",*a);
是不行的。因?yàn)閿?shù)組名a代表數(shù)組首元素的地址,它是一個(gè)指針型常量,它的值在程序運(yùn)行期間是固定不變的。既然a是常量,所以a++是無(wú)法實(shí)現(xiàn)的。
(2)注意指針變量的當(dāng)前值??聪吕?br> 編寫(xiě)程序:
#include<stdio.h>
int main()
{
int *p,i,a[10];
p=a;
printf("please enter 10 integer number:");
for(i=0;i<10;i++)
scanf("%d",p++); //循環(huán)結(jié)束p=&a[10]
for(i=0;i<10;i++,p++)
printf("%d\t",*p);
printf("\n");
return 0;
}
運(yùn)行結(jié)果:

程序分析:顯然輸出的數(shù)值并不是a數(shù)組中各元素的值。需要檢查和分析程序。
可能大家會(huì)覺(jué)得上面的程序沒(méi)有什么問(wèn)題,即使已被告知此程序有問(wèn)題,還是找不出問(wèn)題出在哪里。問(wèn)題出在指針變量p的指向。指針變量p的初始值為a數(shù)組首元素的地址,但經(jīng)過(guò)第一個(gè)for循環(huán)讀入數(shù)據(jù)后,p已指向a數(shù)組的末尾。因此,在執(zhí)行第2個(gè)for循環(huán)時(shí),p的起始值不是&a[0]了,而是a+10。由于執(zhí)行第2個(gè)for循環(huán)時(shí),每次要執(zhí)行p++,因此p指向的是a數(shù)組下面的10個(gè)存儲(chǔ)單元。
解決這個(gè)問(wèn)題的方法只需要在第2個(gè)for循環(huán)之前加一個(gè)賦值語(yǔ)句:
p=;
使p的初始值重新等于&a[0],這樣的結(jié)果就對(duì)了。
利用指針引用數(shù)組元素,比較方便靈活,有不少技巧。在專業(yè)人員中常喜歡用一些技巧,以使程序簡(jiǎn)潔。我們來(lái)分析下面幾種情況
(1)p++使p指向下一個(gè)元素a[1].然后若在執(zhí)行* p,則得到下一個(gè)元素a[1]的值。
p++;
* p;
(2)由于++和*同優(yōu)先級(jí),結(jié)合方向?yàn)樽杂叶?,因此它等價(jià)于*(p++)。先引用p的值,實(shí)現(xiàn)*p的運(yùn)算,然后再使p自增1.
*p++;
(3)*(p++)與*(++p)作用是否相同?答案肯定是不相同的。前者是先取*p的值,然后使p加1.后者是先使p加1,再取*p。
程序分析:這個(gè)程序我們可以做一些改動(dòng)。將函數(shù)change中的形參x改成指針變量。相應(yīng)的實(shí)參仍為數(shù)組名a(即數(shù)組a首元素的地址),將它傳給形參指針變量x,這時(shí)x就指向a[0]。x+m是a[m]元素的地址。設(shè)j和i以及p都是指針變量,用它們指向有關(guān)元素。i的初值x,j的初值為x+n-1,見(jiàn)下圖。使得*i與*j交換就是a[i]和a[j]交換。

#include<stdio.h>
void exchange(int *x,int y);
int main()
{
int i,y,x[10];
for(i=0;i<10;i++)
{
x[i]=rand();
printf("x[%d]=%d\n",i,x[i]);
}
exchange(x,10);
for(i=0;i<10;i++)
printf("x[%d]=%d\n",i,x[i]);
return 0;
}
void exchange (int *x,int y)
{
int temp,*p,*i,*j, m=(y-1)/2;;
i=x;j=x+y-1;p=x+m;
for(;i<=p;i++,j--) // i++=&x[++];
{
temp=*i;
*i=*j;
*j=temp;
}
}
歸納分析:如果有一個(gè)實(shí)參數(shù)組,要想在函數(shù)中改變數(shù)組中的元素的值,實(shí)參和形參的對(duì)應(yīng)關(guān)系有以下4種情況。
(1)形參和實(shí)參都用數(shù)組名,例如:
int main()
{
int a[10];
.
.
.
f(a,10);
}
int f(int x[],int n)
{
.
.
.
}
由于形參數(shù)組名x接收了實(shí)參數(shù)組首元素a[0]的地址,因此可以認(rèn)為在函數(shù)調(diào)用期間,形參數(shù)組與實(shí)參數(shù)組共用一段內(nèi)存單元,這種形式比較好理解。
(2)實(shí)參用數(shù)組名,形參用指針變量。例如:
int main()
{
int a[10];
.
.
.
f(a,10);
}
void f(int *x,int n)
{
.
.
.
}
實(shí)參a為數(shù)組名,形參x為int *型的指針變量,調(diào)用函數(shù)開(kāi)始后,形參x指向a[0],即x=&a[0],通過(guò)x的值的改變,可以指向a數(shù)組的任一元素。例11-2就屬于此類(lèi)。
(3)實(shí)參形參都用指針變量。例如:
int main()
{
int a[10],*p=a; //p=&a[0]
.
.
.
f(p,10);
.
.
.
}
void f(int *x,int n)
{
.
.
.
}
實(shí)參p和形參x都是(int *)型的指針變量。
先使實(shí)參指針變量p指向數(shù)組a[0],p的值是&a[0]。然后將p的值傳給形參指針變量x,x的初始值也是&a[0],通過(guò)x的值的改變可以使x指向數(shù)組a的任意元素。
(4) 實(shí)參為指針變量,形參為數(shù)組名。例如:
int main()
{
int a[10],*p=a;
.
.
.
f(p,10);
}
void f(int x[],int n)
{
.
.
.
.
}
實(shí)參p為指針變量,它指向a[0]。形參為數(shù)組名x,編譯系統(tǒng)把x作為指針變量處理,今將a[0]的地址傳給形參x,使x也指向a[0]。也可以理解為形參數(shù)組x和a數(shù)組共用同一段內(nèi)存單元。在執(zhí)行過(guò)程中可以使x[i]的值變化,而x[i]就是a[i]。這樣,main函數(shù)可以使用變化了的數(shù)組元素的值。
參考文獻(xiàn)
【1】 實(shí)驗(yàn)樓c語(yǔ)言入門(mén)教程 指針(1) (https://www.shiyanlou.com/courses/running)