第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性.

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

C语言程序设计 主讲教师 :张群燕 电话:
“八皇后”问题 崔萌萌 吕金华.
第一章 C语言概述 计算机公共教学部.
藝術與美學欣賞 佛光山文化園區.
编译原理上机实习
第7章 相关分析 7.1 相关分析 7.2 相关系数 7.3 线性相关分析.
C语言程序设计 第八章 函数.
Linked List Operations
C语言程序设计 第十二章 位运算.
Introduction to the C Programming Language
高级语言程序设计 主讲人:陈玉华.
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
单片机原理与应用 C/C++在现代数字计算机上的实现.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数 10.3 宏定义 10.4 编译预处理.
新世纪计算机专业系列教材 数据结构 C++实现 第一章 缪淮扣 顾训穰 沈 俊 编著 科 学 出 版 社.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Function.
Object-Oriented Programming in C++ 第一章 C++的初步知识
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
第12章 從C到C++語言 12-1 C++語言的基礎 12-2 C++語言的輸出與輸入 12-3 C++語言的動態記憶體配置
第 6 章 函式.
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
程序设计专题一 结构化程序设计与递归函数 主讲教师: 刘新国.
第八章 函数.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
QQ: 李祥 QQ: 欢迎多种方式的学习交流,祝大家学有所成.
第二章 基本元素、类型和概念 七、输出函数printf 八、输入格式转换函数scanf.
6 使用者函數 6.1 函數定義 宣告函數 呼叫函數 呼叫多個函數 6-6
C语言 程序设计基础与试验 刘新国、2012年秋.
多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 多维数组元素的地址 先回顾多维数组的性质,可以认为二维数组是“数组的数组”,例 : 定义int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
計數式重複敘述 for 迴圈 P
第三章 顺序结构程序设计 主讲教师 贾月乐 电话:
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第4章 顺序程序设计.
第0章作业: 教材P12-练习与实践 1.写出用符号’*’输出描绘汉字”大”的流程图。
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
第16章 数据的共享和流通 一、浅拷贝和深拷贝 二、只读成员函数 三、友元friend.
第 二 章 数据类型、运算符与表达式.
C语言复习2----函数.
C语言程序设计 教案 崔武子制作
Oop8 function函式.
习题课
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
C程序设计.
第5章 函 数.
C语言程序设计 李祥 QQ:
C++语言程序设计教程 第2章 数据类型与表达式 第2章 数据类型与表达式 制作人:杨进才 沈显君.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
C++程式設計入門 變數與運算子 作者:黃建庭.
第一章 C语言概述 目录 什么是语言、程序 C语言的历史与发展 C语言的书写形式与程序结构 运行C语言的步骤与方法
第二章 类型、对象、运算符和表达式.
第二讲 基本数据类 型及数组等 此为封面页,需列出课程编码、课程名称和课程开发室名称。
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
#include <iostream.h>
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第6章 嵌入式软件开发基础.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
第11章 字符和内存处理 一、字符数组、指针和字符串的初始化作用 二、strlen函数确定字符串有效长度 三、strcpy函数拷贝字符串.
C语言基础学习 从外行到入门.
隨機函數.
Presentation transcript:

第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性

四、生存期与存储属性 生存期是指数据存在而不消失的时间。程序在内存被分 为四个区: 1.代码区,执行指令被加载到代码区。 2.静态数据区 3.动态数据区。 4.堆内存区。 内存的数据和代码由寄存器操作和周转。变量的生存期 是由其存储属性控制的,变量属于一个确定的存储属性。

系统有四个部分可供存放变量,相应的生存期与之密切 联系。 1. 寄存器register 关键字register允许用户将局部变量声明为寄存器存储 属性,如此存放的数据生存期是瞬态的。 编译器根据寄存器的使用情况做出优化处理,未必将 register变量一定存放在寄存器中,寄存器资源紧张的时 候,经关键字register限定的变量可能安排在堆栈中,因而 其生存期是类似于auto存储属性的局部变量。 32位通用寄存器最多可容纳4字节的数据,因此可将整 型变量声明为寄存器变量。例如: register int x; int f (register int x) {return x;}

2. 动态数据区和动态生存期 动态数据区也称为堆栈数据区。局部变量放置在堆栈空 间中,堆栈结构是一个先进后出动态的存储结构,堆栈空间 的变量常通过SS堆栈段寄存器:EBP基址索引寄存器寻 址。局部变量的生存期称为动态生存期。 先入栈的局部变量比后入栈的局部变量具有更长的生存 期。调用函数随即建立堆栈数据区,函数返回则自动释放堆 栈空间。 关键字auto指出其后的变量放置在堆栈空间中,在函 数内部定义的变量以及函数形参或在语句块中定义的局部变 量缺省地具auto存储属性,例如: {int x;} 等价于 {auto int x;} int f(auto int x){return x;} auto关键字在程序设计中倒是出现得非常少。

