色www,五月婷婷深爱五月,午夜国产一级片,色噜噜综合,国产大胸无码视频,清纯美女被操黄网站在线观看,波多野结衣av高清一区二区三区

C語(yǔ)言指針的傳遞

時(shí)間:2025-12-17 08:02:04 C語(yǔ)言 我要投稿

C語(yǔ)言指針的傳遞

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

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

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

  下面的代碼實(shí)現(xiàn)一個(gè)常見的交換函數(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ù),交換就不會(huì)發(fā)生,具體的原理參見任何一本C語(yǔ)言教材

  傳遞指向常量的指針

  傳遞指向常量的指針是C中常用的技術(shù),效率很高,因?yàn)楸苊饽撤N情況下復(fù)制大量?jī)?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;

  }

  下面的代碼會(huì)產(chǎn)生錯(cuò)誤(第二個(gè)形參和實(shí)參的類型不匹配,試圖修改第一個(gè)參數(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語(yǔ)言中堆和棧的區(qū)別

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

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

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

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

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

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

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

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

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

  堆棧的區(qū)別,來看一個(gè)經(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;

  }

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

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

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

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

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

  2.申請(qǐng)效率的比較

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

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

  3.申請(qǐng)大小的限制

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

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

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

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

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

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

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

  局部變量指針

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

  #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ù)組地址也就無效,因?yàn)楹瘮?shù)的棧幀從棧中彈出了

  有一種方法是把a(bǔ)rr變量聲明為static,這樣會(huì)把變量的作用域現(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ù)返回對(duì)象經(jīng)常使用以下兩種技術(shù):

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

  傳遞一個(gè)對(duì)象給函數(shù),讓函數(shù)修改它,這樣分配和釋放對(duì)象的內(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;

  }

  下面這個(gè)版本的allocateArray函數(shù)傳遞了一個(gè)數(shù)組指針、數(shù)組的長(zhǎng)度和用來初始化數(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ù)的時(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;

  }

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

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

  1、二叉樹的定義

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

  typedef struct Node

  {

  char ch;

  struct Node *lchild,*rchild;

  }Node,*BTree;

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

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

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

  3、遞歸調(diào)用

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

  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語(yǔ)言指針的傳遞】相關(guān)文章:

C語(yǔ)言的指針12-21

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

C語(yǔ)言指針的概念02-25

C語(yǔ)言指針的用法11-15

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

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

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

如何理解C語(yǔ)言指針12-18

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

  • 相關(guān)推薦