国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > iOS > 正文

iOS開(kāi)發(fā)系列--詳細(xì)講解C語(yǔ)言之存儲(chǔ)方式和作用域

2019-10-21 18:50:42
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

概述

基本上每種語(yǔ)言都要討論這個(gè)話(huà)題,C語(yǔ)言也不例外,因?yàn)橹挥心阃耆私饷總€(gè)變量或函數(shù)存儲(chǔ)方式、作用范圍和銷(xiāo)毀時(shí)間才可能正確的使用這門(mén)語(yǔ)言。今天將著重介紹C語(yǔ)言中變量作用范圍、存儲(chǔ)方式、生命周期、作用域和可訪(fǎng)問(wèn)性。

  • 變量作用范圍
  • 存儲(chǔ)方式
  • 可訪(fǎng)問(wèn)性

變量作用范圍

在C語(yǔ)言中變量從作用范圍包括全局變量和局部變量。全局變量在定義之后所有的函數(shù)中均可以使用,只要前面的代碼修改了,那么后面的代碼中再使用就是修改后的值;局部變量的作用范圍一般在一個(gè)函數(shù)內(nèi)部(通常在一對(duì)大括號(hào){}內(nèi)),外面的程序無(wú)法訪(fǎng)問(wèn)它,它卻可以訪(fǎng)問(wèn)外面的變量。

//// main.c// ScopeAndLifeCycle//// Created by Kenshin Cui on 14-7-12.// Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#include <stdio.h>int a=1;void changeValue(){ a=2; printf("a=%d/n",a);}int main(int argc, const char * argv[]) { int b=1; changeValue(); //結(jié)果:a=2 printf("a=%d,b=%d/n",a,b); //結(jié)果:a=2,b=1 ,因?yàn)閏hangeValue修改了這個(gè)全局變量 return 0;}

變量存儲(chǔ)方式

C語(yǔ)言的強(qiáng)大之處在于它能直接操作內(nèi)存(指針),但是要完全熟悉它的操作方式我們必須要弄清它的存儲(chǔ)方式。存儲(chǔ)變量的位置分為:普通內(nèi)存(靜態(tài)存儲(chǔ)區(qū))、運(yùn)行時(shí)堆棧(動(dòng)態(tài)存儲(chǔ)區(qū))、硬件寄存器(動(dòng)態(tài)存儲(chǔ)區(qū)),當(dāng)然這幾種存儲(chǔ)的效率是從低到高的。而根據(jù)存儲(chǔ)位置的不同在C語(yǔ)言中又可以將變量依次分為:靜態(tài)變量、自動(dòng)變量、寄存器變量。

靜態(tài)變量

首先說(shuō)一下存儲(chǔ)在普通內(nèi)存中的靜態(tài)變量,全局變量和使用static聲明的局部變量都是靜態(tài)變量,在系統(tǒng)運(yùn)行過(guò)程中只初始化一次(在下面的例子中雖然變量b是局部變量,在外部無(wú)法訪(fǎng)問(wèn),但是他的生命周期一直延續(xù)到程序結(jié)束,而變量c則在第一次執(zhí)行完就釋放,第二次執(zhí)行時(shí)重新創(chuàng)建)。

//// 2.1.c// ScopeAndLifeCycle//// Created by Kenshin Cui on 14-7-12.// Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#include <stdio.h>int a=1; //全局變量存儲(chǔ)在靜態(tài)內(nèi)存中,只初始化一次void showMessage(){ static int b=1; //靜態(tài)變量存儲(chǔ)在靜態(tài)內(nèi)存中,第二次調(diào)用不會(huì)再進(jìn)行初始化 int c=1; ++b; a+=2; printf("a=%d,b=%d,c=%d/n",a,b,c);}int main(int argc, const char * argv[]) { showMessage(); //結(jié)果:a=3,b=2,c=1 showMessage(); //結(jié)果:a=5,b=3,c=1 return 0;}

自動(dòng)變量

被關(guān)鍵字auto修飾的局部變量是自動(dòng)變量,但是auto關(guān)鍵字可以省略,因此可以得出結(jié)論:所有沒(méi)有被static修飾的局部變量都是自動(dòng)變量。

