C语言学习笔记:12_变量的存储方式和生存期

/*
 * 12_变量的存储方式和生存期.c
 *
 *  Created on: 2015年7月5日
 *      Author: zhong
 */
#include <stdio.h>
#include <stdlib.h>

/**
 *  从变量的作用域分: 全局变量,局部变量
 *  从变量存在的时间(生命周期)分:静态存储方式,动态存储方式
 *
 *	静态存储方式:在程序运行期间由系统分配固定的存储空间的方式
 *	动态存储方式:在程序运行期间根据需要进行动态的分配存储空间的方式。
 *
 *	数据存放的位置:静态存储区,动态存储区
 *
 *		1:全局变量全部存放在静态存储区,当程序开始执行时给全局变量分配存储区,结束后释放,在执行期间占据固定存储单元,而不是动态地进行分配和释放。
 *		2:动态存储区:形式参数,函数中定义的变量(不带static关键字),函数调用时的现场保护和返回地址
 *				 动态存储区内分配存储单元,在程序整个运行期间都不会释放。
 *
 *	在c语言中,每一个变量和函数都有两个属性:数据类型(如:int,float)和数据的存储类别(静态,动态存储)。
 *
 *	c语言中存储类别包括4种:自动的(auto,默认) ,静态的(static),寄存器的(register),外部的的(extern)
 *					存储类别不同,变量的作用域和生存期也不同。
 *
 *-------------------------------------------
 * 一:局部变量的存储类别:
 * 	1:自动变量(默认的):在函数中的局部变量,如果不专门声名为static的,都是动态地分配存储空间的,数据存储在动态存储区中。
 * 						调用函数会给这些变量分配存储空间,结束时自动释放存储空间
 * 						如:函数的形参,局部变量。
 * 						自动变量用关键字auto作存储类别的声明。
 *
 *			int f(int a){//形参
 *					auto int b,c=3; //int b,c=3; 自动局部变量,auto当然可以省略(我们平时就是省略的)
 *			}
 *
 *	2:静态局部变量(static局部变量):只是在局部变量int a;前面加个static关键字 static int a; 数据存储在静态存储区中。
 *				特点:当函数结束后,静态局部变量的存储单元不会释放,当下次再调用这个函数时,这个值就是上一次调用时结束时产生的值。
 *
 *	  静态局部与自动局部变量比较:
 *			1:静态局部变量是在编译时赋初值,只赋初值一次,在程序运行时它已经有初值,以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值
 *			2:动态局部变量赋初值,不是在编译时进行的,而是在函数调用时进行的,每调用一次,函数重新比例一次初值。
 *          3:定义静态局部变量时不赋初值,系统会自动赋初值0,或空字符‘\0’。对于自动变量来说,如果定义时不赋初值,系统会随机分配一个不确定的存储单元,所以值不确定。
 *          4:静态局部变量在函数调用结束后仍然存在,但是其它函数不能引用。
 *
 *         静态局部变量使用场景:需要保留函数上一次调用结束时的值
 *          如:输出1到5的阶乘值
 *          int fac(int n){
 *            static int  fac=1;
 *            fac=fac*n;
 *            return fac;
 *          }
 *
 *          int main(){
 *          	int i;
 *          	for(i=1;i<=5;i++)
 *          	  printf("%d!=%d\n",i,fac(i));
 *          }
 *
 *  3:寄存器变量(register): 将变量保存到cpu的寄存器中。
 *	 说明:
 *  	 一般变量(静态,动态存储方式)的值都 存放在内存中的,当程序用到上"控制器"发生指令将内存中这个变量的值送到"运算器"中进行运算,
 *    	运算后,再从运算器将数据送到内存中存放。
 *
 *   为什么要操作寄存器变量:
 *   	例如在函数中执行1000次循环,每次循环中都 要引用局部变量(对某个变量频繁存取),如果每次都由“控制器”发送指令从内存中“存取”变量值,会花费不少时间。
 *		将局部变量的值放在cpu的寄存器中,需要用的时间胻从寄存器取出参加运算,不必从内存中去存取。速度超快的说。
 *
 *   声明寄存器变量:register int f;
 *
 *  由于计算机的发展,优化的编译系统能够自动识别使用频繁的变量,从而自动将这些变量放在寄存器中。所以实际编程中,程序员不需要过多指定这种 变量。
 *
 *-------------------------------
 *二:全局变量的存储类别:
 *
 *   全局变量都是存放在静态存储区中的,因此它们的生存期是固定的。存在于程序运行的整个过程。
 *   虽然生命周期是固定的,但是全局变量的作用域是不确定的,不同的存储类别作用域不同。
 *
 *   一般情况下如果全局变量(外部变量)不在文件的开头定义(整个源文件),其作用域在定义处开始,到本程序文件的未尾。定义处之前的函数不能使用。
 *
 *   如果不在文件开关定义,又想定义处之前的函数能使用这个全局变量,就要对全局变量进行作用域扩展
 *  1:在一个文件内扩展外部变量的作用域 (extern)
 *    	在函数引用这个在函数之后定义的外部变量时,使关键字extern对这个变量作“外部变量声明”:表示将外部变量的作用域扩展到此位置
 *    如:
 *    int fun(){
 *      extern int A; //extern对这个变量作“外部变量声明”
 *      //...在这个函数后面语句就可以使用这个外部变量了
 *    }
 *    int A=20; //在函数之后声名的外部变量
 *
 * 2:将外部变量的作用域扩展到其它文件
 * 	 将其它源文件中的全局变量扩展到本源文件加也是加个extern关键字即可。
 *
 *	如:
 *	file 1.c:
 *	int A=20;
 *	int max(){
 *		A=3;
 *	}
 *
 *	file2.c:
 *	int funk(){
 *	  extern int A; //将file 1.c 中定义的全局变量a扩展到这个文件,当作这文件的局部变量,int可省略
 *	  A=34;
 *	}
 *	extern A;//将file 1.c 中定义的全局变量a扩展到这个文件,当作这文件的外部变量,在此之后的函数可用,之前的函数不可用
 *	int funk(){
 *		A=3; //在此之后的函数可用
 *	}
 *
 *	(静态外部变量)
 * 	3:将外部变量的作用域限制在本文件中(不让其它文件访问):只需要在定义外部变量时添加static关键字即可。
 * 			同时,加了static关键字的全局变量的名称,其它文件也可以使用这个文件,不会发生冲突
 *
 * 		static int A=20; //这样其它文件就不能访问这个外部变量了。
 * 		int main(){
 *
 * 		}
 *
 *
 *小结:
 * 一:  static声明一个变量的作用:
 *    1:对局部变量用static声明,把它分配在静态存储区,这变量在整个程序执行期间不释放
 *    2:对全局变量用static声明,则这变量的作用域只限于 本文件模块,其它文件不可引用
 *
 *二: 声明存储类型的作用
 *  对于局部变量来说,声明存储类型的作用是指定变量存储的区域(静态存储,动态存储,寄存器),以及由此产生的生存期的问题
 *  对于全局变量,由于在编译时分配内存的,都 存放在静态存储区中,声明存储类型的作用是变量作用域的扩展问题,无它。
 *
 *
 */
