C语言数据类型与变量:(二)

本文详细介绍了C语言中typedef定义类型别名、const定义常量的区别以及作用域的概念,包括代码块作用域、文件作用域、原型作用域和函数作用域。同时,讨论了链接属性和存储类型,帮助理解变量的生命周期和内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言数据类型与变量是基础内容,同时也是非常重要的内容,正如上篇所说,它是程序加工的“原料”,只有了解他们的运算规则,熟练运用它们,才能在以后的程序设计中编写出功能强大、健壮且高效的程序,本篇将继续介绍数据类型与变量相关的内容。

1数据类型的别名

1.1 typedef定义类型别名

typedef的使用方式为:

typedef 原类型 别名

typedef实例如下:

typedef char  *ptr//声明ptr为指向char类型的指针变量

1.2 #define定义类型别名

#define使用方式如下:

#define 别名 原类型

#define实例如下:

#define PTR  char *

1.3 typedef #define区别

typedef一般用来定义关键字、冗长的类型的别名;#define为宏定义语句,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它在预编译阶段只是简单的字符替换。

两者区别:typedef定义比较彻底、#define定义比较局限,如下:

typedef char  *ptr;

ptr p1,p2,p3;//定义三个指向char类型的指针变量p1p2p3

 

#define PTR  char *;

PTR p1,p2,p3;

由于#define定义只是简单的字符替换,所以“PTR p1,p2,p3”相当于“char  *p1,p2,p3,因此这条语句其实是定义了指向char类型的指针变量p1以及char变量p2p3......

2.常量

2.1 const定义常量

const用于定义常量,除定义时对const变量赋初值,否则不能再对const变量赋值,如:

 

int const  tmp;

tmp = 3;

定义常量tmp并赋值为3,但是报错,因为const变量不能在声明之后再对其赋值。

易混淆定义形式分析:

 

int const tmp;

const int tmp;

上面两种定义表示的内容一致,都是定义整型的只读变量。

 

int const  *ptr;

ptr为指向整型常量的指针,即ptr地址指向的内容不能更改,但ptr本身可改变。

 

int * const ptr;

声明ptr为常量指针,此时指针不能修改,但指针指向的整型变量值可以修改。

 

int const * const ptr;

该例中,无论指针还是指针指向的变量都是只读的,不允许修改。

2.2 #define定义常量 与const常量区别

#define MAX_ELEMENTS 50;

int cosnt max_elements = 50;

#define定义的常量名一帮为全大写,而const定义常量则无此原则。

上面例子中,使用#define定义常量要比const定义变量好,因为只要允许使用字面值常量的地方均可以使用前者,如声明数组长度;而const只能适用于允许使用变量的地方。

3.作用域

标识符的作用域就是程序中该标识符可以被使用的区域,这也就意味着不同作用域的同名标识符表示不同的含义,因此不同的作用域定义相同的标识符是完全合法的。

标识符声明的位置决定了它的作用域,主要有一下四种作用域:

文件作用域、函数作用于、代码块作用域、原型作用域

3.1代码块作用域

    所有位于一对花括号之间的标识符都具有代码块作用域,表示这些标识符只能在该花括号中被识别。

3.2文件作用域

    所有在代码块之外声明的标识符都具有文件作用域,表示这些标识符从他们声明开始,知道文件结尾处都可以访问。

3.3原型作用域

原型作用域适用于在函数原型中声明的参数名,它允许你在声明和定义函数时使用不同的参数名称,但都表达同样的含义,如:

 

int add(int a,int b);

int add(int c,int d){语句块;}

上面表示同样的函数,前者表示函数add的声明,后者表示add函数的定义。

3.4函数作用域

    函数作用域表示标识符在该函数内有效。

4.链接属性

链接属性决定如何处理不同文件中出现的标识符,它表示不同位置声明的同名标识符是否具有联系(即是否代表同一个标识符)

链接属性一共三种--external(外部)、internal(内部)、none(无),其中:

external(外部):表示位于不同源文件的相同标识符表示同一个实体。

internal(内部):表示位于不同源文件中的相同标识符表示不同的实体,同一源文件中的相同标识符表示相同的实体。