//// 1.3.c// ScopeAndLifeCycle//// Created by Kenshin Cui on 14-7-12.// Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#include <stdio.h>#include <stdlib.h>int main(int argc, const char * argv[]) { int a=1; auto int b=2; printf("a=%d,b=%d/n",a,b); //結(jié)果:a=1,b=2 ,a和b都是自動(dòng)變量,auto可以省略  //需要注意的是,上面的自動(dòng)變量是存儲(chǔ)在棧中,其實(shí)還可以存儲(chǔ)到堆中 char c[]="hello,world!"; long len=strlen(c)*sizeof(char)+1;//之所以加1是因?yàn)樽址竺婺J(rèn)有一個(gè)/0空操作符不計(jì)算在長(zhǎng)度內(nèi) char *p=NULL;//可以直接寫(xiě)成:char *p; p=(char *)malloc(len);//分配指定的字節(jié)存放c中字符串,注意由于malloc默認(rèn)返回“void *”需要轉(zhuǎn)化 memset(p,0,len);//清空指向內(nèi)存中的存儲(chǔ)內(nèi)容,因?yàn)榉峙涞膬?nèi)存是隨機(jī)的,如果不清空可能會(huì)因?yàn)槔鴶?shù)據(jù)產(chǎn)生不必要的麻煩 strcpy(p,c); printf("p=%s/n",p);//結(jié)果:p=hello,world! free(p);//釋放分配的空間 p=NULL;//注意讓p指向空,否則p將會(huì)是一個(gè)存儲(chǔ)一個(gè)無(wú)用地址的野指針   return 0;}

當(dāng)然存儲(chǔ)自動(dòng)變量的棧和堆其實(shí)是兩個(gè)完全不同的空間(雖然都在運(yùn)行時(shí)有效的空間內(nèi)):棧一般是程序自動(dòng)分配,其存儲(chǔ)結(jié)果類(lèi)似于數(shù)據(jù)結(jié)構(gòu)中的棧,先進(jìn)后出,程序結(jié)束時(shí)由編譯器自動(dòng)釋放;而堆則是開(kāi)發(fā)人員手動(dòng)編碼分配,如果不進(jìn)行手動(dòng)釋放就只有等到程序運(yùn)行完操作系統(tǒng)回收,其存儲(chǔ)結(jié)構(gòu)類(lèi)似于鏈表。在上面的代碼中p變量同樣是一個(gè)自動(dòng)變量,同樣可以使用auto修飾,只是它所指向的內(nèi)容放在堆上(p本身存放在棧上)。

這里說(shuō)明幾點(diǎn):malloc分配的空間在邏輯上連續(xù),物理上未必連續(xù);p必須手動(dòng)釋放,否則直到程序運(yùn)行結(jié)束它占用的內(nèi)存將一直被占用;釋放p的過(guò)程只是把p指向的空間釋放掉,p中存放的地址并未釋放,需要手動(dòng)設(shè)置為NULL,否則這將是一個(gè)無(wú)用的野指針;

寄存器變量

默認(rèn)情況下無(wú)論是自動(dòng)變量還是靜態(tài)變量它們都在內(nèi)存中,不同之處就是自動(dòng)變量放在一塊運(yùn)行時(shí)分配的特殊內(nèi)存中。但是寄存器變量卻是在硬件寄存器中,從物理上來(lái)說(shuō)它和內(nèi)存處在兩個(gè)完全不同的硬件中。大家都是知道寄存器存儲(chǔ)空間很小,但是它的效率很高,那么合理使用寄存器變量就相當(dāng)重要了。什么是寄存器變量呢?使用register修飾的int或char類(lèi)型的非靜態(tài)局部變量是寄存器變量。沒(méi)錯(cuò),需要三個(gè)條件支撐:register修飾、必須是int或char類(lèi)型、必須是非靜態(tài)局部變量。

除了存儲(chǔ)位置不同外,寄存器變量完全符合自動(dòng)變量的條件,因此它的生命周期其實(shí)是和自動(dòng)變量完全一樣的,當(dāng)函數(shù)運(yùn)行結(jié)束后它就會(huì)被自動(dòng)釋放。由于寄存器空間珍貴,因此我們需要合理使用寄存器變量,只有訪(fǎng)問(wèn)度很高的變量我們才考慮使用寄存器變量,如果過(guò)多的定義寄存器變量,當(dāng)寄存器空間不夠用時(shí)會(huì)自動(dòng)轉(zhuǎn)化為自動(dòng)變量。

//// 1.3.c// ScopeAndLifeCycle//// Created by Kenshin Cui on 14-7-12.// Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#include <stdio.h>int main(int argc, const char * argv[]) { register int a=1; printf("a=%d/n",a); return 0;}

 上面我們說(shuō)到變量的存儲(chǔ)類(lèi)型,其實(shí)在C語(yǔ)言中還有兩種存儲(chǔ)類(lèi)型:常量存儲(chǔ)區(qū)和代碼存儲(chǔ)區(qū),分別用于存儲(chǔ)字符串常量、使用const修飾的全局變量以及二進(jìn)制函數(shù)代碼。

可訪(fǎng)問(wèn)性

在C語(yǔ)言中沒(méi)有其他高級(jí)語(yǔ)言public、private等修飾符,來(lái)限定變量和函數(shù)的有效范圍,但是卻有兩個(gè)類(lèi)似的關(guān)鍵字能達(dá)到類(lèi)似的效果:extern和static。

