数据类型、运算符与表达式
1、变量在程序的执行中能够赋值,发生变化。变量有一个名字,并在使用之前要说明其类型,一经说明,就在内存中占据与其类型相应的存储单元。
变量名、数组名、函数名称为标识符。
标识符只能由字母、数字、下划线这三种字符组成,且第一个字符必须为字母或下划线,长度不大于247个字符,大小写不通用。(关键字不能作为标识符)。
变量必须使用前定义,以分配空间。
常量是根据其表面形式来判定,整型量即是没有小数点的整数,范围:-231~(231-1),有三种形式:1)十进制(默认方式)2)八进制 以0开头3)十六进制 以0x开头
整型变量:分为有符号型与无符号型。
有符号型:short 在内存中占两个字节,范围为-215~(215-1)
int 在内存中占四个字节,范围为-231~(231-1)
long在内存中占四个字节,范围为-231~231-1
无符号型:最高位不表示符号位
unsigned short 在内存中占两个字节,范围为0~216-1
unsigned int 在内存中占四个字节,范围为0~232-1
unsigned long在内存中占四个字节,范围为0~232-1
1)整型常量亦有长短之分,常量中无unsigned型,但一个非负的整型常量可以赋给unsigned型的变量。
2)若一个常量定义为长整型数,则在其后加l或L进行区分。
不同类型的整型数据间的赋值归根到底就是一条:按存储单元中的存储形式直接传送。
#include <iostream >
void main()
{
unsigned short a;
short int b= -1; a=b;
cout<<"a="<<a<<endl;
}结果:65535
实型数又称浮点数,有两种表示方式:
1)十进制形式:23.0 3.56789
2)指数形式: 45e-1e前有数字,后面必须是整数。
实型变量分单精度 float 和双精度 double 两种形式:
float:占四个字节,提供7~8位有效数字。double: 占八个字节,提供15~16位有效数字。
一般用4个字节表示一个浮点数,也有用8个字节表示的。
当计算机中出现小于机器所能表示的最小数时,机器只能当零来处理,当出现超过机器所能表示的最大数时,出现溢出现象,一旦出现溢出,就会停止运算。定点数,浮点数均会出现溢出现象。
字符型数据实际上是作为整型数据在内存中存储的。
计算机是以字符编码的形式处理字符的,因此,我们在计算机内部是以ASCII码的形式表示所有字符的。所以7位二进制数即可表示出一个字符,我们用一个字节的容量(8位)存储一个字符。
在程序中表示为:
char grade ;//定义一个字符型的变量空间(1个字节)
grade=‘A’; //必须用‘ ’表示,否则易与标识符混同
‘ ’内括起来的字符表示该字符的ASCII码。
进一步,由于在内存中的形式与整型数据相同,所以,可以直接用其整型值给变量赋值。grade=‘A’或grade=65
非打印字符
有些ASCII的字符代表某些操作,不能打印出来,如回车、退格等,可用两种方式表示这些字符。
1)用ASCII码的形式 char re=13;
2)用转义字符 char re=‘\n’;
转义字符虽然包含2个或多个字符,但它只代表一个字符。编译系统在见到字符“\”时,会接着找它后面的字符,把它处理成一个字符,在内存中只占一个字节。
字符串常量:
用" "表示,在内存中顺序存放,以'\0'结束。 如:"CHINA"
实际上内存是对应字符的ASCII码形式 'a'在内存中占一个字节 "a"占两个字节
标识符常量 在C++中有二种方法定义标识符常量,一种是使用编译预处理指令(#define p158);另一种是使用C++的常量说明符const。
变量
1) 在程序的执行过程中,其值可以改变的量称为变量。
2) 变量名必须用标识符来标识。
3) 变量根据其取值的不同值域,分为不同类型的变量:整型变量、实型变量、字符型变量、构造型变量、指针型变量等等。
4) 对于任一变量,编译程序要为其分配若干个字节(连续的)的内存单元,以便保存变量的取值。
5) 当要改变一个变量的值时,就是把变量的新的取值存放到为该变量所分配的内存单元中;用到一个变量的值时,就是从该内存单元中取出数据。
6) 不管什么类型的变量,通常均是变量的说明在前,使用变量在后。
开辟空间后, 空间中为随机值
变量赋初值
在定义变量的同时给变量赋值,即在内存中开辟出一个空间后马上给此空间赋值。
但这个空间的值并不是固定不变的,在程序的运行中一样可以改变。
对变量赋初值的三种方法:
①在变量说明的同时对变量赋初值,例如:char ch1=‘a’,char ch2=‘b’;
②使用赋值语句赋值,例如:float x,y; x=1.234; y=2.56;
③通过输入流cin对变量赋初值,例如:int a; cin>>a;
C++的运算符p24
强制转换类型
(double) a 在强制类型运算后原变量不变,但得到一个所需类型的中间变量。
四、自增、自减运算符 (难点) ++ --
++在前, 先运算,后赋值 ++在后, 先赋值,后运算
1)自增、自减运算符只能用于变量,不可用于常量和表达式
因为表达式在内存内没有具体空间,常量所占的空间不能重新赋值
3++ (x+y)++ (-i)++
2)结合方式自右至左,优先级最高,向右取最大
赋值运算符和赋值表达式 "="左边必须是变量名。
若“ = ” 两边变量类型不同,在赋值时要进行类型转换。
转换原则:根据左边变量的类型转换。(少字节—>多字节)
1)若多字节变量为unsigned ,则转换后多余字节补零。
2)若多字节变量为有符号型,则转换后扩展少字节的最高位。
转换后,数据的符号不变。
多字节—>少字节
低位照搬
"="的结合性为自右至左
关系运算符和关系表达式
3. 算术运算符的优先级大于关系运算符的优先级
关系表达式:用关系运算符将表达式连接起来称为关系表达式。其值非真即假。在C++语言中,用非0代表真,用0表示假。关系表达式的结果只有两个,真为1,假为0。
逻辑运算符 注意事项
1.作为条件,所有非0值均为真;作为结果,只有0或1两种。
2.不可写为 1<x<10 应为:1<x && x<10
sizeof()运算符是一个单目运算符,用于计算某一个操作数类型的字节数。其格式为:
sizeof(<类型>)
逗号运算符和逗号表达式
表达式1,表达式2,表达式3,…,表达式n
顺序求解,结果为最后一个表达式的值,并且优先级最低。
各类数值型数据间的混合运算
整型、实型、字符型数据间可以混合运算。
在进行运算时,不同类型的数据要先转换成同一类型的数据再进行运算。
转换规则如下:P33
简单的输入输出
输入语句:cin
要使用C++提供的输入输出时,必须在程序的开头增加一行:#include <iostream >
输入语句自动过滤空白字符。cin格式过滤空白字符
在缺省的情况下,cin自动跳过输入的空格,换言之,cin不能将输入的空格赋给字符型变量,同样地,回车键也是作为输入字符之间的分隔符,也不能将输入的回车键字符赋给字符型变量。
若要把从键盘上输入的每一个字符,包括空格和回车键都作为一个输入字符赋给字符型变量时,必须使用函数cin.get()。其格式为:
cin.get(<字符型变量>);
cin.get()从输入行中取出一个字符,并将它赋给字符型变量。这个语句一次只能从输入行中提取一个字符。
在缺省的情况下,系统约定输入的整型数是十进制数据。当要求按八进制或十六进制输入数据时,在cin中必须指明相应的数据类型:hex为十六进制;oct为八进制;dec为十进制。
int i,j,k,l;
cin>>hex>>i; //指明输入为十六进制数
cin>>oct>>j; //指明输入为八进制数
cin>>k; //输入仍为八进制数
cin>>dec>>a; //指明输入为十进制数
当执行到语句cin时,若输入的数据为:
11 11 12 12<CR>
使用非十进制数输入时,要注意以下几点:
1、八进制或十六进制数的输入,只能适用于整型变量,不适用于字符型变量,实型变量。
2、当在cin中指明使用的数制输入后,则所指明的数制一直有效,直到在接着的cin中指明输入时所使用的另一数制为止。如上例中,输入k的值时,仍为八进制。
3、输入数据的格式、个数和类型必须与cin中所列举的变量类型一一对应。一旦输入出错,不仅使当前的输入数据不正确,而且使得后面的提取数据也不正确。
输出数据 cout
与输入cin对应的输出是cout输出流。
当要输出一个表达式的值时,可使用cout来实现,其一般格式为:
cout << <表达式> 《<< <表达式>......》;
其中运算符“<<”称为插入运算符,它将紧跟其后的表达式的值,输出到显示器当前光标的位置。
‘\t’为转义字符Tab
endl为回车或‘\n’
cout将双引号中的字符串常量按其原样输出
指定输出项占用的宽度:
在输出的数据项之间进行隔开的另一种办法是指定输出项的宽度。如上面的两个输出语句可改写为:
cout <<setw(6)<<left<< i<<setw(10)<<j<<endl;
_ _ _ _ _ 4_ _ _ _ _ _ _ _ _12
其中setw(6)指明其后的输出项占用的字符宽度为6,即括号中的值指出紧跟其后的输出项占用的字符位置个数,并向右对齐。setw是“set width”的缩写。
使用setw()应注意以下三点:
1、在程序的开始位置必须包含头文件iomanip.h,即在程序的开头增加:
#include <iomanip >
2、括号中必须给出一个表达式(值为正整数),它指明紧跟其后输出项的宽度。
3、该设置仅对其后的一个输出项有效。一旦按指定的宽度输出其后的输出项后,又回到原来的缺省输出方式。
输出八、十六进制数和科学表示法的实数
对于整型数据可指定以十六进制或八进制输出,而对于实型数据可指定以科学表示法形式输出。例如,设有如下一个程序:
#include <iostream.h>
void main(void)
{ float x=3.14,y=100;
cout.setf(ios::scientific,ios::floatfield);
//表明浮点数用科学表示法输出
cout << x<<’\t’;
cout <<y<<endl;
}
与cin中类同,当在cout中指明以一种进制输出整数时,对其后的输出均有效,直到指明又以另一种进制输出整型数据为止。对实数的输出,也是这样,一旦指明按科学表示法输出实数,则接着的输出均按科学表示法输出,直到指明以定点数输出为止。
C++语言的语句概述
语句分类:
1、说明语句(位置任意)—对数据结构的定义和描述、对变量的定义性说明等。
2、控制语句(有可能改变程序执行顺序的语句,如条件、循环等)
3、函数调用语句
4、表达式语句(表达式后加一分号,如I=I+1;)
5、空语句(只有一分号所构成的语句,不执行任何操作,主要用于指明转向的控制点或在特殊情况下作为循环语句的循环体。)
6、块语句(由花括号括起来的语句)
二、程序的三种基本结构
1、 顺序结构
2、 选择结构
3、 循环结构
if语句 p44
注意:1) if 后可跟复合语句。
2) 注意 ;的位置。(if 语句;else 语句;)若为if();即是一个空判断。
3) 注意多重 if else 的搭配。(可省略else)相互配对的语句要对齐。
if 总是与它上面最近的 else 配对,如要改变,用复合语句{}。
例:输入两个实数,按代数值由小到大次序输出这两个数。
void main( void )
{ float a,b,t; //定义变量
cout<<“ Input 2 Real Number:\n";//在屏幕上的提示信息
cin>>a>>b; //给变量赋值 a:7, b:3
if(a>b)
{ t=a; a=b; b=t; }//交换数据,用中间变量
cout<<a<<‘\t’<<b<<endl;//输出变量
} 输出结果:3 7
嵌套的条件语句
x=100; a=10; b=20; ok1=5; ok2=0;
if(a<b)
if(b!=15)
if(!ok1) x=1;
else if (ok2) x=10; x=-1;
输出结果:x=-1
条件运算符 是C++中的唯一的三目运算符。
表达式1?表达式2 :表达式3
注意:
1.条件运算符的优先级比赋值运算符高 x=(x=3) ? x+2 : x-3
2. 结合方向自左至右 a>b?a:c>d?c:d
3. 三个表达式的类型可不同 z=a>b?'A':a+b
x=9, y=6, z=5;
x=((x+y)%z>=x%z+y%z)?1:0;
cout<<"x= "<<x<<endl;
输出结果:x=0
x=1; y=2; z=3;
x+=y+=z;
cout<<( z+=x>y?x++:y++)<<endl;
输出结果:9
执行以下程序段后,变量a,b,c的值分别是:
int x=10, y=9;
int a,b,c;
a=(--x= =y++)?--x:++y;
b=x++;
c=y;
输出结果:x=8 y=10 a=8 b=8 x=9 c=10
void main(void )
{ int a=5,b=1,c=0;
if(a=b+c) cout<<“* * *\n”;
else cout<<“$ $ $\n”;
} 输出结果:* * *
switch语句 p48
switch(grade)
{ case ‘A’:cout<<“100~85\n”;
case ‘B’:cout<<“84~70\n”;
case ‘C’:cout<<“69~60\n”;
case ‘D’:cout<<“no pass\n”;
default:cout<<“error\n”;
}
如果grade为 ‘A’,则结果为
100~85
84~70
69~60
no pass
error
注意:
1、switch与if不同,它仅能判断一种逻辑关系,即表达式是否等于指定的常量,而 if 可以计算并判断各种表达式。
2、case子句后必须为常量,常常是整型和字符型。
3、default可以省略,这时,不满足条件什么也不执行。
4、case和default只起标号的作用,顺序可以颠倒,颠倒时注意后面的break语句。
5、多个case语句可以共用一组程序。
case ‘A’:
case ‘B’:
case ‘C’: cout<<“pass!\n”;
例子:int x=1, y=0, a=0, b=0;
switch( x )
{ case 1:
switch( y )
{ case 0: a++; break;
case 1: b++; break;
}
case 2:
a++; b++; break;
case 3:
a++; b++;
}
cout<<“a=“<<a<<‘\t’<<“b=”<<b<<endl;
输出结果:a=2 b=1
while语句
注意:
1、循环体如果为一个以上的语句,用{ }括起。
2、循环体内或表达式中必须有使循环结束的条件,即一定有一个循环变量。
3、while表达式可以成为语句,要特别小心。
void main(void)
{ int y=10;
while (y--);
cout<<“y=”<<y<<endl;
}输出:y=-1 循环:10次
do—while语句P75
注意:
do—while首先执行循环体,然后再判断表达式,至少执行一次循环体。
对于while,当第一次循环表达式的值为真时,while与do—while的结果完全一样,否则结果不相同。
s=7;
do
s-=2;
while(s= =0);
cout<<“s=”<<s<<endl;
输出:s=5
for语句 P54
注意:
1、当型循环,条件测试是在循环开始时进行,有可能一次也进入不了循环体。
2、for语句中的三个表达式可以部分省略或全部省略,但“;”不能省略,若省略表达式2,则表示循环条件为真。
3、for语句中三个表达式可以是任何有效的C语言表达式。
void main(void)
{ char i, j ;
for (i=‘a’, j=‘z’ ; i<j ; i++, j--)
cout<<i<<j;
cout<<endl;
} 输出:azbycx.......lomn
循环的嵌套
注意:
1、循环体内有多个语句要用{}括起来。
2、书写格式要清晰。
break语句和continue语句P59
break 只能退出一层循环或switch语句。
a=10 ; y=0;
do
{ a+=2; y+=a;
cout<<“a=“<<a<<“, y=“<< y<<endl;
if (y>50) break;
} while (a=14);
第一次:a=12 y=12 第二次:a=16 y=28
第三次:a=16 y=44 第四次:a=16 y=60
continue:其作用为结束本次循环
void main(void)
{ int i;
for (i=1 ; i<=5 ; i++ )
{ if (i%2) cout<<“*”;
else continue;
cout<<“#”;
}
cout<<“ $\n”;
}输出:*#*#*#$
在循环体中,break从循环体内跳出循环体,提前结束循环。
continue:其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
求素数:只可以被1与自身整除的数。
判断一个数 t 是否为素数,用2到t-1循环除。
for( i=2; i<t ; i++)
if(t%i==0)
break;
if (i==t) cout<<“是素数。\n”;
else cout<<“不是素数\n”;
进一步,由于 t 不可能被大于 t/2 的数整除,所以可将循环次数降低。
函数与编译预处理
函数是C++的基本模块
为什么要使用函数?p67
1、避免重复的编程。
2、使程序更加模块化,便于阅读、修改。
所编写的函数应尽量少与主调函数发生联系,这样便于移植。
函数与源程序
1、一个源程序文件由一个或多个函数组成,编译程序以文件而不是以函数为单位进行编译的。
2、一个程序可以由多个源文件组成,可以分别编译,统一执行。
3、一个程序必须有且只有一个main( )函数,C++从main( )函数开始执行。
4、C++语言中,所有函数都是平行独立的,无主次、相互包含之分。函数可以嵌套调用,不可嵌套定义。
5、从使用角度来说,分库函数和用户自定义函数;从形式来说,分无参函数和有参函数。
库函数是C++编译系统已预定义的函数
用户在程序中,根据应用的需要,由用户自己定义函数,这类函数称为用户自定义的函数。
根据定义函数或调用时是否要给出参数,又可将函数分为:无参函数和有参函数。
函数定义的一般形式
一、无参函数
主调函数并不将数据传给被调函数。
无参函数主要用于完成某一操作。
二、有参函数
主调函数和被调函数之间有数据传递。主调函数可以将参数传递给被调函数,被调函数中的结果也可以带回主调函数。
函数参数和函数的值
形参是被调函数中的变量;
实参是主调函数赋给被调函数的特定值。
实参可以是常量、变量或复杂的表达式,不管是哪种情况,在调用时实参必须是一个确定的值。
1、在未出现函数调用时,形参并不占内存的存储单元,只有在函数开始调用时,形参才被分配内存单元。调用结束后,形参所占用的内存单元被释放。
2、实参对形参变量的传递是“值传递”,即单向传递。在内存中实参、形参分占不同的单元。
3、形参只作用于被调函数,可以在别的函数中使用相同的变量名。
void fun(int x, int y)
{ x=x*10;
y=y+x;
cout<<x<<‘\t’<<y<<endl;
}
void main(void)
{ int a=2, b=3;
fun(a+b,a*b);
cout<<a<<‘\t’<<b<<endl;
}
输出结果:50 56 2 3
形参实参类型相等,一一对应
形参必须要定义类型,因为在定义被调函数时,不知道具体要操作什么数,而定义的是要操作什么类型的数。
形参是被调函数中的变量;实参是主调函数赋给被调函数的特定值。在函数调用语句中,实参不必定义数据类型,因为实参传递的是一个具体的值(常量),程序可依据这个数值的表面形式来判断其类型,并将其赋值到对应的形参变量中。
参数的传递方式:
(1)按值传递(单项传递)
#include<iostream.h>
void p(int a ,int b )
{
a++;b++;
}
void main(void)
{
int x=100,y=200; cout<<x<<'\t'<<y<<'\n';
p(x, y);cout<<x<<'\t'<<y<<'\n';
p(x, x);cout<<x<<'\t'<<y<<'\n';
p(y, x);cout<<x<<'\t'<<y<<'\n';
p(y, y);cout<<x<<'\t'<<y<<'\n';
}
(2)引用传递(双向传递)
#include<iostream.h>
void p(int &a ,int b )
{
a++;b++;
}
void main(void)
{
int x=100,y=200; cout<<x<<'\t'<<y<<'\n';
p(x, y);cout<<x<<'\t'<<y<<'\n';
p(x, x);cout<<x<<'\t'<<y<<'\n';
p(y, x);cout<<x<<'\t'<<y<<'\n';
p(y, y);cout<<x<<'\t'<<y<<'\n';
}
函数的返回值
函数的返回值通过return语句获得。
函数只能有唯一的返回值。
函数返回值的类型就是函数的类型。
l return语句可以是一个表达式,函数先计算表达式后再返回值。
l return语句还可以终止函数,并将控制返回到主调函数。
l 一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个语句起作用。
l 既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。
l 不带返回值的函数可说明为void型。
l 函数的类型与函数参数的类型没有关系。
l 如果函数的类型和return表达式中的类型不一致,则以函数的类型为准。函数的类型决定返回值的类型。对数值型数据,可以自动进行类型转换。
l 函数体的类型、形式参数的类型必须在函数的定义中体现出来。
函数的调用 p70
形参与实参类型相同,一一对应。
在一个函数中调用另一函数(即被调用函数)需要具备哪些条件呢?
1) 被调用的函数必须是已存在的函数
2) 如果使用库函数,必须用 #include < math.h>
3) 函数调用遵循先定义、后调用的原则,即被调函数应出现在主调函数之前。
float max(float x, float y)//形参必须说明参数类型
{ float z;被调函数先定义
z=(x>y)? x : y ;
return z;
}
void main (void)
{ float a,b, c;
cin>>a>>b;
c=max (a+b , a*b) ;实参传递的是一个具体的值,不必说明参数类型
cout<<“The max is”<<c<<endl;
}
4) 如果使用用户自己定义的函数,而该函数与调用它的函数(即主调函数)在同一个程序单位中且位置在主调函数之后,则必须在调用此函数之前对被调用的函数作声明。
void main (void)
{ float a,b, c;
float max (float,float);//函数原型说明
cin>>a>>b;
c=max (a,b) ;
cout<<“The max is”<<c<<endl;
}
float max (float x, float y)//函数定义
{ float z;
z=(x>y)? x : y ;
return z;
}
void main(void )
{ int x=2,y=3, z=0;void add(int,int,int);
cout<<“(1) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl;
add (x, y, z);
cout<< (“(3) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl;
}
void add ( int x, int y, int z)
{ z=x+y; x=x*x; y=y*y;
cout<<(“(2) x=“<<x<<“ y=“<<y<<“ z=“<<z<<endl;
}
(1) x=2 y=3 z=0
(2) x=4 y=9 z=5
(3) x=2 y=3 z=0
编写程序,分别计算下列函数的值(x从键盘输入)
float f1(float x)
{ float y;
y=3*x*x*x+2*x*x-1;
return y;
}
void main(void)
{
float x, y;
cin>>x;
y=f1(x);
cout<<“x=“<<x<<“ , y=“<<y<<endl;
}
编写程序,分别计算下列函数的值(x从键盘输入)
当最后一项小于0.00001时,累加结束。
float fun(float x)
{ float s=1, t=1;
do
{ t=t/x;
s+=t;
}while (t>0.00001);
return s;
}
void main(void)
{ float x;
cin>>x;
cout<<“s=“<<fun(x)<<endl;
}
函数的嵌套调用 p75
C语言中,所有函数都是平行独立的,无主次、相互包含之分。函数可以嵌套调用,不可嵌套定义。
int max ( int a, int b)
{ int c;
int min ( int a, int b)
{ return ( a<b? a: b);
}
c=min(a,b);
return ( a>b? a : b);
}
int min ( int a, int b)
{ return ( a<b? a: b);
}
int max ( int a, int b)
{ int c;
c=min(a,b);
return ( a>b? a : b);
}
int power(int m,int n) //m^n
{ int i,product=m;
for(i=1;i<n;i++)
product=product*m;
return product;
}
int sum_of_power(int k,int n) //n^k的累加和
{ int i,sum=0;
for(i=1;i<=n;i++)
sum+=power(i,k);
return sum;
}
void main(void)
{ int k,m;
cin>>k>>m;
cout<<"f("<<k<<","<<m<<")="<<sum_of_power(k,m)<<endl; //m^k的累加和
}
函数的递归调用
在调用一个函数的过程中直接或间接地调用函数本身,称为函数的递归调用。
用递归方法求n!
1 n=0,1
n!= n*(n-1)! n>1
float fac (int n)
{ float y;
if ((n= =0)|| (n= =1) y=1;
else y=n*fac(n-1);
return y;
}
void main (void)
{ float y; int n;
cout<<“Input n:\n”;
cin>>n ;
cout<<n<<“!=”<<fac(n)<<endl;
}
int sub(int);
void main (void)
{ int i=5;
cout<<sub(i)<<endl;
}
int sub (int n )
{ int a;
if (n= =1) return 1;
a=n+sub(n-1);
return a;
}
算法相同,层层调用,每层函数的变量所占内存单元不同。
作用域和存储类 p148
作用域是指程序中所说明的标识符在哪一个区间内有效,即在哪一个区间内可以使用或引用该标识符。在C++中,作用域共分为三类:块作用域、文件作用域、函数原型作用域。
块作用域
我们把用花括号括起来的一部分程序称为一个块。在块内说明的标识符,只能在该块内引用,即其作用域在该块内,开始于标识符的说明处,结束于块的结尾处。
在一个函数内部定义的变量或在一个块中定义的变量称为局部变量。
在函数内或复合语句内部定义的变量,其作用域是从定义的位置起到函数体或复合语句的结束。形参也是局部变量。
主函数main中定义的变量,也只在主函数中有效,同样属于局部变量。
不同的函数可以使用相同名字的局部变量,它们在内存中分属不同的存储区间,互不干扰。
注意:
具有块作用域的标识符在其作用域内,将屏蔽其作用块包含本块的同名标识符,即
变量名相同,局部更优先。
void main(void)
{ int a=2, b=3, c=5;
cout<<a<<‘\t’<<b<<‘\t’<<c<<endl;
{ int a, b=2;
a=b+c;
cout<<a<<‘\t’<<b<<‘\t’<<c<<endl;
}
c=a-b;
cout<<a<<‘\t’<<b<<‘\t’<<c<<endl;
}
void main(void)
{ int a=1,b=2,c=3;
++a;
c+=++b;
{ int b=4, c;
c=b*3;
a+=c;
cout<<“first:”<<a<<‘\t’<<b<<‘\t’<<c<<endl;
a+=c;
cout<<“second:”<<a<<‘\t’<<b<<‘\t’<<c<<endl;
}
cout<<“third:”<<a<<‘\t’<<b<<‘\t’<<c<<endl;
}
文件作用域
在函数外定义的变量称为全局变量。
全局变量的作用域称为文件作用域,即在整个文件中都是可以访问的。
其缺省的作用范围是:从定义全局变量的位置开始到该源程序文件结束。
当在块作用域内的变量与全局变量同名时,局部变量优先。
全局变量增加了函数间数据联系的渠道,在函数调用时可以得到多于一个的返回值。
int min;
int max (int x, int y)
{ int z;
min=(x<y)?x : y;
z=(x>y)? x : y ;
return z;
}
void main (void)
{ int a,b,c;
cin>>a>>b;
c=max (a , b) ;
cout<<“The max is”<<c<<endl;
cout<<“ The min is”<<min<<endl;
}
运行结果:The max is 4
The min is 1
在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量不起作用。
int a=3, b=5;
int max(int a, int b)
{ int c;
c=a>b? a:b;
return c;
}
void main(void)
{ int a=8;
cout<<max(a,b)<<endl;
}
输出结果:8
int x;
void cude(void)
{ x=x*x*x ;
}
void main (void)
{ x=5; //若改为int x=5,输出结果为5
cude ( );
cout<<x<<endl;
}
输出结果:125
在块作用域内可通过作用域运算符“::”来引用与局部变量同名的全局变量。
#include <iostream.h>
int i= 100;
void main(void)
{
int i , j=50;
i=18; //访问局部变量i
::i= ::i+4; //访问全部变量i
j= ::i+i; //访问全部变量i和局部变量j
cout<<”::i=”<<::i<<’\n’;//::i=104
cout<<”i=”<<i<<’\n’;//i=18
cout<<”j=”<<j<<’\n’;//j=108
}
函数原型作用域
在函数原型的参数表中说明的标识符所具有的作用域称为函数原型作用域,它从其说明处开始,到函数原型说明的结束处结束。
float tt(int x , float y); //函数tt的原型说明
由于所说明的标识符与该函数的定义及调用无关,所以,可以在函数原型说明中只作参数的类型说明,而省略参量名。
float tt (int , float);
静态存储:在文件运行期间有固定的存储空间,直到文件运行结束。
动态存储:在程序运行期间根据需要分配存储空间,函数结束后立即释放空间。若一个函数在程序中被调用两次,则每次分配的单元有可能不同。
动态局部变量未被赋值时,其值为随机值。其作用域的函数或复合语句结束时,空间被程序收回。
程序执行到静态局部变量时,为其在静态区开辟存储空间,该空间一直被保留,直到程序运行结束。
由于存储在静态区,静态局部变量或全局变量未赋初值时,系统自动使之为0。
int fun(int a)
{ int c;
static int b=3;
c=a+ b++;
return c;
}
void main(void)
{ int x=2, y;
y=fun(x);
cout<<y<<endl;
y=fun(x+3);
cout<<y<<endl;
}
输出结果:5 8
int f (int a)
{ int b=0;
static int c=3;
b=b+1;
c=c+1;
return a+b+c;
}
void main(void)
{ int a=2,i;
for (i=0;i<3;i++)
cout<<f(a)<<endl;
}
输出结果:7 8 9
int func (int a, int b)
{ static int m=0, i=2;
i+=m+1;
m=i+a+b;
return m;
}
void main(void)
{ int k=4, m=1, p;
p=func(k, m); cout<<p<<endl;
p=func(k, m); cout<<p<<endl;
}
输出:8,17
全局变量的存储方式(extern static)
全局变量是在函数的外部定义的,编译时分配在静态存储区,如果未赋初值,其值为0。
1、extern 存储类别
全局变量的默认方式,当在一个文件中要引用另一个文件中的全局变量或在全局变量定义之前要引用它时,可用extern作说明,相当于扩大全局变量的作用域。
2、静态(static)存储类别
它仅能在本文件中引用,即使在其它文件中用extern说明也不能使用。相当于限制了全局变量的作用域范围。
程序的作用是:给定b的值,输入a和m,求a×b和am的值。
文件file1.c中的内容为:
int a;外部全局变量定义
void main(void)
{ extern int power (int);
int b=3, c, d, m;
cin>>a>>m;
c=a*b;
cout<<a<<“*”<<b<<“=“<<c<<endl;
d= power(m);
cout<<a<<“**”<<m<<“=“<<d<<endl;
}
文件file2.c中的内容为:
extern int a;外部全局变量说明
int power (int n )
{ int i, y=1;
for (i=1; i<=n; i++)
y*=a;引用文件外定义的全局变量
return y;
}
静态局部变量:static 在函数内部定义,存储在静态存储区,与auto对应,在别的函数中不能引用。
全局静态变量:static 在函数外部定义,只限在本文件中使用,与extern对应。
当变量名相同致使作用域相重时,起作用的是最近说明的那个变量。
内联函数
内联函数的实质是用存储空间(使用更多的存储空间)来换取时间(减少执行时间).
内联函数的定义方法是,在函数定义时,在函数的类型前增加修饰词inline。
inline int max (int x, int y)
{
}
void main (void )
{ int a,b,c;
cin>>a>>b;
c=max (a+b , a*b) ;
cout<<“The max is”<<c<<endl;
}
使用内联函数时应注意以下几点:
1、C++中,除在函数体内含有循环,switch分支和复杂嵌套的if语句外,所有的函数均可定义为内联函数。
2、内联函数也要定义在前,调用在后。形参与实参之间的关系与一般的函数相同。
3、对于用户指定的内联函数,编译器是否作为内联函数来处理由编译器自行决定。说明内联函数时,只是请求编译器当出现这种函数调用时,作为内联函数的扩展来实现,而不是命令编译器要这样去做。
4、正如前面所述,内联函数的实质是采用空间换取时间,即可加速程序的执行,当出现多次调用同一内联函数时,程序本身占用的空间将有所增加。如上例中,内联函数仅调用一次时,并不增加程序占用的存储间。
具有缺省参数值和参数个数可变的函数
在C++中定义函数时,允许给参数指定一个缺省的值。在调用函数时,若明确给出了这种实参的值,则使用相应实参的值;若没有给出相应的实参,则使用缺省的值。(举例说明)
int fac(int n=2)
{ int t=1;
for(int i=1;i<=n;i++)
t=t*i;
return t;
}
void main(void)
{
cout<< fac(6) <<endl;//改为fac()输出结果为2
}
输出:720
int area(int long=4 , int width=2)
{ return long* width;
}
void main(void )
{ int a=8, b=6;
cout<< area(a,b) <<endl;//48
cout<< area(a) <<endl;//16
cout<< area( ) <<endl;//8
}
使用具有缺省参数的函数时,应注意以下几点:p84
函数的重载
所谓函数的重载是指完成不同功能的函数可以具有相同的函数名。
C++的编译器是根据函数的实参来确定应该调用哪一个函数的。
int fun(int a, int b)
{ return a+b; }
int fun (int a)
{ return a*a; }
void main(void)
{ cout<<fun(3,5)<<endl;//8
cout<<fun(5)<<endl;//25
}
1、定义的重载函数必须具有不同的参数个数,或不同的参数类型。只有这样编译系统才有可能根据不同的参数去调用不同的重载函数。
2、仅返回值不同时,不能定义为重载函数。
即仅函数的类型不同,不能定义为重载函数
C语言提供的编译预处理的功能有以下三种:p156
宏定义、文件包含、条件编译
1.宏定义
不带参数的宏定义
用一个指定的标识符(即名字)来代表一个字符串,以后凡在程序中碰到这个标识符的地方都用字符串来代替。
这个标识符称为宏名,编译前的替代过程称为“宏展开”。
# define 标识符 字符串
编译程序将宏定义的内容认为是字符串,没有任何实际的物理意义。
1、宏展开只是一个简单的“物理”替换,不做语法检查,不是一个语句,其后不加分号“;”
2、#define命令出现在函数的外面,其有效范围为定义处至本源文件结束。可以用# undef命令终止宏定义的作用域。
3、对程序中用双引号括起来的字符串内容,即使与宏名相同,也不进行置换。
4、在进行宏定义中,可以用已定义的宏名,进行层层置换。
带参数的宏定义
#define 宏名(参数表) 字符串
按#define命令行中指定的字符串从左至右进行置换宏名,字符串中的形参以相应的实参代替,字符串中的非形参字符保持不变。
定义宏时在宏名与带参数的括弧间不能有空格。
带参数的宏与函数调用的区别
相同:有实参、形参,代入调用。
不同之处:
1、函数调用先求表达式的值,然后代入形参,而宏只是机械替换。
2、函数调用时形参、实参进行类型定义,而宏不需要,只是作为字符串替代。
3、函数调用是在运行程序时进行的,其目标代码短,但程序执行时间长。而宏调用是在编译之前完成的,运行时已将代码替换进程序中,目标代码长,执行时间稍快。
一般用宏表示实时的、短小的表达式。
2.文件包含
一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中。
# include “文件名”
1、文件名是C的源文件名,是文本文件,后缀名可以任选。*.cpp *.h
2、一个#include语句只能指定一个被包含文件。
3、文件名用双引号或尖括号括起来。
4、包含后所有源文件编译为一个可执行文件。
3.条件编译P161
C语言允许有选择地对程序的某一部分进行编译。也就是对一部分源程序指定编译条件。
程序的多文件组织
而在设计一个功能复杂的大程序时,为了便于程序的设计和调试,通常将程序分成若干个模块,把实现一个模块的程序或数据放在一个文件中。当一个完整的程序被存放在多于一个文件中时,称为程序的多文件组织。
内部函数和外部函数
内部函数:函数只限于在本文件中调用,其它文件不能调用,用static 定义该函数。
static float fac( int n)
{ ...... }
外部函数:函数的默认形式,可以被其它文件调用,用extern 定义该函数。调用时,在文件中用extern 说明。
void main(void)
{ extern enter_string( );
char str[80];
enter_string(str);
..........
}