3.静态数据区和静态生存期 关键字static定义的变量称为静态变量,放置在静态数据 区中,静态数据区常通过DS:ESI 或ES: EDI 寄存器来寻址。 静态数据区中的变量的生存期与程序的运行期间是等长 的。全局变量和静态变量在全局数据区。 把贯穿程序运行期间的变量的生存期称为静态生存期。 静态全局变量、静态局部变量具有静态生存期,全局变量在 静态数据区,文件作用域的全局变量也具有静态生存期。 外部全局变量可以通过extern关键字为外部文件所共 享,静态全局变量的连接属性是内部的,拒绝外部模块的直 接访问.

4.堆区heap area 堆区是通过系统内置的运算符new或特定的函数如 malloc来建立的,堆空间是可以由用户控制的内存区域,运 算符new或特定的函数如malloc为用户开辟一块内存区域用 new运算符分配的内存当它们从定义的所在范围退出时不自 动释放。 new运算符返回它分配内存的首地址,须在合适的范围 定义一个指针以访问这片堆中内存。例如: void main() { char * out = new char[20]; for (int i=0;i<20;++i) { if (i==0) { char * inner = new char[20]; } } delete [ ] inner; delete [ ] out; }

指针p可以指向堆空间,也可以指向其它内存空间。但 在该指针指向堆空间的期间不要改动该指针的值,等到用 delete 释放该指针占有的堆空间后再将该指针另外派作它 用。 如果改变了这个指针,当delete运算符作用到改变后的 指针上时,会引起系统内存管理的混乱。若必须改变这个指 针,应将new分配的地址保持在另一个指针中,例如: int *p = new int [100]; int *ptemp =p; p++; delete [ ] ptemp; 下面的运算导致堆空间的悬空,堆空间的首地址没有妥 当保存: int * p= new int [100]; int x; p=&x; 安全的用法是定义一个固定指针a,例如: int* const a=new int [100];

五、extern关键字与外部连接属性 一个完整的程序由分别单独编译的不同的源程序或目标. 模块连接而成,每一个独立的功能模块可称为程序单元。 在程序单元之间共享变量、对象或函数名称的方式称为 连接。外部连接属性的函数名称和全局数据名称由关键字 extern 来确定。它们可以在不同单元之间共享,因而跨单 元这些全局名称的定义必须是唯一的。 关键字extern可以加在全局变量、全局对象或全局引用 等名称前,说明其后的名称在相关的程序单元中已经定义, 全局数据名称的外部连接说明的语法格式为: extern 类名 全局数据名称; extern type variable; //type为已声明的类型

如上的extern连接语句是说明语句,不涉及变量的存储 分配,它仅仅说明其后的名称在另外的位置或模块定义过, 经此说明的名称可以在该模块内随后的语句中索引。 例如: extern int x; extern const int y; extern long & z; extern int a[ ]; 分别引入全局变量x,全局常数y,全局引用z以及全局数 组a。

外部数据连接说明语句不能省去关键字extern,省去关 此源程序中的函数若要为其它程序单元所调用,可在函 数原型前明显地加关键字extern: extern 类型 函数名 (类型1 形参1,类型2 形参2,…,类型n 形参n); extern type function (type1 parm1, type2 parm2, …,typen parmn); 这样明显地说明在该模块内出现的函数名是有定义的, 程序连接的时候在其它模块中搜寻函数的实现部分。

可以在函数的定义部分冠以关键字extern。 extern type function (type1 parm1, type2 parm2, …,typen parmn) { 语句;} 例如: extern long* fg (); extern long* fx (); extern long f (int n) {static int s=1; return s*=n; } 函数名具有全局的性质,其连接属性默认是外部的,通 常在函数原型说明前不必加关键字extern,这是大量库函数 的简洁说明格式。 函数形参仅在堆栈空间,形参不用extern 和static修 饰。即int f ( extern int x ){ return x; }和 int f ( static int x ) { return x; }是错误的。

六、static关键字与内部连接属性 1.静态函数或内部函数 在C中static关键字有两种主要含义: 作用域维持原先的性质 . b.限制其后的名称在本模块内访问. 内部连接属性的数 据名称和函数名称由static限定. 内部连接的函数名称和全局 数据名称限制在特定的单元。 在特定单元全局名称的定义必须是唯一的。不同单元的 相同内部名称是彼此无关的。

默认情况下,全局函数连接属性是外部的,这样程序中 的其它模块可以访问外部连接属性的函数。可以用static关 键字说明一个全局函数,限制这个static函数只在定义它的 模块或文件内可见。 static关键字修饰的函数为静态函数。 格式为(type, type1, typen 等为已声明的类型): static type f (type1 parm1, type2 parm2, …,typen parmn); …,typen parmn) { 函数体语句; }

