做技術(shù),越做到后面越覺(jué)得基礎(chǔ)的、底層的才是越需要鞏固的。最近做的項(xiàng)目有關(guān)音視頻、圖像處理,涉及到的都死c和c++相關(guān)的代碼。遇到了問(wèn)題才發(fā)現(xiàn),c和c++才是通用大法。這兩塊沒(méi)學(xué)好,那也只有玩一玩應(yīng)用層、UI這些東西。抽空整理下!
作用域
四種:
- 多個(gè)文件共享的變量
- 特定文件每個(gè)函數(shù)共享的變量
- 某個(gè)函數(shù)特有的變量
- 某個(gè)函數(shù)一個(gè)代碼塊的變量
一個(gè)C變量的作用域可以是代碼塊作用域,函數(shù)作用域,文件作用域,基本概念就不說(shuō)了。
需要注意的幾點(diǎn):
for (int i = 0; i < 10 ; i++) {
printf("%d", i);
}
這里i的作用域是整個(gè)for循環(huán)。
一個(gè)所有函數(shù)之外定義的變量就是文件作用域。整個(gè)文件可以訪問(wèn)該變量。也叫全局作用域
#include "CTest.h"
int a = 4;
int main() {
for (int i = 0; i < 10 ; i++) {
printf("%d", i);
}
printf("%d", a);
return 0;
}
int test() {
a = 6;
printf("%d", a);
return a;
}
鏈接
- 外部鏈接:多個(gè)文件使用
- 內(nèi)部鏈接:當(dāng)前文件使用
- 空連接:函數(shù)代碼塊使用
int a = 4; // 外部鏈接
static int b = 5; // 內(nèi)部鏈接、文件私有
int main() {
...
return 0;
}
存儲(chǔ)時(shí)期(變量在內(nèi)存中生存的時(shí)間)
- 靜態(tài)存儲(chǔ):程序執(zhí)行期間一直存儲(chǔ),文件作用域(內(nèi)部和外部)的變量具有靜態(tài)存儲(chǔ)時(shí)期。文件作用域中特別注意用static表明鏈接類型而并非存儲(chǔ)時(shí)期。一個(gè)使用了static生命的文件作用域變量表示這個(gè)變量具有內(nèi)部作用域。
- 自動(dòng)存儲(chǔ):代碼塊作用域的變量。
5種存儲(chǔ)類:自動(dòng),寄存器,代碼作用域靜態(tài),外部靜態(tài),內(nèi)部靜態(tài)。下面這種表總結(jié)了上面的多種情況。

