1. 程式人生 > >C/C++基本語法,入門及提高(1)

C/C++基本語法,入門及提高(1)

-- 學習C++可分為4個層次:
  第一層次,C++基礎:挑選一本入門書籍,如《C++ Primer》、《C++大學教程》、或Stroustrup撰寫的經典《C++程式設計語言》或他一年半前的新作《C++程式設計原理與實踐》,而一般C++課程也止於此,另外《C++ 標準程式庫》及《The C++ Standard Library Extensions》可供參考;
  第二層次,正確高效地使用C++:此層次開始必須自修,閱讀過《(More)Effective C++》、《(More)Exceptional C++》、《Effective STL》及《C++程式設計規範》等,才適宜踏入專業C++開發之路;
  第三層次,深入瞭解C++:關於全域性問題可讀《深入探索C++物件模型》、《Imperfect C++》、《C++沉思錄》、《STL原始碼剖析》,要挑戰智商,可看關於模版及模版超程式設計的書籍如《C++ Templates》、《C++設計新思維》、《C++模版超程式設計》;
  第四層次,研究C++:閱讀《C++語言的設計和演化》、《程式設計的本質》(含STL設計背後的數學根基)、C++標準檔案《ISO/IEC 14882:2003》、C++標準委員會的提案書和報告書、關於C++的學術文獻。
  讀透《c++ primer》,啃一遍《linux核心原始碼整體》?

  Java和C++的一個不同點是, 在Java中不可能直接操作物件本身,所有的物件都由一個引用指向,必須通過這個引用才能訪問物件本身,包括獲取成員變數的值,改變物件的成員變數,呼叫物件的方法等。而在C++中存在引用,物件和指標三個東西,這三個東西都可以訪問物件。其實,Java中的引用和C++中的指標在概念上是相似的,他們都是存放的物件在記憶體中的地址值,只是在Java中,引用喪失了部分靈活性,比如Java中的引用不能像C++中的指標那樣進行加減運算。 

C++知識框架體系圖- http://blog.csdn.net/payshent/article/details/55254574
C++入門簡單例項- http://blog.csdn.net/aheroofeast/article/details/6856943
c++專案(圖書館管理系統,詳細簡單適合初學者)- http://download.csdn.net/detail/u011706736/7998273
C入門之簡單的學生管理系統- http://blog.csdn.net/way_ping_li/article/details/8040959
鏈式棧的實現(C實現)- http://blog.csdn.net/gjggj/article/details/72938440
C-Free 5 免安裝註冊版-

http://download.csdn.net/download/u4110122855/5265901 ,MinGW離線壓縮包

C語言的面向過程程式設計,C++的面向物件程式設計。

> C/C++語法及特性, .h標頭檔案與.c原始檔

  .h檔案作為介面存在的。所謂介面就是指型別定義、變數宣告、函式宣告等等,基本上不會在.h裡面放置函式實現。.c裡面才真正實現函式。然後面向介面程式設計。struct結構變數(結構體)也宣告在.h檔案中、
 如果其可見性超出一個.c檔案,那麼應當放入.h中,如果只是某個.c裡需要這麼一個結構作為輔助,直接放入這個.c中更好一些。 .h的影響範圍更大,如果有修改的話所有依賴的檔案都要重新編譯,會影響編譯效率,主要就是基於這個考慮
 ——提供給別人的介面越隱藏細節,介面越簡單,耦合越少,越容易修改。但是把結構體定義在.c檔案使用的人就不能在棧上分配記憶體了。
 ——放c還是h取決於該結構是否要暴露給其他c,原則就是能放c絕不放h,但一般來說既然定義了結構,多半還是要暴露出來的.
-- 綜合來說,


1.全域性變數一般都用static包裹,然後提供配套的set和get介面給別人呼叫,放在.c檔案中。
2.結構體、列舉、巨集(名字儘量複雜點,避免和別人的巨集重複)、定義放在.h中,可以讓別人include,提高程式碼的複用率。

