久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

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

只有你完全了解每個(gè)變量或函數(shù)存儲方式、作用范圍和銷毀時(shí)間才可能正確的使用這門語言。今天將著重介紹C語言中變量作用范圍、存儲方式、生命周期、作用域和可訪問性。

概述

基本上每種語言都要討論這個(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)用不會再進(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ī)的,如果不清空可能會因?yàn)槔鴶?shù)據(jù)產(chǎn)生不必要的麻煩
  strcpy(p,c);
  printf("p=%s\n",p);//結(jié)果:p=hello,world!
  free(p);//釋放分配的空間
  p=NULL;//注意讓p指向空,否則p將會是一個(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é)束后它就會被自動(dòng)釋放。由于寄存器空間珍貴,因此我們需要合理使用寄存器變量,只有訪問度很高的變量我們才考慮使用寄存器變量,如果過多的定義寄存器變量,當(dāng)寄存器空間不夠用時(shí)會自動(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)行定義一樣會報(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會被認(rèn)為是省略了extern的聲明),正確
int a;
int main(int argc, const char * argv[]) {
  
  printf("a=%d\n",a);
  return 0;
}
int a;
//其實(shí)下面的情況也是不會出錯(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,雖然不會報(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ù),下面會說到),在其他文件中也可以訪問。但是大家應(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è)程序中是不能重名的,否則會報(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會使用自己內(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í)會報(bào)錯(cuò),因?yàn)閙esage.c中的showMessage()函數(shù)是私有的,在main.c中盡管進(jìn)行了聲明,可以在編譯階段通過,但是在鏈接階段會報(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í),該變量只會定義一次,以后在使用時(shí)不會重新定義,當(dāng)static作用于全局變量時(shí)說明該變量只能在當(dāng)前文件可以訪問,其他文件中不能訪問; static作用于函數(shù)時(shí)與作用于全局變量類似,表示聲明或定義該函數(shù)是內(nèi)部函數(shù)(又叫靜態(tài)函數(shù)),在該函數(shù)所在文件外的其他文件中無法訪問此函數(shù);

【網(wǎng)站聲明】本站部分內(nèi)容來源于互聯(lián)網(wǎng),旨在幫助大家更快的解決問題,如果有圖片或者內(nèi)容侵犯了您的權(quán)益,請聯(lián)系我們刪除處理,感謝您的支持!

相關(guān)文檔推薦

這篇文章主要介紹了ios實(shí)現(xiàn)文件對比的方法,主要是用到了filemanager,有需要的小伙伴可以參考下。
這篇文章主要給大家匯總了一下ios下移動(dòng)文件方法,從簡單到復(fù)雜,十分的實(shí)用,有需要的小伙伴可以參考下。
本文給大家總結(jié)了幾則在IOS系統(tǒng)下刪除文件的代碼,十分的實(shí)用,有需要的小伙伴可以參考下。
本文給大家分享的是IOS開發(fā)中遇到的一個(gè)手風(fēng)琴特效無法正常工作的問題的解決方法,經(jīng)過度娘了很久才找到解決方法,這里推薦給大家,有需要的小伙伴可以參考下。
這篇文章主要介紹了iOS、Mac OS X系統(tǒng)中編程實(shí)現(xiàn)漢字轉(zhuǎn)拼音的方法(超級簡單),本文講解的方法不僅支持中文,還支持日文、韓文等,需要的朋友可以參考下
這篇文章主要分享了iOS7 毛玻璃特效代碼,非常的實(shí)用,做IOS開發(fā)的童鞋們不要錯(cuò)過了
主站蜘蛛池模板: 中文字幕电影在线观看 | 欧美性video 精品亚洲一区二区 | 免费观看黄网站 | 国产大毛片 | 国产高清自拍视频在线观看 | 国产日韩一区二区三免费 | 亚洲欧美视频 | 国产情侣一区 | 国产在线观看一区二区三区 | www.日韩系列 | 精品久久久久久久 | 亚洲电影一区二区三区 | 日本一区二区三区在线观看 | 日韩视频在线一区 | 99精品欧美一区二区蜜桃免费 | 国产在线精品一区二区 | 成人免费视频久久 | 日本高清视频在线播放 | 国产成人99久久亚洲综合精品 | 日韩视频精品在线 | 久久av资源网 | 亚洲瑟瑟| 久久婷婷av | 国产精品成人一区二区 | 免费看日韩视频 | 日韩成人影院在线观看 | 久久成人人人人精品欧 | 国产成人av在线 | 国产免费一二三区 | 中文字幕欧美日韩一区 | 欧美精品二区三区 | 亚洲+变态+欧美+另类+精品 | 美女天天操 | 中文字幕亚洲欧美日韩在线不卡 | 在线播放中文字幕 | 中文字幕一区二区三区精彩视频 | 日韩欧美亚洲 | 亚洲欧美国产精品久久 | 黄色大片免费观看 | 亚洲一区二区久久 | 一区二区三区亚洲视频 |