none(无):表示该标识符的所有同名标识符表示不同的实体。

关键字externstatic用于在声明中修改标识符的链接属性。如果某个标识符在正常情况下具有external链接属性,在它前面加上static关键字可以使他的链接属性变为internal

【注意】static可改变external的链接属性为internal;但是extern不能改变static修饰的internal链接属性为external。一下对后者(extern不能改变static声明的链接属性)举例,至于前者可自行运行下看看效果。

 

static int i;

extern int i;

经过上述两条执行语句后,标识符i的链接属性是external还是internal呢?答案是:“static”,即后来对标识符i声明的链接属性external将不起作用,以下写程序验证一下:

 定义两个文件111.c 与 222.c:

/*
* 文件名:111.c
* 程序功能:输出变量i的值
*/
#include <stdio.h>

//static int i =1;
extern int i;
int main(void)
{
	printf("i = %d\n",i);
	return 0;
}

/*
* 文件名:222.c
* 功能:定义变量i的取值
*/
int i = 3;

程序运行结果:


此时运行程序,结果为“i = 3”,这点不难理解,因为extern表链接属性为external(即不同文件的表示符i表示同一标识符),所以文件111.c输出的变量i的值其实就是在文件222.c中定义的变量值。


然后将上述源码文件111.c中的第七行注释拿掉,如下:


程序运行结果:

直观上认为,虽然程序中先对变量i进行了static声明,但在其后又对其进行了extern声明,变量i的取值应该为3才对。之所以出现这种情况,正验证了上面得出的结论:

extern不能改变由static修饰的internal链接属性。

5.存储类型

变量的存储类型是指存储变量的内存类型。变量可存储于:普通内存、运行时堆栈、硬件寄存器。

 

变量的缺省存储类型取决于它被声明的位置。

变量的存储类型有动态与静态之分。

 

动态变量:

在代码块内部声明的变量缺省为动态变量,它门存在于堆栈中,当程序执行到该变量时变量才被创建,当代码块运行完毕时变量作用域结束,变量被自动销毁。当下次再执行到该语句块时,变量再次重复“创建-销毁”的流程。【注意:】多次执行语句块中的变量时,对变量的创建不保证位置上的相同,因此你不能试图保留该变量的位置在语句块外对其进行访问。

 

静态变量:

在代码块外声明的变量以及在代码块内通过关键字static声明的变量属于静态变量。静态存储类型的变量在整个程序生命周期内一直有效,而不仅仅局限于声明变量的作用域。


静态变量&动态变量初始值问题:
对整型而言,静态变量的初始化值为0,动态变量的初始化值不固定。

6.总结

作用域:

作用域表示空间概念,表示程序可以被识别的地方,如程序中有AB两个代码块,那么A中定义的变量只能在A中被访问,B中则无法访问。你或许会说,AB中分别定义同名变量不就实现了A中变量能在B中访问,B变量能在A中访问了吗?非也,从本质上来说,不同语句块中的同名变量就不是同一个变量。

 

存储属性:

存储属性表示时间概念,表示变量在何时被创建、何时销毁。

 

链接属性:

链接属性表示相同或不同文件中的同一标识符(变量、函数)本质上是否是同一个对象。

 

【注意】

1.当对标识符进行访问时,只有当其满足了作用域(空间概念)、存储属性(时间概念)上的要求。如下代码:

/*
* 文件名:333.c
* 程序功能:验证作用域与存储属性对程序的影响
*/
#include <stdio.h>

int i = 5;
int main(void)
{
	{
		static int i =2;
	}
	printf("i = %d\n",i);
}
本实例程序中,程序运行结果如下:
程序输出 i值等于5,为什么是5而不是2呢?下面分析下:
第 7 行定义的i属于静态变量,其生命周期为整个程序运行期间;又因其在语句块外定义,故其作用域为定义开始直至程序结束有效,它涵盖了 13 行中访问变量i的所有语义。
第 11 行定义的i也属于静态变量,其生命周期也为程序运行期间;但因其定义于语句块内,所以它的作用域为语句块开始到语句块结束,它没满足第 13 行的作用域要求。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值