> C/C++ 結構化程式設計,面向物件程式設計
資料型別、運算子與表示式(常量與變數,整形 字元型別,+-*/)
順序程式設計(1.順序結構:2.選擇(判斷)結構:3.迴圈結構,賦值 putchar getchar printf scanf)
順序結構,選擇(判斷)結構(if switch),迴圈結構(goto while for break continue)
一維、二維陣列,字元陣列,字串和字串結束標誌
函式,內部函式 外部函式(全域性變數區域性變數,auto static register extern )
預處理命令(帶巨集和不帶巨集,檔案包含)

指標:一維指標 二維指標 多維指標

C語言位運算子:與、或、異或、取反、左移和右移- http://www.cnblogs.com/yezhenhan/archive/2011/11/06/2238452.html

> * 或&用法

&和*在C語言中的含義:& 取地址,* 取值
&x是對x變數取地址,也就是返回的是x的地址。 int *i;這裡面的*說明變數i是一個指標,存的是一個地址。
而printf("%d\n",*i);這裡面的*的作用是返回指標i所指的變數。
  & 是取地址符號,既取得某一個變數的地址,如:&a;而* 是指標運算子(乘號就不說了),可以表示一個變數是指標型別搜尋;也可以表示一個指標變數的所指向的儲存單元,可以獲取某個地址儲存的值。
  * 兩種,一種乘法 一種用於表示指標的內容;&兩種 一種位與運算,一種是取變數地址.
-- 三個函式只是形參不一樣而已:
 f(int s)  //形參是s,int s表示:函式自己開設一個變數s存放傳入的整型數值,以便函式內使用;
 f(int *s) //形參是指標,int *s表示:函式開設一個指標變數s,存放傳入的某變數的地址,函式內用*s的方法可訪問這個變數單元,函式結束這個變數被捨棄;
 f(int &s) //形參是引用,int &s表示:在呼叫函式時所給出的變數比如int a; f(a);這個變數在子程式中與變數a對應,改變s的值如同修改呼叫者變數a一樣,視作同一單元的操作,也就是子程式通過變數名s直接訪問呼叫者變數a。

#include<stdio.h>
int main()
{
    char  const * keyword[]={
        "1111",
        "2222",
        "3333",
        "4444",
        NULL};
    char **p=(char**)keyword;
    while(*p!=NULL)
    {
        puts(*p++);
    }
    return 0;
}

> 程式1
#include <stdio.h>  
int main(int argc, const char * argv[]) { 
  int b = 20;
  int *a = 0; 
  printf("%d,\n",&b); //取變數b的地址
  printf("%d,\n",a);  //取變數a的值
  return 0;  


> 程式2  *、&用法介紹
#include <stdio.h>
int find(int *a);
main(){
    int b = 1;
    int wait, test;
    test = find(&b);//int* a = &b,建立了一個新的指向b的整型指標a作為find函式範圍內的區域性變數。
    printf("記憶體地址為:%d\n",&test);
    printf("記憶體地址為:%d\n",test);
    scanf("%d", &wait);
    
}
int find(int *a){
    return *a;
}

> 程式3
#include <stdio.h>
#include <string.h>
int main(){
  int a = 97;
  char ch = *(char *)&a; //*(char *) &a: 含義就是先取a的首地址,然後強制轉換為char指標型別,然後取該指標的值
  printf("ch is %c\n",ch);
}

> 程式4  &作為取地址操作時,其行為結果是在編譯時就被確定的;而*,解引用操作(或取內容)操作,其行為結果只能在執行時才可被確定
//&作為取地址操作,當且僅當&後面跟著的是變數或函式識別符號。所以這裡的&表示脫去解引用
#include "stdio.h"
int main(void)  {  
    int a = 0; // &a = 0x0012ff60  
    printf("%d,\n",&a);
    //*(int*)&a表示取變數a的內容
    int *p = &*(int*)&a;//這裡的&不是取地址,因為一個*(int*)0x0012ff60不是變數,它是沒有地址的 
    printf("The value is: %d\n", *p);  
    return 0;  
}

> 程式4,上面程式4的變樣
#include "stdio.h"
int main(void) 

    int a = 0;
    int *p = &*&*&a;
    printf("The value is: %d\n", *p);
    return 0; 
}

> 程式5 ,在C++中,&還可以表示引用,
#include "iostream" 
using namespace std;
int main(void){ 
    int a = 0;
    int &r = a;
    cout << "The value is: " << r << endl;
    return 0; 
}