extern

extern作用于變量

我們知道在C語(yǔ)言中變量的定義順序是有嚴(yán)格要求的,要使用變量則必須在使用之前定義,extern用于聲明一個(gè)已經(jīng)存在的變量,這樣一來(lái)即使在后面定義一個(gè)變量只要前面聲明了,也同樣可以使用。具體的細(xì)節(jié)通過(guò)下面的代碼相信大家都可以看明白:

//// 2.1.c// ScopeAndLifeCycle//// Created by Kenshin Cui on 14-7-12.// Copyright (c) 2014年 Kenshin Cui. All rights reserved.//#include <stdio.h>//如果在main函數(shù)下面定義了一個(gè)變量a,如果在main上面不進(jìn)行聲明是無(wú)法在main中使用a的;//同樣如果只進(jìn)行了extern聲明不進(jìn)行定義一樣會(huì)報(bào)錯(cuò),因?yàn)閑xtern并不負(fù)責(zé)定義變量a而僅僅是聲明一個(gè)已經(jīng)定義過(guò)的變量;//當(dāng)然如果說(shuō)在main上面定義int a;去掉main下面的定義同樣是可以的,相當(dāng)于在上面定義,但如果兩個(gè)地方都定義a的話(huà)(main上面的extern去掉),則程序認(rèn)為上面的定義是聲明,只是省略了extern關(guān)鍵字;//第一種情況,在下面定義,不進(jìn)行聲明,報(bào)錯(cuò)int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}int a;//第二種情況,在上面定義,正確int a;int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}//第三種情況,在下面定義在上面聲明,正確extern int a;int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}int a;//第四種情況,只在上面聲明(編譯時(shí)沒(méi)有問(wèn)題,因?yàn)樯厦娴穆暶黩_過(guò)了編譯器,但運(yùn)行時(shí)報(bào)錯(cuò),因?yàn)閑xtern只能聲明一個(gè)已經(jīng)定義的變量),錯(cuò)誤extern int a;int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}//第五種情況,上下同時(shí)定義(這種方式是正確的,因?yàn)樯厦娴亩x會(huì)被認(rèn)為是省略了extern的聲明),正確int a;int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}int a;//其實(shí)下面的情況也是不會(huì)出錯(cuò)的int a;int a;int main(int argc, const char * argv[]) {  printf("a=%d/n",a); return 0;}int a;int a;//第六種情況,將全局變量聲明為局部變量,但是它的實(shí)質(zhì)還是全局變量,正確int a;int main(int argc, const char * argv[]) { extern int a; printf("a=%d/n",a); return 0;}int a;//第七種情況,在函數(shù)內(nèi)部重新定義一個(gè)變量a,雖然不會(huì)報(bào)錯(cuò),但是兩個(gè)a不是同一個(gè)int a;int main(int argc, const char * argv[]) { int a; printf("a=%d/n",a);//注意這里輸出的a其實(shí)是內(nèi)部定義的a,和函數(shù)外定義的a沒(méi)有關(guān)系 return 0;}int a;

如果兩個(gè)文件同時(shí)定義一個(gè)全局變量,那實(shí)質(zhì)上他們指的是同一個(gè)變量。從下面的例子可以看出,在main.c中修改了變量a之后message.c中的變量a值也修改了。ios數(shù)據(jù)存儲(chǔ)方式,ios中數(shù)據(jù)存儲(chǔ)方式

需要注意,在上面的代碼中無(wú)論在message.h中將a定義前加上extern,還是在main.h中的a定以前加上extern結(jié)果都是一樣的,extern同樣適用。和在單文件中一樣,不能兩個(gè)定義都添加extern,否則就沒(méi)有定義了。如果把message.c中a的定義(或聲明)去掉呢,那么它能否訪(fǎng)問(wèn)main.c中的全局變量a呢,答案是否定的(這和在一個(gè)文件中定義了一個(gè)函數(shù)在另一個(gè)文件不聲明就直接用是類(lèi)似的)。

extern作用于函數(shù)

extern作用于函數(shù)就不再是簡(jiǎn)單的聲明函數(shù)了,而是將這個(gè)函數(shù)作為外部函數(shù)(當(dāng)然還有內(nèi)部函數(shù),下面會(huì)說(shuō)到),在其他文件中也可以訪(fǎng)問(wèn)。但是大家應(yīng)該已經(jīng)注意到,在上面的代碼中message.c中的showMessage前面并沒(méi)有添加extern關(guān)鍵字,在main.c中不是照樣訪(fǎng)問(wèn)嗎?那是因?yàn)檫@個(gè)關(guān)鍵字是可以省略的,默認(rèn)情況下所有的函數(shù)都是外部函數(shù)。ios數(shù)據(jù)存儲(chǔ)方式,ios中數(shù)據(jù)存儲(chǔ)方式