//局部静态,动态变量
void local_static_auto(int a) {
	auto int b = 1; //auto可以省略  自动变量
	static int c = 3; //定义静态变量,程序运行期间,其存储单元不会释放,这语句只会在编译时执行一次,运行后不再执行。
					  //当第二次调用时,不会再重新赋初值3,只会使用前一次调用后保存的值
	printf("第%d次运行:b=%d,c=%d,a+b+c=%d\n", a, b, c, (a + b + c));

	c++; //c自增后保存在存储单元中,不释放,以便函数下次被调用时使用 .
	b++; //自动变量在这里自增后也没用,因为
}
void test_local_static_auto() {
	int i;
	for (i = 1; i < 5; i++) {
		local_static_auto(i);
	}
	/**
	 * output:
	 第1次运行:b=1,c=3,a+b+c=5
	 第2次运行:b=1,c=4,a+b+c=7
	 第3次运行:b=1,c=5,a+b+c=9
	 第4次运行:b=1,c=6,a+b+c=11
	 */
}

//求n的阶乘
int fac(int n) {
	static int fac = 1; //记录乘积结果
	fac *= n;
	return fac;
}
void test_fac() {
	int i;
	for (i = 1; i <= 5; i++)
		printf("%d!=%d\n", i, fac(i));
  /*1!=1
	2!=2
	3!=6
	4!=24
	5!=120*/
}

extern a;//将11_全局变量.c中定义的全局变量a扩展到这个文件,在此之后的函数可用,之前的函数不可用