> C的資料型別及基本資料型別printf()對應格式

  C語言的執行過程:源程式---編譯--連結--執行
編譯:將源程式編譯生成 .o的目標檔案(快捷方式 command +b);
連結:連結庫檔案,將目標檔案生成 .out的可執行檔案。(快捷方式 command +r)。

資料型別   關鍵字:void int  char float double (5)
型別修飾符關鍵字:short long signed unsigned(4)
複雜型別    關鍵字:struct  enum    union(3) 
流程控制      關鍵字: for break continue do while   if else  goto  suitch case default  return(12)
儲存型別     關鍵字:auto extern  static  regist ( 4)
其他            關鍵字:const sizeof  typedel    volatile(4)

常用基本資料型別佔用空間(64位機器為例)int* p2=(int*)malloc(sizeof(int));
char:1個位元組 ; int:4個位元組; float:4個位元組; double:8個位元組

-- C語言的基本語法- http://blog.csdn.net/ww231147/article/details/49837561
1 整型,int, 使用格式為%d;
2 短整型,short, 使用格式為%h;
3 長整型,long, 使用格式為%ld;
4 字元型,char, 使用格式為%c;
5 字元指標型,char *, 使用格式為%s;
6 單精度浮點型,float, 使用格式為%f;
7 雙精度浮點型,double, 使用格式為%lf。
%d 十進位制有符號整數 
%u 十進位制無符號整數 
%f 浮點數 
%s 字串 
%c 單個字元 
%p 指標的值 
%e 指數形式的浮點數 
%x, %X 無符號以十六進位制表示的整數 
%0 無符號以八進位制表示的整數 
%g 自動選擇合適的表示法 
%3d 表示輸出3位整型數, 不夠3位右對齊。 
%9.2f 表示輸出場寬為9的浮點數, 其中小數位為2, 整數位為6,小數點佔一位, 不夠9位右對齊。 
%8s 表示輸出8個字元的字串, 不夠8個字元右對齊。 

