亚洲国产日韩欧美在线a乱码,国产精品路线1路线2路线,亚洲视频一区,精品国产自,www狠狠,国产情侣激情在线视频免费看,亚洲成年网站在线观看

C語言指針的傳遞

時間:2025-12-17 08:02:04 C語言 我要投稿

C語言指針的傳遞

  傳遞指針可以讓多個函數(shù)訪問指針?biāo)玫膶ο,而不用把對象聲明為全局可訪問,要在某個函數(shù)中修改數(shù)據(jù),需要用指針傳遞數(shù)據(jù),當(dāng)數(shù)據(jù)是需要修改的指針的時候,就要傳遞指針的指針,傳遞參數(shù)(包括指針)的時候,傳遞的是它們的值,也就是說,傳遞給函數(shù)的是參數(shù)值的一個副本,本文將討論C語言中指針傳遞給函數(shù)與從函數(shù)返回指針的內(nèi)容。

  用指針傳遞數(shù)據(jù)

  用指針傳遞數(shù)據(jù)的一個主要原因是函數(shù)可以修改數(shù)據(jù)

  下面的代碼實現(xiàn)一個常見的交換函數(shù):

  #include

  void swap(int* a, int* b)

  {

  int tmp;

  tmp = *a;

  *a = *b;

  *b = tmp;

  }

  int main()

  {

  int m, n;

  m = 5;

  n = 10;

  printf("m=%d, n=%d ",m, n);

  swap(&m, &n);

  printf("m=%d, n=%d ",m, n);

  return 0;

  }

  如果不通過指針傳遞參數(shù),交換就不會發(fā)生,具體的原理參見任何一本C語言教材

  傳遞指向常量的指針

  傳遞指向常量的指針是C中常用的技術(shù),效率很高,因為避免某種情況下復(fù)制大量內(nèi)存,如果不希望數(shù)據(jù)被修改,就要傳遞指向常量的指針

  我們不能修改通過指向常量的指針傳進(jìn)來的值:

  #include

  void passconstant(const int* num1, int*num2)

  {

  *num2 = *num1;

  }

  int main()

  {

  const int a = 100;

  int b = 5;

  printf("a=%d, b=%d ",a, b);

  passconstant(&a, &b);

  printf("a=%d, b=%d ",a, b);

  return 0;

  }

  下面的代碼會產(chǎn)生錯誤(第二個形參和實參的類型不匹配,試圖修改第一個參數(shù)所引用的常量):

  #include

  void passconstant(const int* num1, int* num2)

  {

  *num1 = 100;

  *num2 = 200;

  }

  int main()

  {

  const int limit = 100;

  passconstant(&limit, &limit);

  return 0;}

  C語言中堆和棧的區(qū)別

  預(yù)備知識—程序的內(nèi)存分配

  一個由C編譯的程序占用的內(nèi)存分為以下幾個部分:

  1、棧區(qū)(stack)— 由編譯器自動分配釋放 ,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

  2、堆區(qū)(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結(jié)束時可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。

  3、全局區(qū)(靜態(tài)區(qū))(static),全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域, 未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。程序結(jié)束后由系統(tǒng)釋放。

  4、文字常量區(qū) —常量字符串就是放在這里的, 程序結(jié)束后由系統(tǒng)釋放

  5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。

  下面就說說C語言程序內(nèi)存分配中的堆和棧,內(nèi)存分配一般情況下程序存放在Rom或Flash中,運(yùn)行時需要拷到內(nèi)存中執(zhí)行,內(nèi)存會分別存儲不同的信息,如下圖所示:

  內(nèi)存中的棧區(qū)處于相對較高的地址以地址的增長方向為上的話,棧地址是向下增長的,棧中分配局部變量空間,堆區(qū)是向上增長的用于分配程序員申請的內(nèi)存空間。另外還有靜態(tài)區(qū)是分配靜態(tài)變量,全局變量空間的;只讀區(qū)是分配常量和程序代碼空間的;以及其他一些分區(qū)。

  堆棧的區(qū)別,來看一個經(jīng)典例子:

  #include

  #include

  int a = 0; /pic/p>

  char *p1; /pic/p>

  int main()

  {

  int b; /pic/p>

  char s[] = "abc"; /pic/p>

  char *p2; /pic/p>

  char *p3 = "123456"; /pic/p>

  static int c =0; /pic/p>

  p1 = (char*)malloc(10); /pic/p>

  p2 = (char*)malloc(10);

  return 0;

  }

  不知道你是否有點明白了,堆和棧的第一個區(qū)別就是申請方式不同:棧(英文名稱是stack)是系統(tǒng)自動分配空間的,例如我們定義一個 char a;系統(tǒng)會自動在棧上為其開辟

  空間。而堆(英文名稱是heap)則是程序員根據(jù)需要自己申請的空間,例如malloc(10);由于棧上的空間是自動分配自動回收的,所以棧上的數(shù)據(jù)的生存周期只是在函數(shù)的運(yùn)行過程中,運(yùn)行后就釋放掉,不可以再訪問。而堆上的數(shù)據(jù)只要程序員不釋放空間,就一直可以訪問到,不過缺點是一旦忘記釋放會造成內(nèi)存泄露。還有其他的一些區(qū)別網(wǎng)上的總結(jié)的不錯這里轉(zhuǎn)述一下:

  1.申請后系統(tǒng)的響應(yīng)

  棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報異常提示棧溢出。

  堆:首先應(yīng)該知道操作系統(tǒng)有一個記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請時,會遍歷該鏈表,尋找第一個空間大于所申請空間的堆結(jié)點,然后將該結(jié)點從空閑結(jié)點鏈表中刪除,并將該結(jié)點的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的 語句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點的大小不一定正好等于申請的大小,系統(tǒng)會自動的將多余的那部分重新放入空閑鏈表中,也就是說堆會在申請后還要做一些后續(xù)的工作這就會引出申請效率的問題。

  2.申請效率的比較

  棧:由系統(tǒng)自動分配,速度較快。但程序員是無法控制的。

  堆:是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便。

  3.申請大小的限制

  棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數(shù)),如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。

  堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。

  4.堆和棧中的存儲內(nèi)容

  棧: 在函數(shù)調(diào)用時,第一個進(jìn)棧的是主函數(shù)中函數(shù)調(diào)用后的下一條指令(函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址,然后是函數(shù)的各個參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。 當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開始存的地址,也就是主函數(shù)中的下一條指令,程序由該點繼續(xù)運(yùn)行。

  堆:一般是在堆的頭部用一個字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。

  堆和棧的區(qū)別可以引用一位前輩的比喻來看出:

  使用棧就象我們?nèi)ワ堭^里吃飯,只管點菜(發(fā)出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。使用堆就象是自己動手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。

  局部變量指針

  如果不了解程序棧如何工作,就很容易犯返回指向局部數(shù)據(jù)指針的錯誤,看下面的例子:

  #include

  #include

  int* allocateArray(int size, int value)

  {

  int arr[size];

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

  arr[i] = value;

  }

  return arr;

  }

  int main()

  {

  int* vector = allocateArray(5, 45);

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

  printf("%d ", vector[i]);

  }

  return 0;

  }

  一旦函數(shù)返回,返回的數(shù)組地址也就無效,因為函數(shù)的棧幀從棧中彈出了

  有一種方法是把a(bǔ)rr變量聲明為static,這樣會把變量的作用域現(xiàn)在在函數(shù)內(nèi)部,但是分配在棧幀的外面,避免其他函數(shù)覆寫變量值

  #include

  #include

  int* allocateArray(int size, int value)

  {

  static int arr[10];

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

  arr[i] = value;

  }

  return arr;

  }

  int main()

  {

  int* vector = allocateArray(5, 45);

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

  printf("%d ", vector[i]);

  }

  return 0;

  }

  返回指針

  從函數(shù)返回對象經(jīng)常使用以下兩種技術(shù):

  使用malloc在函數(shù)內(nèi)部分配內(nèi)存并返回其地址,調(diào)用者負(fù)責(zé)釋放返回的內(nèi)存

  傳遞一個對象給函數(shù),讓函數(shù)修改它,這樣分配和釋放對象的內(nèi)存都是調(diào)用者的責(zé)任

  #include

  #include

  int* allocateArray(int size, int value)

  {

  int* arr = (int*)malloc(size * sizeof(int));

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

  arr[i] = value;

  }

  return arr;

  }

  int main()

  {

  int* vector = allocateArray(5, 45);

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

  printf("%d ", vector[i]);

  }

  free(vector);

  return 0;

  }

  下面這個版本的allocateArray函數(shù)傳遞了一個數(shù)組指針、數(shù)組的長度和用來初始化數(shù)組元素的值,返回指針只是為了方便

  #include

  #include

  int* allocateArray(int *arr, int size, int value)

  {

  if(arr != NULL) {

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

  arr[i] = value;

  }

  }

  return arr;

  }

  int main()

  {

  int* vector = (int*)malloc(5 * sizeof(int));

  allocateArray(vector, 5, 45);

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

  printf("%d ", vector[i]);

  }

  free(vector);

  return 0;

  }

  傳遞指針的指針

  將指針傳遞給函數(shù)的時候,傳遞的是值,如果希望修改原指針而不是指針的副本,就需要傳遞指針的指針

  #include

  #include

  void allocateArray(int **arr, int size, int value)

  {

  *arr = (int*)malloc(size * sizeof(int));

  if(arr != NULL) {

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

  *(*arr + i) = value;

  }

  }

  }

  int main()

  {

  int* vector = NULL;

  allocateArray(&vector, 5, 45);

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

  printf("%d ", vector[i]);

  }

  free(vector);

  return 0;

  }

  二叉樹遞歸實現(xiàn)與二重指針

  二叉樹的諸多操作往往是通過遞歸調(diào)用來實現(xiàn)的,這就決定,不能只通過main函數(shù)實現(xiàn)全部過程,其中還需要調(diào)用main外定義的函數(shù)。也因此,對main調(diào)用外定義的函數(shù)的參數(shù)傳遞,就有了嚴(yán)格的要求。在網(wǎng)上查找很多關(guān)于二叉樹建立的程序,但直接拷貝在自己計算機(jī)上運(yùn)行卻發(fā)現(xiàn)不少錯誤,無法編譯通過。以下有關(guān)代碼編譯通過,不涉及二叉樹的全部操作,著重通過C語言實現(xiàn)二叉樹的創(chuàng)建過程說明遞歸實現(xiàn)與二重指針的相關(guān)問題。

  1、二叉樹的定義

  二叉樹的定義結(jié)構(gòu)通常為如下形式:

  typedef struct Node

  {

  char ch;

  struct Node *lchild,*rchild;

  }Node,*BTree;

  Node一般可用來定義二叉樹節(jié)點,而*BTree可用來定義指向二叉樹(根節(jié)點)的指針

  2、內(nèi)存動態(tài)分配

  采用內(nèi)存動態(tài)分配需要用到malloc函數(shù)。值得注意的是,該函數(shù)在成功開辟新的內(nèi)存時,默認(rèn)返回void*指針,因此需要強(qiáng)制轉(zhuǎn)換成Node*形式,其調(diào)用形式如(Node*)malloc(sizeof(Node))

  3、遞歸調(diào)用

  因為遞歸調(diào)用的需要,二叉樹的一些操作需要獨(dú)立作為一個函數(shù)。但是,這些函數(shù)是在main中調(diào)用,因此傳遞的參數(shù)和返回的值的處理是非常重要的。另外注意,對二叉樹的操作,首先就需要知道二叉樹的入口,即指向二叉樹的指針,也即指向二叉樹根節(jié)點的指針。因此,所傳遞的參數(shù),則為指向根節(jié)點的指針。又因為涉及分配內(nèi)存的操作,必須傳遞二級指針,如下程序,CreateTree函數(shù)可以是由返回值,也可以不具有返回值(因為傳遞的是地址)。在main函數(shù)中作了測試,返回的值為二叉樹根節(jié)點的值。

  void CreateTree(Node** pTree)

  {

  char ch;

  scanf("%c",&ch);

  if(chr == '#') {

  (*pTree) = NULL;

  } else {

  if(!((*pTree) = (Node*)malloc(sizeof(Node)))) {

  exit(OVERFLOW);

  }

  (*pTree)->ch = chr;

  CreateTree(&((*pTree)->lchild));

  CreateTree(&((*pTree)->rchild));

  }

  }


【C語言指針的傳遞】相關(guān)文章:

C語言的指針12-21

C語言指針的總結(jié)11-24

C語言指針的概念02-25

C語言指針的用法11-15

對C語言指針的總結(jié)12-09

C語言指針教學(xué)02-10

什么是C語言中指針 C語言指針的基礎(chǔ)使用12-17

如何理解C語言指針12-18

C語言指針變量的運(yùn)算09-30

  • 相關(guān)推薦