[例] static关键字屏蔽函数在模块间连接 c.pp #include<stdio.h> extern int x; extern int y; extern int a[ ]; void main ( ) { printf ("%d, %d, %d, %d\n",x, y, a[0], a[1]); } a.cpp static long f (long x); int x=f(1); long f ( long x ) { return x; } int a[ ]={ 3, 4 };

b.cpp static long f ( long x ) { return x; } int y=f (2); 说明: 上面的工程文件由三个源文件c.cpp,a.cpp,b.cpp构 成。a和b文件中各有一个同名函数f,因为前面加上static限 制,有效地屏蔽了目标模块单元之间的连接。 若去掉static,则连接时弹出 Linking...b.obj : error : "long __cdecl f(long)" already defined in a.obj。

2.静态全局变量和静态局部变量 全局变量的连接属性允许是外部的,在全局变量前冠以 static关键字,则得到静态全局变量或内部全局变量。 全局变量与单文件结构中的全局变量用法是一致的。 在全局变量前加一个static关键字可以放心地使用该变 量而不必担心其它模块中同名全局变量的冲突,起到内部屏 蔽的作用。 static关键字定义静态变量或静态数组的语法格式为: static类名 变量名; static type variable; static类名 数组名[N]; static type a[ ]={初始化列表};

经static关键字定义的变量称为静态变量。extern引入 定义语句,导致静态变量的内存分配,是唯一的。 static关键字可以用于定义一个局部变量。在保持该变 量的局部作用城的同时,赋予这个变量与程序相同的生存 期。 非静态局部变量则位于堆栈空间中随着函数调用动态变 化,而静态局部变量则常驻不变的数据区中,在程序调用之 间保持其位置和数据的静态稳定性。可以用指针访问局部静 态变量,而指针指向内层非静态局部变量,其结果是靠不住 的。

#include <stdio.h> //定义静态变量并初始化为0 void f() { static int n=0; n++; printf ("%d ", n); } void main () { f(); f(); f(); } 输出结果:1 2 3 局部静态变量的一个特征是仅初始化一次。在上面的例 子中,静态变量n只有一次为零,第二次调用该函数后n增值 为 2,若去掉static关键字则在每次函数调用时都把n初始化 为0,此时输出结果1 1 1。 下面的代码输出4 5 6, 去掉static关键字则输出4 8 1 。 void g ( int k ) { static int n=k; n++; printf ("%d ", n); } void main () { g(3); g(7); g(0); }

下面的代码输出1 21 21,去掉static关键字则输出: 1 1 1 void h ( ) { static int n=0; n++; printf ("%d ", n); n=20; } void main () { h(); h(); h(); } 全局变量和静态局部变量都存储在全局数据区。变量在 全局范围定义初始化一次。静态变量在局部范围定义仅分配 内存一次,仅在流程首次经过其定义点时被初始化一次。 非静态的局部变量随函数多次调用被重新分配不同的堆 栈内存被重新初始化。

[例] 全局范围的初始化语句[long x=fx();long& y=fy();]导 致函数在main之前调用。 #include<stdio.h> typedef long LONG; long fx () { LONG z; scanf ("%d", &z); return z;} long& fy () { static LONG q=5 ; typedef long LINT; static LINT z; scanf ("%d", &z); if (z!=1) return z; else return q; } LONG x=fx (); long& y=fy ();

void main( ) { printf ("y=%d, x=%d", y, x); } 程序某次交互运行结果为: 程序另一次交互运行结果为: 20 20 30 1 y=30,x=20 y=5,x=20 上面的例题表明:在进入main函数之前C++程序就进 入动态运行的交互过程,程序首先执行的是全局变量或引用 声明语句中的初始化函数,这是C语言不具备的特点。

[例]静态局部变量求n! [例]静态全局变量求n! # include<stdio.h> # include<stdio.h> extern long f (int n) static int s=1; { static int s=1; long f (int n) return s*=n; { return s*=n; } } void main () void main() { int k; for (k=1;k<3;k++) { int k ;for (k=1; k<4; k++) printf ("%d!=%d;",k,f(k)); printf ("%d!=%d; ",k,f (k)); printf ("%d!=%d; ", k, f (k)); } }

[例]局部变量求n!阶乘 #include <stdio.h> long f (int n) { long s=1;int j=n; for (; j>0; j--) s*=j; return s; } void main (void) { int k ; for ( k=1; k<4; k++) printf ("%d!=%d; ", k, s*=k); } 三个程序运行都输出:1!=1;2!=3;3!=6; 代码 { int s=1; for (int n=1;n<4;n++) printf ("%d!=%d; ", n, s*=n); } 也输出1!=1;2!=3;3!=6;

请打开“第7章(3).ppt”