-- c語言中基本資料型別printf()對應格式- http://www.cnblogs.com/xiaobaizhu/articles/2783868.html
#include <stdio.h> 
#include <string.h> 
int main() { 
  char c, s[20], *p,ccc; 
  int b= 12;
  int a=1234, *i; 
  float f= 3.141592653589; 
  double x= 0.12345678987654321; 
  p="How do you do"; 
  strcpy(s, "Hello, Comrade"); 
  i= &b;//TODO
  c='\x41'; 
  printf("a=%d\n", a); /*結果輸出十進位制整數a=1234*/ 
  printf("a=%6d\n", a); /*結果輸出6位十進位制數a= 1234*/ 
  printf("a=%06d\n", a); /*結果輸出6位十進位制數a=001234*/ 
  printf("a=%2d\n", a); /*a超過2位, 按實際值輸出a=1234*/ 
  printf("*i=%4d\n", *i); /*輸出4位十進位制整數*i= 12*/ 
  printf("*i=%-4d\n", *i); /*輸出左對齊4位十進位制整數*i=12*/ 
  printf("i=%p\n", i); /*輸出地址i=06E4*/ 
  printf("f=%f\n", f); /*輸出浮點數f=3.141593*/ 
  printf("f=6.4f\n", f); /*輸出6位其中小數點後4位的浮點數 f=3.1416*/ 
  printf("x=%lf\n", x); /*輸出長浮點數x=0.123457*/ 
  printf("x=%18.16lf\n", x);/*輸出18位其中小數點後16位的長浮點 數x=0.1234567898765432*/ 
  printf("c=%c\n", c); /*輸出字元c=A*/ 
  printf("c=%x\n", c); /*輸出字元的ASCII碼值c=41*/ 
  printf("s[]=%s\n", s); /*輸出陣列字串s[]=Hello, Comrade*/ 
  printf("s[]=%6.9s\n", s);/*輸出最多9個字元的字串s[]=Hello, Co*/ 
  printf("s=%p\n", s); /*輸出陣列字串首字元地址s=FFBE*/ 
  printf("*p=%s\n", p); /* 輸出指標字串p=How do you do*/ 
  printf("p=%p\n", p); /*輸出指標的值p=0194*/ 
  return 0; 

> const和define關鍵字宣告常量及指標

C語言中我們可以使用const和define關鍵字宣告常量,所謂常量就是指值不能修改的量。如下面的例子所示:
1> int const a; const int a; //這兩條語句都把a宣告為一個常量(整數),它的值不能被修改。
2> 在宣告時對其進行初始化 int const a = 15;  #define PI 3.14  // 定義了一個常量為3.14的巨集PI,
3> int *pi; pi是一個普通的指向整形的指標。
4> 而變數int const *pci;則是一個指向整型常量的指標。你可以修改指標的值,但你不能修改它所指向的值
5> int *const cpi;則宣告cpi為一個指向整型的常量指標。此時指標是常量,它的值(記憶體值?)無法修改,但你可以修改它所指向的整型的值。
6> int const *const cpci; 無論是指標本身還是它所指向的值都是常量,不允許修改。

>  .與->的區別?
 ->在C語言中稱為間接引用運算子,是二目運算子,優先順序同成員運算子“.”。
 用“.”的話,只需要宣告一個結構體。格式是,結構體型別名+結構體名。然後用結構體名加“.”加域名就可以引用域 了。因為自動分配了結構體的記憶體。如同 int a;一樣。用->的話,要宣告一個結構體的指標,還要手動開闢一個該結構體的記憶體,然後把返回的指標給宣告的結構體指標。才能用->正確引用。否則記憶體中只分配了指標的記憶體,沒有分配結構體的記憶體,想要的結構體實際上是不存在。這時候用->引用自然出錯了,因為沒有結構體,自然沒有結構體的域了。
 "."我直接讀做"的”。->我讀作"指向的結構體的"。
 存的地方不同吧,用.的是在棧裡的區域性變數,區域性變數在方法執行完後會清空棧,所以不用free垃圾回收,這時整修結構體都在棧中。而->是在棧中聲明瞭一個指標,指向堆中的結構體,這樣方法執行完後只會清空棧中的指標,所以需要手動free清空堆中的結構體。

p->a,其中p是指向一個結構體的指標,a是這個結構體型別的一個成員。表示式p->a引用了指標p指向的結構體的成員a。例如:
struct T{
   int a;
   char b;
}s;
struct T* p=&s;
那麼,p->a相當於s.a。顯然,有個等價寫法:(*p).a,和p->a完全等效。
連結串列指標是C語言的一個難點,但也是重點,學懂了非常有用。要仔細講就必須先講變數、指標。

> C++:與::的區別?http://blog.sina.com.cn/s/blog_6754000a0101a8cf.html
1.冒號(:)用法
(1)表示機構內位域的定義(即該變數佔幾個bit空間)
typedef struct _XXX{
  unsigned char a:4;
  unsigned char c;
} ; XXX
(2)建構函式後面的冒號起分割作用,是類給成員變數賦值的方法,初始化列表,更適用於成員變數的常量const型。
struct _XXX{
  _XXX() : y(0xc0) {}
};
(3) public:和private:後面的冒號,表示後面定義的所有成員都是公有或私有的,直到下一個"public:”或"private:”出現為止。"private:"為預設處理。
(4)類名冒號後面的是用來定義類的繼承。
class 派生類名 : 繼承方式 基類名{
  派生類的成員
};
繼承方式:public、private和protected,預設處理是public。

2.雙冒號(::)用法
(1)表示“域操作符”
例:聲明瞭一個類A,類A裡聲明瞭一個成員函式void f(),但沒有在類的聲明裡給出f的定義,那麼在類外定義f時, 
就要寫成void A::f(),表示這個f()函式是類A的成員函式。
(2)直接用在全域性函式前,表示是全域性函式 
例:在VC裡,你可以在呼叫API 函式裡,在API函式名前加::
(3)表示引用成員函式及變數,作用域成員運算子
例:System::Math::Sqrt() 相當於System.Math.Sqrt()

VC中如下:
 ::是C++裡的“作用域分解運算子”。比如聲明瞭一個類A,類A裡聲明瞭一個成員函式voidf(),但沒有在類的聲明裡給出f的定義,那麼在類外定義f時,就要寫成voidA::f(),表示這個f()函式是類A的成員函式。
 :: 一般還有一種用法,就是直接用在全域性函式前,表示是全域性函式。當類的成員函式跟類外的一個全域性函式同名時,考試,大提示在類內定義的時候,打此函式名預設呼叫的是本身的成員函式;如果要呼叫同名的全域性函式時,就必須打上::以示區別。比如在VC裡,你可以在呼叫API函式時,在API函式名前加::。

> C的IDE 編譯器
愛手工用手工,愛makefile用makefile,愛ide用ide。
在Windows平臺下,用MinGW + EditPlus。vim gcc gdb.
編輯好的原始碼是怎麼變成可執行檔案的,什麼前處理器、編譯器、連結器、執行時庫一概不知
我的IDE使用路徑提供參考: Turbo C,  Borland C++,  VC++,  Eclipse, Emacs + Toolchains
linux下沒什麼ide可言,就是主要需要一個文字編輯器。gedit,vim都可以用。用慣了windows的人肯定更習慣用gedit編輯程式碼。Visual Studio自帶的
Linux Platform:
Editor: Vim7.4;
tag: ctags + cscope;
Compiler: gcc4.9, clang-3.5;
Debugger: gdb, lldb-3.5
IDE: vim, emacs, slickedit, vc,source insight, codeblock, ultraedit, eclipse, 太多了。編譯器,主要就是vc, gcc, llvm
在windows平臺,初學者還是用C-free吧,簡單小巧容易上手,當然做專案肯定是不行的,水平提高了那也只能用visual studio。Linux平臺推薦vim+gcc+gdb,eclipse C++也不錯。

> 指標的指標,C;C語言動態和靜態記憶體分配與回收???
-- 記憶體分配方式:  
  (1) 從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個執行期間都存在。例如全域性變數,static變數。  
  (2) 在棧上建立。在執行函式時,函式內部區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放,棧記憶體分配運算內置於處理  器的指令集中,效率很高,但是分配的記憶體容量有限。  
  (3) 從堆上分配。亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多的記憶體,程式設計師自己負責在什麼時候free或delete釋放記憶體。動態記憶體  的生存期有程式設計師決定,使用非常靈活,但問題也最多。

//c語言靜態記憶體分配,靜態記憶體是程式編譯執行後系統自動分配,由系統自動釋放,靜態記憶體是棧分配的。
#include <stdio.h>  
#include <stdlib.h>    
void func(int** address )  {   
    //定義int型別的i變數,並賦值100  
    int i = 100;  
    //把i對應的地址賦值給iPoint變數  
    *address = &i;  
}  
int main(int argc, char *argv[])  {   
    //定義int型別的一級指標變數iPoint  
    int* iPoint;  
    func(&iPoint);  
    printf("*iPoint==%d\n",*iPoint); //列印值為100  
    printf("*iPoint==%d\n",*iPoint); //列印值為-2 (變為垃圾值)  
  
    system("pause");  
    return 0;  


//c語言動態記憶體分配,動態記憶體是開發者手動去分配的,是堆分配的。
#include <stdio.h>  
#include <stdlib.h>    
void func(int** address )  {     
    int i = 100;  
    int* temp;  
    //malloc(int)  --記憶體地址  此方法返回的是記憶體地址  
    //temp=(int *)malloc (sizeof (int))與temp=malloc (sizeof (int))是有區別的 
    temp = (int*)malloc(sizeof(int)); //malloc(sizeof(int)) 
    //把i對應的值,賦值給temp地址對應的值  
    *temp = i;  
    //把address對應的地址對應的值修改成temp  
    *address = temp;  
    //free(temp); //釋放記憶體  
}   
int main(int argc, char *argv[]) {   
    //定義int型別的一級指標變數iPoint  
    int* iPoint;  
    func(&iPoint);  
    printf("*iPoint==%d\n",*iPoint); //列印值為100  
    printf("*iPoint==%d\n",*iPoint); //列印值為100 (記憶體沒有被回收)  
  
    system("pause");  
    return 0;  
}

  c語言提供記憶體動態分配的函式有:malloc、calloc、realloc,在使用這些函式時必須包含其標頭檔案,分別為:<malloc.h>、<stdlib.h>、<alloc.h>。
  在C++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。
malloc與free是C++/C語言的標準庫函式,new/delete是C++的運算子。它們都可以用於申請動態記憶體和釋放記憶體。
對於非內部資料型別物件而言,光用malloc/free無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行解構函式。由於malloc/free是庫函式而不是運算子,不在編譯器控制權限之內,不能夠把執行建構函式和解構函式的任務強加於malloc/free.
   堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如區域性變數的分配。動態分配由函式malloc進行分配。不過棧的動態分配和堆不同,他的動態分配是由編譯器進行釋放,無需我們手工實現。全域性變數和靜態變數分配在靜態資料區,本地變數分配在動態資料區,即堆疊中。

> 一級指標和二級指標

  void fun(int *p),指標引數p的副本為_p,編譯器使_p=p,_p和p指向相同的記憶體空間,如果在函式內修改了_p所指向的內容,就會導致p的內容也做相應的改變;但如果在函式內_p申請了新的記憶體空間或者指向其他記憶體空間,則_p指向了新的記憶體空間,而p依舊指向原來的記憶體空間,因此函式返回後p還是原來的p。這樣的話,不但沒有實現功能,反而每次都申請新的記憶體空間,而又得不到釋放,因為沒有將該記憶體空間的地址傳遞出來,容易造成記憶體洩露。
  void fun(int **p),如果函式引數是指標的地址,則可以通過該引數p將新分配或新指向的記憶體地址傳遞出來,這樣就實現了有效的指標操作。
 -- 指標也是值傳遞
一級指標所關聯的是其值(一個地址)名下空間裡的資料,一級指標:即我們一般說的指標,就是記憶體地址;
二級指標又分為指向指標變數的指標和指向陣列的指標,二級指標:指向指標的指標,就是地址的地址;

 -- 陣列指標與指標陣列(一些notes):
陣列指標:int(*p)[4] 指向陣列p的指標 a pointer to an array
指標陣列:int *p[4] or int *(p[4]) 陣列p中元素都為int型指標array of pointers,[ ]的優先順序高於*
#include <stdio.h>  
#include <stdlib.h>   
int main(){
 int a= 1;
 int *p=&a;
 int **q=&p;
 printf("*iPoint==%d\n",*p); //列印值為1
printf("*iPoint==%d\n",&a); //列印值為地址值   
 printf("*iPoint==%d\n",**q); //列印值為1 
 return 0;
}

 --在傳遞一級指標時,只有對指標所指向的記憶體變數做操作才是有效的;
在傳遞二級指標時,只有對指標的指向做改變才是有效的;
#include<stdio.h>
 void  fun(int  *p){
    int  b=100;
    p=&b;
}
int main(){
    int  a=10;
    int  *q;
    q=&a;
    printf("%d\n",*q);
    fun(q);
    printf("%d\n",*q);
    return  0;
}//執行結果:10  10

#include<stdio.h>
void  fun(int  **p){
    int  b=100;
    *p=&b;
}
int main(){
    int  a=10;
    int  *q;
    q=&a;
    printf("%d\n",*q);
    fun(&q);
    printf("%d\n",*q);
    return  0;
}//執行結果:10  100

二級指標在連結串列中的使用:在連結串列或者樹的操作中,也需要用到二級指標,
比如建立連結串列的頭指標:
 在初始化連結串列函式中,傳入頭指標,並在函式中為該指標分配空間,此時就應該使用二級指標,如void initLinklist(Node **head);
 而在新增刪除結點的過程中,我們並沒有改變函式引數指標的指向,而是通過傳入的指標如Node *head,找到要刪除結點的位置,並未對該指標做改變,因此退出函式後,該指標無影響。
  
 一級指標存放變數的地址,指向的值是變數的內容。如int* p={1,2,3}, p=陣列的首地址,*p=陣列的第一個值;
 二級指標存放一級指標的地址,指向一級指標。如int*p ={1,2,3}, int**pp=&p,pp=指標p的首地址,*pp=陣列的首地址,**pp=陣列第一個值1。
 在作為引數傳遞時什麼時候用一級指標,什麼時候用二級指標?
 一級指標作為引數傳遞時,由實參賦予形參對其指向內容的修改的能力,但是一旦修改形參的指向使其指向其它地方,則這種改變不會返回給實參,此時若要使實參的指標指向地址(指標本身的值)發生改變則使用二級指標。