C語言程式猿必會的記憶體四區及經典面試題解析
前言:
為啥叫C語言程式猿必會呢?因為特別重要,學習C語言不知道記憶體分割槽,對很多問題你很難解釋,如經典的:傳值傳地址,前者不能改變實參,後者可以,知道為什麼?還有經典面試題如下:
#include <stdio.h> #include <stdlib.h> #include <stdlib.h> void getmemory(char *p) { p=(char *) malloc(100); } int main( ) { char *str=NULL; getmemory(str); strcpy(str,"hello world"); printf("%s/n",str); free(str); return 0; }
這段程式碼執行了會怎麼樣?接下里我會解釋這道面試題。
一、記憶體佈局
可能網上有很多把記憶體分的很多、很細,但覺得很難記,並對於理解問題作用並不大。現在主要將記憶體分為四區如下:
程式碼區:存放程式碼;執行期間不可修改
全域性區:全域性變數、靜態變數、常量字串;程式執行時存在,退出時消失。
棧區:自動變數、函式引數、函式返回值;作用域函式內(程式碼塊內)
堆區:動態分配記憶體,需手動釋放
用交換兩個數的程式進行解釋吧,如下:
#include<stdio.h> void swap(int a,int b) { int temp = a;//棧 a = b; b =temp; } int main() { int a=1,b=2;//棧 printf("a:%d,b:%d\n",a,b); swap(a,b); printf("a:%d,b:%d\n",a,b); return 0; }
畫個圖進行講解,如下:PS:依舊是全部落格園最醜圖,不接受反駁!
說明:main函式把a,b的值給了temp函式,temp函式在內部交換了值,並沒有影響main函式,並且temp結束,棧上的資料釋放。傳值不會改變實參。
二、程式示例及面試題講解
1、傳地址交換兩個數
在拿傳指標的例子來說明一下,如下:
#include<stdio.h> void swap(int *a,int *b) { int temp = *a;//棧 *a = *b; *b =temp; } int main() { int a=1,b=2;//棧 printf("a:%d,b:%d\n",a,b); swap(&a,&b); printf("a:%d,b:%d\n",a,b); return 0; }
結果:成功交換了實參的值
用圖進行解釋,如下:PS:依舊是全部落格園最醜圖,不接受反駁!
說明:實參把地址傳給形參,形參*a、*b是取的實參在記憶體中的值,交換也就是交換實參的值了,所以成功交換了實參的值。
2、解釋面試題
程式就是最開始的面試題那個,不再列出來了。
結果:段錯誤
然後畫圖進行說明,如下:PS:依舊是全部落格園最醜圖,不接受反駁!
說明: 最重要一點實參是把值傳給形參,而不是地址,要理解這一點!就是把實參的NULL給了形參,然後getmemory在堆上開闢空間,結束時p被釋放了,但main函式中的str並沒有指向堆上的記憶體,再給strcpy,當然會段錯誤。
三、解決被調函式開闢空間
可能有人就問了,我就想讓被調函式開空間,怎麼辦呢?那就需要形參是二級指標了。
給大家演示一下,程式碼如下:
#include <stdio.h> #include <string.h> #include <stdlib.h> void getmemory(char **p) { *p=(char *) malloc(100); } int main( ) { char *str=NULL; getmemory(&str); strcpy(str,"hello world"); printf("%s/n",str); free(str); return 0; }
結果:沒有段錯誤了
大家可以自己畫下圖,不懂歡迎隨時留言。
三、十月份計劃
十月份需求會很忙,但也要抽出時間把C++基礎學完,然後深入學習資料結構和演算法了