天天看點

C語言中指針局部變量釋放問題

目錄

    • 1.問題代碼
    • 2.一次改動
    • 3.理論
    • 4.佐證測試代碼
    • 5.總結

   一個朋友有次跟我探讨一段代碼,其中涉及了局部變量被釋放的問題,但是意外發現定義的局部指針變量在釋放時候會有些奇怪的現象,借此我查找一些資料,寫了測試佐證代碼得出結論。不太清楚的朋友可以了解一下。

1.問題代碼

#include "stdio.h"
#include "string.h"
int* get(int a ,int b)
{
  int c = 0;
  c = a + b;
  printf("%p\n",&c);
  return &c;
}

int main(void)
{
  int *p = get(4,5);
  printf("%p\n",p);
  return 0;
}

           

gcc 編譯時警告已經顯示

C語言中指針局部變量釋放問題

Waning:函數傳回了一個局部變量的位址

  • 運作結果:
    C語言中指針局部變量釋放問題

2.一次改動

    這裡我對傳回的位址用指針存放,傳回這個指針位址

#include "stdio.h"
#include "string.h"
int* get(int a ,int b)
{
  int c = 0;
  c = a + b;
  int *d = &c;
  printf("%p\n",&c);
  return d;
}

int main(void)
{
  int *p = get(4,5);
  printf("%p\n",p);
  printf("%d\n",*p);
  return 0;
}


           
  • 運作結果:
    C語言中指針局部變量釋放問題
    》》》發現沒有警告,而且位址相同,甚至值也對的
但是經過測試發現,這個指針跟指向的值,其實都被回收了,隻是沒有人用而已,是以值才沒有改變。

3.理論

-------------引用趙四老師:

    a) : 棧中的變量通常包括函數參數和函數裡聲明的臨時變量。

    b) : 棧中的基本變量退出其作用域時,沒有誰執行一段代碼去釋放/銷毀/析構它所占用的記憶體,僅僅是沒人再去理會的留在目前棧頂上方的若幹遺留下來可被後續壓棧操作覆寫的無用資料而已。

    c) : 而棧中的類變量退出其作用域時,會自動執行其析構函數

4.佐證測試代碼

#include <stdio.h>
int *global = NULL;
int *f(int c)
{
  int b = c;
  int *p1 = &b;
  global = &b;
  return p1;
}

int main()
{
  int *p = f(6);
  printf("p_addr : %p\n",p);
  printf("p_num : %d\n",*p);
  printf("global_addr : %p\n",global);
  printf("global_num : %d\n",*global);
  printf("*f(7) return : %d\n",*f(7));
  printf("p_addr : %p\n",p);
  printf("p_num : %d\n",*p);
  printf("global_addr : %p\n",global);
  printf("global_num : %d\n",*global);
}

           
  • 運作結果:
    C語言中指針局部變量釋放問題

5.總結

    結果會發現,同一個位址,又被配置設定一次。

    其實就是說,再一次執行這個函數時,你上次用這個函數傳回的位址跟指向的記憶體位址,又被配置設定使用了,是以那樣的使用是不安全的,那個對的資料,隻是遺留下來可被後續壓棧操作覆寫的無用資料

    是以你通路一個被釋放的局部變量,都是一個不安全的行為。傳回可以傳回數值,但是不能傳回一個局部變量的位址

繼續閱讀