和作用于變量不同,上面main.c和message.c中的extern都可以省略,在這里extern的作用就是定義或聲明一個(gè)外部函數(shù)。從上面可以看到在不同的文件中可以定義同一個(gè)變量,它們被視為同一個(gè)變量,但是需要指出的是外部函數(shù)在一個(gè)程序中是不能重名的,否則會(huì)報(bào)錯(cuò)。

static

static作用于變量

其實(shí)在前面的例子中我們已經(jīng)看到static關(guān)鍵字在變量中的使用了,在例子中使用static定了一個(gè)局部變量,而且我們強(qiáng)調(diào)static局部變量在函數(shù)中只被初始化一次。那么如果static作用于全局變量是什么效果呢?如果static作用于全局變量它的作用就是定義一個(gè)只能在當(dāng)前文件訪(fǎng)問(wèn)的全局變量,相等于私有全局變量。ios數(shù)據(jù)存儲(chǔ)方式,ios中數(shù)據(jù)存儲(chǔ)方式

從上面的輸出結(jié)果可以看出message.c中的變量a和main.c中的變量a并不是同一個(gè)變量,事實(shí)上message.c中的變量a只能在message.c中使用,雖然main.c中的變量a是全局變量但是就近原則,message.c會(huì)使用自己內(nèi)部的變量a。當(dāng)然,上面例子中main.c中的變量a定義成靜態(tài)全局變量結(jié)果也是一樣的,只是這樣如果還有其他源文件就不能使用a變量了。但是main.c中的a不能聲明成extern,因?yàn)閙ain.c不能訪(fǎng)問(wèn)message.c中的變量a,這樣在main.c中就沒(méi)變量a的定義了。

static作用于函數(shù)

static作用于函數(shù)和作用于變量其實(shí)是類(lèi)似的,如果static作用于函數(shù)則這個(gè)函數(shù)就是內(nèi)部函數(shù),其他文件中的代碼不可以訪(fǎng)問(wèn)。下面的代碼在運(yùn)行時(shí)會(huì)報(bào)錯(cuò),因?yàn)閙esage.c中的showMessage()函數(shù)是私有的,在main.c中盡管進(jìn)行了聲明,可以在編譯階段通過(guò),但是在鏈接階段會(huì)報(bào)錯(cuò)。ios數(shù)據(jù)存儲(chǔ)方式,ios中數(shù)據(jù)存儲(chǔ)方式

總結(jié)

最后做一下簡(jiǎn)單總結(jié)一下:

  1. extern作用于變量時(shí)用于聲明一個(gè)已經(jīng)定義的變量,但是并不能定義變量;使用extern你可以在其他文件中使用全局變量(當(dāng)然此時(shí)extern可以省略);
  2. extern作用于函數(shù)時(shí)與它作用于全局變量有點(diǎn)類(lèi)似,聲明這個(gè)函數(shù)是外部函數(shù),其他文件可以訪(fǎng)問(wèn),但不同的是當(dāng)它作用于函數(shù)時(shí)不僅可以聲明函數(shù)還可以定義函數(shù)(用在函數(shù)定義前面),不管是定義還是聲明都可以省略,C語(yǔ)言默認(rèn)認(rèn)為函數(shù)定義或聲明都是外部函數(shù);
  3. static作用于變量時(shí),該變量只會(huì)定義一次,以后在使用時(shí)不會(huì)重新定義,當(dāng)static作用于全局變量時(shí)說(shuō)明該變量只能在當(dāng)前文件可以訪(fǎng)問(wèn),其他文件中不能訪(fǎng)問(wèn);
  4. static作用于函數(shù)時(shí)與作用于全局變量類(lèi)似,表示聲明或定義該函數(shù)是內(nèi)部函數(shù)(又叫靜態(tài)函數(shù)),在該函數(shù)所在文件外的其他文件中無(wú)法訪(fǎng)問(wèn)此函數(shù);

原文鏈接:http://www.cnblogs.com/kenshincui/p/3854243.html

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到IOS開(kāi)發(fā)頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 三亚市| 昔阳县| 徐州市| 来凤县| 汝州市| 临桂县| 左权县| 曲沃县| 开封市| 凯里市| 奉节县| 中超| 池州市| 北宁市| 高雄市| 怀来县| 尼勒克县| 会同县| 尉氏县| 临漳县| 青海省| 灯塔市| 黄龙县| 溆浦县| 安宁市| 剑河县| 东兴市| 梨树县| 深泽县| 安宁市| 浮山县| 常山县| 富宁县| 吉林市| 海淀区| 台山市| 拜泉县| 大姚县| 肃宁县| 潼关县| 秀山|