C变量
变量其实只不过是程序可操作的存储区的名称。C中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为C是对大小写敏感的。有以下几种基本的变量类型:
类型 | 描述 |
---|---|
char | 通常是一个字节(八位)。这是一个整数类型 |
int | 对机器而言,整数的最自然的大小。 |
float | 单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。![]() |
double | 双精度浮点值。双精度是1位符号,11位指数,52位小数。![]() |
void | 表示类型的缺失。 |
C语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等,这些将会在后续更新中讲解。
C中的变量定义
变量定义就是告诉编译器在何处创建变量的存储,以及如何让创建变量的存储。变量定义指定一个数据类型,并包含了该类型的一个或多个变量的列表,如下所示:
type variable_list;
在这里,type必须是一个有效的C数据类型,可以是char、w_char、int、float、double或任何用户自定义的对象,variable_list可以由一个或多个标识符名称组成,多个标识符之间用逗号分隔。下面列出了几个有效的声明:
int i,j,k;
char c,ch;
float f,salary;
double d;
行int i,j,k;声明并定义了变量i、j和k,这指示编译器创建类型位int的名位i,j,k的变量。变量可以在声明的时候被初始化(指定一个初始值)。初始化器由一个等号,后跟一个常量表达式组成,如下所示:
type variable_name=value;
下面列举几个实例:
extern int d=3,f=5; //d和f的声明与初始化
int d=3,f=5; //定义并初始化d和f
byte z=22; //定义并初始化z
char x='x'; //变量x的值为'x'
不带初始化的定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的。
C中的变量声明
变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。变量的声明有两种情况:
- 一种是需要建立存储空间的。例如:int a在声明的时候就已经建立存储空间。
- 另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。例如:extern int a其中变量a可以在别的文件中定义的。
- 除非有extern关键字,否则都是变量的定义。
- 注意:int a;或int a=1;这种的只能在程序中出现一次;但是extern int a;能出现很多次。
extern int i;//声明,不是定义
int i;//声明,也是定义
实例
通过下面的实例,其中,变量在头部就已经被声明,但是定义与初始化在主函数内:
#include<stdio.h>
//函数外定义变量x和y
int x;
int y;
int addtwonum()
{
//函数内声明变量x和y为外部变量
extern int x;
extern int y;
//给外部变量(全局变量)x和y赋值
x=1;
y=2;
return x+y;
}
int main()
{
int result;
//调用函数addtwonum
result=addtwonum();
printf("result为:%d",result);
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
result为:3
C中的左值和右值
C中有两种类型的表达式:
- 左值(lvalues):指向内存位置的变大时被称为左值表达式。左值可以出现在赋值号的左边或右边。
- 右值(rvalues):术语右值指的是存储在内存中某些地址的数值。右值是不能对其进行赋值的表达式,也就是说,右值可以出现在赋值号的右边,但不能出现在赋值号的左边。
变量是左值,因此可以出现在赋值号的左边。数值型的字面值是右值,因此不能被赋值,不能出现在赋值号的左边。下面是一个有效的语句:
int g=20;
但是下面这个就不是一个有效的语句,会生成编译时错误:
10=20;
注意:当需要保存数据的时候,需要左值(lvalues)。当需要读取数据的时候,需要右值(rvalues)。
变量的内存寻址
- 内存寻址由大到小,优先分配内存地址比较大的字节给变量,所以说变量越先定义,内存地址就越大。如下面代码,先定义变量a,再定义变量b,打印出a的地址是0000003F128FF7E4,b的地址是0000003F128FF804。a的地址比b的地址大4字节。
- 变量地址的获取方式:&变量名。(&为地址符)
- 输出地址的方式:%p
例如:
#include <stdio.h>
int main()
{
int a;
int b;
printf("a的地址是%p\nb的地址是%p\n",&a,&b);
return 0;
}
- 一个变量一定要先初始化才可以使用,因为C语言中默认一个没有初始化的变量值是一个不可知的很大值。
#include <stdio.h>
int main()
{
int a;
printf("a的值是%d\n",a);
return 0;
}
全局变量和局部变量在内存中的区别
全局变量保存在内存的全局存储区中,占用静态的存储单元;局部变量保存在栈中,只有在所在函数被调用是才动态地为变量分配存储单元。
C语言经过编译之后将内存氛围以下几个区域:
- (1)栈(stack):有编译器进行管理,自动分配和释放,存放函数调用过程中的各种参数、局部变量、返回值以及函数返回地址。操作方式类似数据结构中的栈。
- (2)堆(heap):用于程序动态申请分配和释放空间。C语言中的malloc和free,C++中的new和delete均是在堆中进行的。正常情况下,人为申请的空间在使用结束后应该释放,若没有人为释放空间,则程序结束时系统自动回收。注意:这里的“堆”不是数据结构里的“堆”。
- (3)全局(静态)存储区:分为DATA段和BSS段。DATA段(全局初始化区)存放初始化的全局变量和静态变量;BSS段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BSS段在程序执行之前会被系统自动清零,所以未初始化的全局变量和静态变量在程序执行之前已经为0.
- (4)文字常量区:存放常量字符串。程序结束后由系统释放。
- (5)程序代码区:存放程序的二进制代码。
- 显然,C语言中的全局变量和局部变量在内存中是有区别的。C语言中的全局变量包括外部变量和静态变量,均是保存在全局存储区中,占用永久性的存储单元;局部变量,即自动变量,保存在栈中,只有在所在函数被调用时才由系统动态在栈中分配临时性的存储单元。
请分析下面代码的运行结果:
#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main( )
{ static int m1=2, m2;
int i=1;
char*p;
char str[10] = "hello";
char *q = "hello";
p= (char *)malloc( 100 );
free(p);
printf("栈区-变量地址 i:%p\n", &i);
printf(" p:%p\n", &p);
printf(" str:%p\n", str);
printf(" q:%p\n", &q);
printf("堆区地址-动态申请:%p\n", p);
printf("全局外部有初值 k1:%p\n", &k1);
printf(" 外部无初值 k2:%p\n", &k2);
printf("静态外部有初值 k3:%p\n", &k3);
printf(" 外静无初值 k4:%p\n", &k4);
printf(" 内静态有初值 m1:%p\n", &m1);
printf(" 内静态无初值 m2:%p\n", &m2);
printf("文字常量地址 :%p, %s\n",q, q);
printf("程序区地址 :%p\n",&main);
return 0;
}