//使用此函数之后 定义的外部变量
void use_extern_variable(){
	extern int A; //把外部变量a的作用域扩展到从此处开始
//	extern  A; //类型名可写可不写
	A=30;
	printf("extern_variable A=%d ,other file a=%d\n",A,a);
}
int A=20;
int main12() {

//	test_local_static_auto();
//	test_fac();
	use_extern_variable();
	extern a; //将11_全局变量.c中定义的全局变量a扩展到这个方法里面,其它方法不能用
	printf("%d",a);

	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 11:20:07

C语言学习笔记:12_变量的存储方式和生存期的相关文章

Go语言学习笔记(二) [变量、类型、关键字]

日期:2014年7月19日 1.Go 在语法上有着类 C 的感觉.如果你希望将两个(或更多)语句放在一行书写,它们 必须用分号分隔.一般情况下,你不需要分号. 2.Go 同其他语言不同的地方在于变量的类型在变量名的后面.例如:不是,int a,而是 a int.当定义了一个变量,它默认赋值为其类型的 null 值.这意味着,在 var a int后,a 的 值为 0.而 var s string,意味着 s 被赋值为零长度字符串,也就是 "". 3.Go语言的变量声明和赋值 在Go中使

java笔记之变量的存储方式

1.java变量存储域 java变量的存储区域主要放在以下几个地方: (1)寄存器:可以说是最快的存储区,在C/C++中可以声明寄存器变量,但是在java中不能声明寄存器变量,只是编译器在编译时确定. (2)栈:存放关于基本类型数据和对象的引用,但是对象本身并不在栈里,(通过new出来的)对象放在堆里或者常量池中(字符串的常量对象就放在常量池中). (3)堆:用于存放new出来的对象. (4)常量池:存放字符串常量和基本类型数据的常量(通过 public static final修饰). (5)

Go语言学习笔记1 变量,类型以及赋值

1.变量 1.1 声明变量 使用var关键字可以创建一个指定类型的变量: var i int = 0 var i = 0 var i int 以上三个表达式均是合法的,第三个表达式会将i初始化为int类型的零值,0:如果i是bool类型,则为false:i是float64类型,则为0.0:i为string类型,则为"":i为interface类型,则为nil:i为引用类型,则为nil:如果i是struct,则是将struct中所有的字段初始化为对应类型的零值. 可以在同一条语句中声明多

R语言学习笔记

參考:W.N. Venables, D.M. Smith and the R DCT: Introduction to R -- Notes on R: A Programming Environment for Data Analysis and Graphics,2003. http://bayes.math.montana.edu/Rweb/Rnotes/R.html 前言:关于R 在R的官方教程里是这么给R下注解的:一个数据分析和图形显示的程序设计环境(A system for data

Perl语言学习笔记 day 1

1.Perl Practical Extraction and Report Language:实用摘录与报表语言 2.多行注释 (1) =需要顶格写 = description statement; =cut (2)末尾的description需要顶格写 <<description; print "Hello,world!\n"; description 3.数字: 所有数字在Perl内都以双精度浮点数格式存储; 5**3:5*5*5: 4.字符串: 最短的字符串为空字符

C语言学习笔记(五) 数组

数组 数组的出现就是为了解决大量同类型数据的存储和使用的问题: 数组的分类:一维数组.二维数组. 一维数组:为多个变量连续分配存储控件:所有的变量的数据类型必须相同:所有变量所占的字节大小必须相等: 例如:int a[4]; 一维数组名不代表数组中的所有元素而是代表数组中第一个元素的地址: 数组的初始化: 完全初始化: int a[4] = {1,2,3,4}; 不完全初始化: int a[4] = {1};  未被初始化的元素的值默认为0; 数组清零 int a[4] = {0}; 不初始化:

Go语言学习笔记(四) [array、slices、map]

日期:2014年7月22日 一.array[数组] 1.定义:array 由 [n]<type> 定义,n 标示 array 的长度,而 <type> 标示希望存储的内容的类型. 例如: var arr[10] int arr[0] = 1 arr[1] = 2 数组值类型的:将一个数组赋值给 另一个数组,会复制所有的元素.另外,当向函数内传递一个数组的时候,它将获得一个数组的副本,而不是数组的指针. 2.数组的复合声明.a :=[3]int{1,2,3}或简写为a:=[...]i

Perl语言学习笔记 9 正则表达式处理文本

1.替换 s/PATTERN/REPLACE/; #返回是否替换成功的布尔值 可以使用捕获变量,如:s/(\w)/$1/ 匹配失败则不做任何处理 2.定界符 对于没有左右之分的定界符,重复三次即可,如:s///.s### 对于有左右之分的定界符,需使用两对,一对包含模式,一对包含替换字符串,这两对可以不一样,如:s{}{}.s[]{}.s<>[] 3.可选修饰符 /g可进行全局替换,替换所有匹配到的字符串,如:s/ / /g /s:使得 . 匹配所有字符 /i:大小写无关 4.绑定操作符 $f

c++学习笔记:变量

c++学习笔记:变量(2) 先说明一下上一篇博文中的一个问题:char.signed char.unsigned char 这三者到底是怎么回事. signed char与unsigned char 是明确的拥有含义的,也就是说当定义了一个signed char那么这个char一定是有符号的整数类型.而当定义了一个unsigned char时这个char是明确无符号的整数类型.但是char却不一定了,它的行为依靠具体的实现.(“普通char究竟是有符号还是无符号,此事由实现确定.这也可能导致出现