麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

IOS開發(fā)之路--C語言存儲方式和作用域

2020-07-26 03:36:29
字體:
供稿:網(wǎng)友

概述

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

變量作用范圍 存儲方式 可訪問性

變量作用范圍

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

//// 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;}

變量存儲方式

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

靜態(tài)變量

首先說一下存儲在普通內(nèi)存中的靜態(tài)變量,全局變量和使用static聲明的局部變量都是靜態(tài)變量,在系統(tǒng)運(yùn)行過程中只初始化一次(在下面的例子中雖然變量b是局部變量,在外部無法訪問,但是他的生命周期一直延續(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; //全局變量存儲在靜態(tài)內(nèi)存中,只初始化一次void showMessage(){  static int b=1; //靜態(tài)變量存儲在靜態(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é)論:所有沒有被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)變量是存儲在棧中,其實(shí)還可以存儲到堆中  char c[]="hello,world!";  long len=strlen(c)*sizeof(char)+1;//之所以加1是因?yàn)樽址竺婺J(rèn)有一個(gè)/0空操作符不計(jì)算在長度內(nèi)  char *p=NULL;//可以直接寫成:char *p;  p=(char *)malloc(len);//分配指定的字節(jié)存放c中字符串,注意由于malloc默認(rèn)返回“void *”需要轉(zhuǎn)化  memset(p,0,len);//清空指向內(nèi)存中的存儲內(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è)存儲一個(gè)無用地址的野指針      return 0;}

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

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

寄存器變量

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

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

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

可訪問性

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

externextern作用于變量

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

//// 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)行聲明是無法在main中使用a的;//同樣如果只進(jìn)行了extern聲明不進(jìn)行定義一樣會(huì)報(bào)錯(cuò),因?yàn)閑xtern并不負(fù)責(zé)定義變量a而僅僅是聲明一個(gè)已經(jīng)定義過的變量;//當(dāng)然如果說在main上面定義int a;去掉main下面的定義同樣是可以的,相當(dāng)于在上面定義,但如果兩個(gè)地方都定義a的話(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í)沒有問題,因?yàn)樯厦娴穆暶黩_過了編譯器,但運(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沒有關(guān)系  return 0;}int a;

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

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

extern作用于函數(shù)

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

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

staticstatic作用于變量

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

從上面的輸出結(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不能訪問message.c中的變量a,這樣在main.c中就沒變量a的定義了。

static作用于函數(shù)

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

總結(jié)

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

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

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 国产精品成人一区二区三区电影毛片 | 午夜亚洲影院 | 欧美一级特黄aaaaaa在线看首页 | 久久久久久久久久久亚洲 | 欧美亚洲国产一区二区三区 | 看免费一级毛片 | 手机视频在线播放 | 日本成人在线免费 | 一本免费视频 | 在线成人www免费观看视频 | 久久国产精品免费视频 | 亚洲天堂午夜 | 色的综合| 中文字幕综合 | 日韩视频一区在线 | 久久精品成人影院 | 一区二区三视频 | 欧美精品日日鲁夜夜添 | 天堂在线中文资源 | 把娇妻调教成暴露狂 | 成人福利视频网站 | 成人在线观看一区二区三区 | 毛片视频大全 | 久久久久99一区二区三区 | www噜噜偷拍在线视频 | 热久久91| 久久综合福利 | 成年免费大片黄在线观看岛国 | 女人裸体让男人桶全过程 | 欧美性色大片 | 狠狠操天天射 | 做爰xxxⅹ性护士hd在线 | 国产亚洲美女精品久久久2020 | 91久久精品一二三区 | 美国av在线免费观看 | 国产精品探花在线观看 | av黄色在线免费观看 | 中国妞xxxhd露脸偷拍视频 | 亚洲午夜不卡 | 中文字幕一区二区三区久久 | 欧美videofree性欧美另类 |