3.2 基本声明
变量声明的基本形式是:
说明符(一个或多个) 声明表达式列表
对于简单的类型,声明表达式列表就是被声明的标识符的列表。对于更为复杂的类型,声明表达式列表中的每个条目实际上是一个表达式,显示被声明的名字的可能用途。
说明符(specifier)包含了一些关键字,用于描述被声明的标识符的基本类型。说明符也可以用于改变标识符的缺省存储类型和作用域。
基本的变量声明:
int i;
char j, k, l;
说明符也可能是一些用于修改变量的长度或是否为有符号数的关键字。这些关键字是:
short long signed unsigned
同时,在声明整型变量时,如果声明中已经至少有了一个其他的说明符,关键字int可以省略。因此,下面两个声明的效果是相等的:
unsigned short int a;
unsigned short a;
signed关键字一般只用于char类型,因为其他整型类型在缺省情况下都是有符号数。至于char是否是signed,则因编译器而异。
浮点类型在这方面要简单一些,因为除了long double,其余几个说明符(short、signed和unsigned)都是不可用的。
相等的整型声明
short signed short | unsigned short
short int signed short int | unsigned short int
int signed int | unsigned int
signed | unsigned
long signed long | unsigned long
long int signed long int | unsigned long int
#include
#include
int i;
static int static_i;
signed int si;
unsigned int ui;
static unsigned int ssi;
char ch;
int main( void ){
int loc_i;
static int loc_static_i;
register int loc_reg_i;
char ch;
long double ld;
return EXIT_SUCCESS;
}
3.2.1 初始化
在一个声明中,可以给一个标量变量指定一个初始值,方法是在变量名后面跟一个等号(赋值号),后面是想要赋给变量的值。例如:
int j = 15;
3.2.2 声明简单数组
声明一个一维数组,在数组名后面要跟一对方括号,方括号里面是一个整数,指定数组中元素的个数。例如:
int values[20];
显而易见的解释是:声明了一个数组,数组包含20个整型元素。一种更好的方法来阅读这个声明。名字values加一个下标,产生一个类型为int的值(共有20个整型值)。这个“声明表达式”显示一个表达式中的标识符产生了一个基本类型的值,在本例中为int。
数组的下标总是从0开始,最后一个元素的下标是元素的数目减1。
C数组另一个值得关注的地方是,编译器并不检查程序对数组下标的引用是否在数组的非法范围之内。好处是不需要浪费时间对有些已知是正确的数组下标进行检查。坏处是这样做将无法检测出无效的下标引用。一个良好的经验法则是:
如果下标值是从那些已知是正确的值计算得来,那么就无须检查它的值。如果一个用作下标的值是根据某种方法从用户输入的数据产生的,那么在使用它之前必须进行检测,确保它们位于有效的范围之内。
#include
#include
int
main( void ){
int a[] = { 1, 2, 3, 4, 5 };
int i;
int len;
len = sizeof( a ) / sizeof( *a );
printf( "print elements of array: n" );
for( i = 0; i < len; i++ ){
printf( "%d ", a[i] );
}
printf( "n" );
return EXIT_SUCCESS;
}
3.2.3 声明指针
声明表达式也可用于声明指针。在C语言的声明中,先给出一个基本类型,紧随其后的是一个标识符列表,这些标识符组成表达式,用于产生基本类型的变量。例如:
int *a;
这条语句表示表达式*a产生的结果类型为int。知道了*操作符执行的是间接访问操作以后,我们可以推断出a肯定是一个指向int的指针。
indirection在本书中译为“间接访问”。
间接访问操作只对指针变量才是合法的。指针指向结果值。对指针进行间接访问操作可以获得这个结果值。
警告:
int* a,把星号挨着类型并不是一个好技巧,原因如下:
int* b, c, d;
星号实际上只是表达式*b的一部分,只对这个标识符有用。b是一个指针,但其余两个变量只是普通的整型。要声明3个指针,正确的语句如下:
int *b, *c, *d;
在声明指针时,也可以为它指定初始值。例如:
char *message = "Hello world";
message声明了一个指向字符的指针,并用字符串常量中第一个字符的地址对该指针进行初始化。
警告:
看上去初始化值似乎是赋给表达式*message,事实上它是赋给message本身的。换句话说,前面一个声明相当于:
char *message;
message = "Hello world!";
3.2.4 隐式声明
C语言中有几种声明,它的类型可以省略。例如,函数如果不显式地声明返回值的类型,它就默认返回整型。当使用旧风格来声明函数的形式参数时,如果省略了参数的类型,编译器就会默认它们为整型。最后,如果编译器可以得到足够的信息,推断出一条语句实际上是一个声明时,如果它缺少类型名,编译器会假定它为整型。
考虑下面这个程序:
int a[10];
int c;
b[10]; //缺少类型名 (3)
d; //缺少类型名 (4)
f( x ) //缺少返回类型,编译器默认它返回整型,参数x默认为整型
{
return x + 1;
}
第3行和第4行在ANSI C中却是非法的。
提示:
依赖隐式声明可不是一个好主意。容易留下疑问:是有意遗漏类型名呢,还是不小心忘记写了?显示声明就能够清楚地表达你的意图。
#include
#include
int main( void ){
int* b, c;
int *d, *e;
const char *message = "Hello world!", *message2 = "Hello world!!";
c = 1;
b = &c;
e = NULL;
printf( "c: the value of c = %d, *b: the value of *b = %dnb: the content of b = %p, &c: the address of c = &cn",
c, *b, b, &c );
printf( "%%p is used to print a pointer;n%%s is used to print string, it will stop until it encounters a \0.n" );
printf( "message: the vale of message = %pnmessage2: the value of message2 = %p, e: the value of e = %pn",
message, message2, e );
printf( "message: the content pointed to by message = %snmessage2: the value pointed to by message2 = %s, e: the value of e = %pn",
message, message2, e );
printf( "string literal in an expression, the value of literal will convert to pointer points to const char:n" );
printf( ""Hello world!": the value of "Hello world!" = %pn"Hello world!!": the value of "Hello world!!" = %pn",
"Hello world!", "Hello world!!" );
printf( ""Hello world!": the content of "Hello world!" = %sn"Hello world!!": the content of "Hello world!!" = %sn",
"Hello world!", "Hello world!!" );
return EXIT_SUCCESS;
}



