理解变量标识符的作用域和可见性,以及变量生存期。
(1)标识符的作用域和可见性
作用域:作用域是一个标识符在源程序中有效的区域。
可见性:程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。
(2)变量生存期:
变量的生存期就是指变量从创建到销毁的时间范围。变量按照生存期分“静态生存期”和“动态生存期”。静态生存期:如果变量的生存期与程序的运行期相同,则称该变量具有“静态生存期”; 动态生存期:变量生存期始于创建声明点,结束于作用域结束处。
注意:源程序声明(定义)变量原则:满足需要的情况下,缩短标识符作用域,缩短变量生存期。
1 /* 2 *变量练习 3 * 4 *理解标识符的作用域和可见性,以及变量生存期。 5 * 6 *作用域:作用域是一个标识符在源程序中有效的区域。 7 *可见性:程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。 8 * 9 * 10 *变量生存期:变量的生存期就是指变量从创建到销毁的时间范围。 11 * 12 *变量按照生存期分“静态生存期”和“动态生存期”。 13 *静态生存期:如果变量的生存期与程序的运行期相同,则称该变量具有“静态生存期”; 14 *动态生存期:变量生存期始于创建声明点,结束于作用域结束处。 15 */ 16 17 int value;//对于全局变量,编译器会在编译期自动初始化为零 18 19 void func() 20 { 21 int value2 = 2;//局部变量 22 printf("%d\n", value2); 23 } 24 25 int main() 26 { 27 value4 = 0;//局部变量。 28 { 29 int value3 = 3;//局部变量。 30 //该条变量定义语句定义的变量作用域为:自其定义语句起到当前大括号结束为止。 31 //我们称这类局部变量具有“块作用域”,也称为“块变量” 32 printf("%d\n", value3); 33 printf("%d\n", value4); 34 } 35 //func(); 36 //printf("%d\n", value2);//编译器error:value2没有被定义 37 //printf("%d\n", value3);//编译器error: value3没有被定义。 38 return 0 39 }
变量类型修饰符(type-specifier)
auto关键字可以用来声明变量,所有的局部变量自动就是auto的,所以源程序中根本不需要特别声明。
static关键字可以用来声明静态变量。静态全局变量的作用域被缩小成声明它的那个文件里面的所有语句。静态局部变量在程序一开始运行就被创建直到程序结束才被销毁,它的生存期被拉长为整个程序运行期。
/*static类型修饰符修饰局部变量时可以实现改变变量的生存期,但无法改标识符在源程序中的作用域和可见性。
*static类型修饰符修饰全局变量时可以实现改变变量的作用域。*/
register关键字可以用来声明寄存器变量。
volatile关键字可以声明易变变量。
const关键字可以用来声明不可变变量。
语言中的地址数据和指针
指针变量是用来存放地址数据的变量。
指针变量声明语法如下:
int *p_value;//声明语句中标识符前的星号表示p_value是指针类型。
int *p_value1, value1, *p_value2, temp,
integer;//本声明语句中的标识符有星号的表示是指针类型,没有星号的是int类型。也就是说p_value1,
p_value2的类型是int*, value1, temp, integer的类型是int
两个最基本的地址运算操作符&和*。其中*是间接访问操作符,&是取址操作符。他们的运算优先级极高。
范例练习:
1 /* 2 *秒表练习 3 *了解库函数sleep() time() 4 * 5 */ 6 7 #include <stdio.h> 8 #include <time.h> 9 #include <unistd.h> 10 11 int main() 12 { 13 int start = time(0);//time(0)返回值是现今与1970年1月1日0时0分0秒(0时区)的秒数 14 while(1) { 15 printf("%d\r", time(0) - start);//注意printf打印输入字符流时候,首先是将输出字符放入输出缓冲区,当输出缓冲区中有换行符时候才会打印到屏幕 16 fflush(stdout);//立即打印输出缓冲区中的字符流 17 sleep(1);//库函数sleep实现让当前程序休眠一秒钟 18 } 19 return 0; 20 }
1 /* 2 * const type-specifier练习 3 * 4 * */ 5 6 #include <stdio.h> 7 8 int main() 9 { 10 const int value = 0; 11 printf("value是%d\n", value); 12 //value = 3;//编译报错,const 类型修饰符只能在初始化时候放入数据,一旦初始化完成就不能再放入数据。也就是说变量value不再改变。 13 //value++; 14 printf("value是%d\n", value); 15 16 return 0; 17 }
1 /* 2 * 静态局部变量练习 3 * */ 4 5 #include <stdio.h> 6 7 void f() 8 { 9 //int value = 0; 10 static value = 0;//静态局部变量在程序一开始运行时就被创建了,直到整个程序运行结束才会被销毁。静态局部变量具有静态生存期。 11 /*static类型修饰符修饰局部变量时可以实现改变变量的生存期,但无法改标识符在源程序中的作用域和可见性。 12 *static类型修饰符修饰全局变量时可以实现改变变量的作用域。*/ 13 printf("f()中value是%d\n", value); 14 value++; 15 } 16 17 int main() 18 { 19 f(); 20 f(); 21 return 0; 22 }
1 /* 2 * 函数返回指针类型数据 3 * 4 * 5 * 指针变量可以作为函数返回值使用,只能把全局变量的地址、静态局部变量的地址或者通过参数获得的地址当做返回值使用。普通局部变量因生存期问题导致使用普通变量的地址作为返回值非常危险,所以绝对不要讲普通局部变量的地址作为返回值使用。 6 * 7 * */ 8 #include <stdio.h> 9 int *func() 10 { 11 static int value = 0; 12 printf("value是%d\n", value); 13 14 return &value; 15 } 16 17 int main() 18 { 19 int *p_value = NULL; 20 p_value = func(); 21 printf("p_value = func(); *p_value是%d\n", *p_value); 22 *p_value = 7; 23 func(); 24 printf("*p_value是%d\n", *p_value); 25 return 0; 26 }