重點(diǎn)說(shuō)明一下寄存器變量:寄存處變量是存儲(chǔ)在CPU的寄存器中,比一般的內(nèi)存要快很多。但是有一個(gè)問(wèn)題就是寄存器變量的地址是無(wú)法獲取的。
把變量定義下所有函數(shù)之外,就創(chuàng)建了一個(gè)外部變量,為了使程序清晰,可以在使用使用外部變量的函數(shù)中通過(guò)extern來(lái)再次聲明。如果變量在別的文件定義,使用extern來(lái)聲明就是必須的。這里想一想OC中的寫第三方庫(kù)的時(shí)候,為了讓其他模塊能夠訪問(wèn)某個(gè)變量就是通過(guò)這種方式來(lái)達(dá)到目的的。
比如YYWebImageSetter中。
.h
extern NSString *const _YYWebImageFadeAnimationKey;
extern const NSTimeInterval _YYWebImageFadeTime;
extern const NSTimeInterval _YYWebImageProgressiveFadeTime;
.m
NSString *const _YYWebImageFadeAnimationKey = @"YYWebImageFade";
const NSTimeInterval _YYWebImageFadeTime = 0.2;
const NSTimeInterval _YYWebImageProgressiveFadeTime = 0.4;
函數(shù)也是具有存儲(chǔ)類。函數(shù)默認(rèn)是外部的,可以被其他文件中的函數(shù)調(diào)用,靜態(tài)函數(shù)只可以在定義它的文件中使用(用static)
使用static可以防止名字的沖突,為文件定義一個(gè)私有的變量或者函數(shù)。想想平時(shí)我們?cè)诙x常量的時(shí)候,有時(shí)候會(huì)出現(xiàn)沖突,OC中用static解決的。應(yīng)該有些同學(xué)有印象的。
分配內(nèi)存
系統(tǒng)自動(dòng)分配內(nèi)存:
float x;
char hello = "hello world";
系統(tǒng)將會(huì)預(yù)留出存儲(chǔ)float或字符串的足夠內(nèi)存空間。也可以指定預(yù)留多少內(nèi)存空間:
int plates[100];
聲明了100個(gè)內(nèi)存位置,每個(gè)位置可以存儲(chǔ)一個(gè)int值。這里的plate和上面的x、hello變量可以理解為內(nèi)存的標(biāo)識(shí)符。所以我們可以用x、hello來(lái)標(biāo)識(shí)、獲取這些內(nèi)存數(shù)據(jù)。
malloc&&free&&calloc
用于動(dòng)態(tài)開辟內(nèi)存。函數(shù)void* malloc( size_t size );
函數(shù)說(shuō)明
Allocates size bytes of uninitialized storage.
If allocation succeeds, returns a pointer to the lowest (first) byte in the allocated memory block that is suitably aligned for any object type.
If size is zero, the behavior is implementation defined (null pointer may be returned, or some non-null pointer may be returned that may not be used to access storage, but has to be passed to free).
malloc is thread-safe: it behaves as though only accessing the memory locations visible through its argument, and not any static storage.
A previous call to free or realloc that deallocates a region of memory synchronizes-with a call to malloc that allocates the same or a part of the same region of memory. This synchronization occurs after any access to the memory by the deallocating function and before any access to the memory by malloc. There is a single total order of all allocation and deallocation functions operating on each particular region of memory.
傳入所需要的內(nèi)存字節(jié)數(shù),然后malloc找到內(nèi)存中一個(gè)大小適合的快,內(nèi)存是匿名的,不像上面可以用定義float x;x用于標(biāo)識(shí)。不過(guò)返回的是一個(gè)開辟內(nèi)存的第一個(gè)字節(jié)的地址。雖然沒(méi)有為它指定名字,但是我們可以通過(guò)指針來(lái)接受返回的值來(lái)訪問(wèn)那塊內(nèi)存。
因?yàn)閏har代表一個(gè)字節(jié),所以經(jīng)常將malloc定義為指向char的指針類型。但是后來(lái)又了新的類型——————通用型指針(void *)。這樣就可以返回其他類型的了。特別注意如果malloc找不到所需的空間,就會(huì)返回空指針。比如傳入一個(gè)負(fù)數(shù)就會(huì)返回NULl
double *dbl;
dbl = malloc(30 * sizeof(double));
請(qǐng)求30個(gè)double類型值的空間,并把dbl指向該空間的所在的起始位置。然后就可以使用數(shù)組那樣使用它。簡(jiǎn)單來(lái)講可以dbl[0],dbl[1]訪問(wèn)
開辟了內(nèi)存,必定要釋放內(nèi)存。用free釋放內(nèi)存。對(duì)應(yīng)到OC就是那句內(nèi)存管理的至理名言誰(shuí)開辟、誰(shuí)釋放(alloc、release)
一次malloc,應(yīng)該調(diào)用一次free。free的參數(shù)是malloc返回的地址,釋放掉先前分配的內(nèi)存。不能使用free來(lái)釋放通過(guò)其他形式分配的內(nèi)存,比如聲明一個(gè)數(shù)組。
例子強(qiáng)調(diào)一下free的重要性
void memoryTest() {
double array[2000];
for (int i = 0; i< 1000; i++) {
testCopy(array, 2000);
}
}
void testCopy(double arr[], int count) {
double *temp = (double *)malloc(count * sizeof(double));
// No free
}
第一次調(diào)用testCopy,創(chuàng)建指針temp,并使用malloc開辟了2000 * 16,一個(gè)32000個(gè)字節(jié)。當(dāng)函數(shù)終止,temp作為自動(dòng)變量被銷毀,但是它指向的32000個(gè)字節(jié)的內(nèi)存仍然存在,并且無(wú)法訪問(wèn)這些內(nèi)存,因?yàn)榈刂凡灰娏耍╰emp銷毀),由于沒(méi)有調(diào)用free,那么就不可以再次使用這些內(nèi)存。
第二次調(diào)用testCopy,又創(chuàng)建一個(gè)temp,但是第一次的32000字節(jié)的塊已經(jīng)不能再用了。所以malloc不得不再去開辟一塊新的內(nèi)存地址。當(dāng)函數(shù)終止,這塊內(nèi)存同樣沒(méi)有調(diào)用free,創(chuàng)建的內(nèi)存同樣不能被訪問(wèn)。
循環(huán)1000次,就是32000000個(gè)字節(jié)。已經(jīng)有3200萬(wàn)字節(jié)在內(nèi)存中中不能使用。這就是在做iOS開發(fā)中MRC時(shí)代經(jīng)常遇到的內(nèi)存泄漏。
為了說(shuō)明問(wèn)題,這里我用xcode測(cè)試了一下,把循環(huán)次數(shù)改為了100000000。
-
沒(méi)有加free之前。
-
加free之后。
對(duì)比上面很明顯能看到兩者的區(qū)別。
calloc與malloc最大的區(qū)別是calloc會(huì)把開辟的全部位置為0。使用方式和malloc類似,同樣需要用free釋放內(nèi)存。
long *test;
test = (long *)calloc(100, sizeof(long));
開辟了可以容乃100個(gè)long類型的內(nèi)存空間。
常見的限定詞
const
普通類型前,標(biāo)識(shí)這個(gè)值不可變。而用在指針的時(shí)候情況就分多種了
因?yàn)橹羔槾嬖?,指針不可變還是指向的值不可變。
-
const float *pf(等同于float const * pf):表示pf指向一個(gè)常量浮點(diǎn)型數(shù)值。但是pf本身的值可以改變。比如它可以指向另一個(gè)const值 -
float * const pt:表示pt是一個(gè)常量指針,他總是指向同一個(gè)地址,但是地址里面的內(nèi)容可以改變。 -
const float * const pfc:表示pfc是個(gè)常量指針,而且指向的地址內(nèi)容也不能變。
記憶方式,const位于*左邊代表指向的值不可變,位于*右邊指針不可變

