1.在你的机器上,字符的范围有多大?有哪些不同的整数类型?它们的范围又是如何?
解析:
/*
** problem_1_char_range_and_integer_type.cpp.
*/
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <limits.h> /* in this header file has more information about integer */
int main( void ){
printf( "sizeof operator is used to compute the byte size of type or variable:\n" );
printf( "sizeof( char ) = %zd, sizeof( short ) = %zd\n"
"sizeof( int ) = %zd, sizeof( long ) = %zd\n"
"sizeof( long long ) = %zd, sizeof( size_t ) = %d\n",
sizeof( char ), sizeof( short ), sizeof( int ), sizeof( long ), sizeof( long long ), sizeof( size_t ) );
printf( "\n\n" );
/*
** %d is used to output the size of int and the size of type is smaller than int,
** %u is used to output the size of unsigned int and the size of unsigned type is smaller than unsigned int,
** %ld is used to output the size of long and the size of type is smaller than long,
** %lu is used to output the size of unsigned long and the size of unsigned type is smaller than unsigned long,
** %zd is used to output the size of long long or size_t and the size of unsigned type is smaller than long long
** or size_t,
** %llu is used to output the size of unsigned long long and the size of unsigned type is smaller than unsigned
** long long,
** %lld is used to output the size of long long and the size of type is smaller than long long。
*/
printf( "SCHAR_MIN = %d, SCHAR_MAX = %d\n"
"UCHAR_MIN = %u, UCHAR_MAX = %u\n"
"CHAR_MIN = %d, CHAR_MAX = %d\n",
SCHAR_MIN, SCHAR_MAX, 0, UCHAR_MAX, CHAR_MIN, CHAR_MAX );
printf( "CHAR_BIT = %d, MB_LEN_MAX = %d\n\n", CHAR_BIT, MB_LEN_MAX );
printf( "SHRT_MIN = %d, SHRT_MAX = %d\n"
"USHRT_MIN = %u, USHRT_MAX = %u\n\n",
SHRT_MIN, SHRT_MAX, 0, USHRT_MAX );
printf( "INT_MIN = %d, INT_MAX = %d\n"
"UINT_MIN = %u, UINT_MAX = %u\n\n",
INT_MIN, INT_MAX, 0, UINT_MAX );
printf( "LONG_MIN = %ld, LONG_MAX = %ld\n"
"ULONG_MIN = %lu, ULONG_MAX = %lu\n\n",
LONG_MIN, LONG_MAX, 0, ULONG_MAX );
printf( "LLONG_MIN = %lld, LLONG_MAX = %lld\n"
"ULLONG_MIN = %llu, ULLONG_MAX = %llu\n\n",
LLONG_MIN, LLONG_MAX, 0, ULLONG_MAX );
return EXIT_SUCCESS;
}
输出:
2.在你的机器上,各种不同类型的浮点数的范围是怎样的?
解析:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
int main( void ){
printf( "sizeof( float ) = %zd, sizeof( double ) = %zd, sizeof( long double ) = %zd\n",
sizeof( float ), sizeof( double ), sizeof( long double ) );
printf( "FLT_MIN = %e, FLT_MAX = %e\nDBL_MIN = %e, DBL_MAX = %e\nLDBL_MIN = %Le, LDBL_MAX = %Le\n",
FLT_MIN, FLT_MAX, DBL_MIN, DBL_MAX, LDBL_MIN, LDBL_MAX );
return EXIT_SUCCESS;
}
输出:
3.假定你正在编写一个程序,它必须运行于两台机器之上。这两台机器的缺省整型长度并不相同,一个是16位,另一个是32位。而这两台机器的长整型长度分别是32位和64位。程序所使用有些变量的值并不太大,足以保存于任何一台机器的缺省整型变量中,但有些变量的值却很大,必须是32位的整型变量才能容纳它。一种可行的解决方案是用长整型表示所有的值,但在16位机器上,对于那些用16位足以容纳的值而言,时间和空间的浪费不可小视。在32位机器上,也存在时间和空间的浪费问题。如果想让一台机器在编译程序前对程序进行修改。提示:试试包含一个头文件,里面包含每台机器特定的声明。
解析:
声明整型变量名,使变量的类型必须有一个确定的长度(如int8、int16、int32)。对于希望成为缺省长度的整数,根据它所能容纳的最大值,使用类似defint8、defint16或defint32这样的名字。然后为每台机器创建一个名为int_sizes.h的文件,它包含一些typedef声明,为所创建的类型名字选择最合适的整形长度。在一台典型的32位机器上,这个文件将包含:
typedef signed char int8;
typedef short int int16;
typedef int int32;
typedef int defint8;
typedef int defint16;
typedef int defint32;
在一台典型的16位整数机器上,这个文件将包含:
typedef signed char int8;
typedef int int16;
typedef long int int32;
typedef int defint8;
typedef int defint16;
typedef long int defint32;
也可以使用#define指令。
4.假定你有一个程序,它把一个long整型变量赋值给一个short整型变量。当编译程序时会发生什么情况?当运行程序时会发生什么情况?
解析:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int main( void ){
long li = SHRT_MAX + 1;
short si = li;
printf( "SHRT_MIN = %d, SHRT_MAX = %d\n", SHRT_MIN, SHRT_MAX );
printf( "li = %ld, si = %d\n", li, si );
li = 20;
si = li;
printf( "li = %d, si = %d\n", li, si );
return EXIT_SUCCESS;
}
输出:
5.假定你有一个程序,它把一个double变量赋值给一个float变量。当编译程序时会发生什么情况?当运行程序时会发生什么情况?
解析:
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
int main( void ){
printf( "FLT_MIN = %e, FLT_MAX = %e\n", FLT_MIN, FLT_MAX );
printf( "DBL_MIN = %e, DBL_MAX = %e\n", DBL_MIN, DBL_MAX );
printf( "sizeof(FLT_MAX) = %zd, sizeof(float) = %zd, sizeof(DBL_MAX) = %zd, sizeof(double) = %zd\n",
sizeof(FLT_MAX), sizeof(float), sizeof(DBL_MAX), sizeof(double) );
double d = (double)FLT_MAX + 1.0;
float f = d;
printf( "d = %e, f = %e\n", d, f );
d = DBL_MAX;
f = d;
printf( "d = %e, f = %e\n", d, f );
d = 2.0;
f = d;
printf( "d = %f, f = %f\n", d, f );
d = (double)FLT_MAX + FLT_MAX;
f = d;
printf( "d = %e, f = %e\n", d, f );
return EXIT_SUCCESS;
}
输出:
6.编写一个枚举声明,用于定义硬币的值。请使用符号PENNY,NICKEL等。
解析:
#include <stdio.h>
#include <stdlib.h>
enum coin {
PENNY, NICKEL
};
int main( void ){
enum coin coin_var;
coin_var = PENNY;
printf( "coin_var = PENNY, coin_var = %d\n", coin_var );
coin_var = NICKEL;
printf( "coin_var = NICKEL, coin_var = %d\n", coin_var );
return EXIT_SUCCESS;
}
输出:
7.下列代码段会打印什么内容?
enum Liquid{ OUNCE = 1, CUP = 8, PINT = 16, QUART = 32, GALLON = 128 };
enum Liquid jar;
...
jar = QUART;
printf( "%s\n", jar );
jar = jar + PINT;
printf( "%s\n", jar );
变量jar是一个枚举类型,但它的值实际上是个整数。但是,printf格式代码%s用于打印字符串。结果,我们无法判断它的输出会是什么样子。如果格式代码是%d,那么输出将会是:
32
48
解析:
#include <stdio.h>
#include <stdlib.h>
enum Liquid{ OUNCE = 1, CUP = 8, PINT = 16, QUART = 32, GALLON = 128 };
int main( void ){
enum Liquid jar;
jar = QUART;
printf( "%s\n", jar );
/*printf( "%d\n", jar );*/
jar = jar + PINT;
printf( "%s\n", jar );
/*printf( "%d\n", jar );*/
return EXIT_SUCCESS;
}
输出:
#include <stdio.h>
#include <stdlib.h>
enum Liquid{ OUNCE = 1, CUP = 8, PINT = 16, QUART = 32, GALLON = 128 };
int main( void ){
enum Liquid jar;
jar = QUART;
/*printf( "%s\n", jar );*/
printf( "%d\n", jar );
jar = jar + PINT;
/*printf( "%s\n", jar );*/
printf( "%d\n", jar );
return EXIT_SUCCESS;
}
输出:
8.你所使用的C编译器是否允许程序修改字符串常量?是否存在编译器选项,允许或禁止你修改字符串常量?
解析:
#include <stdio.h>
#include <stdlib.h>
int main( void ){
char *p = "message";
printf( "%s\n", p );
p[0] = 'M';
printf( "%s\n", p );
return EXIT_SUCCESS;
}
输出:
9.如果整数类型在正常情况下是有符号类型,那么signed关键字的目的何在呢?
解析:
1.与unsigned形成对照,明确告诉读者整数是有符号的。
2.提醒读者注意算术、比较等操作。
10.一个无符号变量是否可以比相同长度的有符号变量容纳更大的值?
解析:
否,任何给定的n个位的值只有2^n个不同的组合。一个有符号值和无符号值仅有的区别在于它的另一半是如何解释的。在一个有符号值中,它们是负值。在一个无符号值中,它们是一个更大的正值。
#include <stdio.h>
#include <stdlib.h>
int main( void ){
printf(" SHRT_MIN = %d, SHRT_MAX = %d\n"
"USHRT_MIN = %u, USHRT_MAX = %u\n",
SHRT_MIN, SHRT_MAX, 0, USHRT_MAX );
return EXIT_SUCCESS;
}
输出:
11.假如int和float类型都是32位,你觉得哪种类型所能容纳的值精度更大一些?
解析:
float的范围比int大,但如果它的位数不比int更多,则并不能比int表示更多不同的值。前一个问题的答案已经提示了它们能够表示的不同值的数量是相同的,但在绝大多数浮点系统中,这个答案是错误的。零通常有许多种表示形式,而且通过使用不规则的小数形式,其他值也具有多种不同的表示形式。因此,float能够表示的不同值的数量比int少。
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <float.h>
int main( void ){
printf( "sizeof(float) = %zd, sizeof(int) = %zd\n", sizeof(float), sizeof(int) );
return EXIT_SUCCESS;
}
输出:
12.下面是两个代码片段,取自一个函数的起始部分。
int a = 25; int a; a= 25;
它们完成任务的方式有何不同?
解析:
自动变量的初始化较之赋值语句效率并无提高,除了声明为const的变量之外,在声明变量的同时进行初始化和先声明后赋值只有风格之差,并无效率之别。如果是const的自动变量,只能在声明的时候的时候进行初始化;如果不再声明的时候进行初始化,则后续该变量不能被赋值,因为它是个这时的自动变量是个只读自动变量。
13.如果问题12中代码片段的声明中包含有const关键字,它们完成的任务的方式又有何不同?
const int a = 25; const int a; a = 25;
解析:
第一个初始化操作能够通过编译,第二个赋值操作不能够通过编译。
#include <stdio.h>
#include <stdlib.h>
int main( void ){
const int a = 25;
const int b;
return EXIT_SUCCESS;
}
输出:
#include <stdio.h>
#include <stdlib.h>
int main( void ){
const int a = 25;
const int b;
/*
** can't pass compilation:
** because of [Error] assignment of read-only variable 'b'
*/
b = 25;
return EXIT_SUCCESS;
}
输出:
14. 在一个代码块内部声明的变量可以从该代码块的任何位置根据名字来访问。这是对还是错?
解析:
错。只能在所在块的变量声明的后面嵌套的作用域或者同一个作用域才能根据名字访问,并且嵌套的作用域不能含有相同的变量名定义,否则就会隐藏外部同名的变量,从而访问嵌套的作用域中的同名变量。
#include <stdio.h>
#include <stdlib.h>
int var = 3;
int main( void ){
int var = 2;
{
printf( "the outermost var in function main body = %d\n", var );
int var = 5;
printf( "var in function main body second block = %d\n", var );
}
{
printf( "var in function main body third block = %d\n", var );
extern int var;
printf( "after extern var, var = %d\n", var );
}
printf( "var in function main body first block = %d\n", var );
return EXIT_SUCCESS;
}
输出:
15.假定函数a声明了一个自动整型变量x,你可以在其他函数内访问变量x,只要你使用了下面这样的声明:
register int x;
这是对是错?
解析:
错。register声明的变量存储在硬件寄存器中。只有存储于静态内存的全局变量才能在其他函数内访问,并且其声明必须位于访问该变量的函数之前。
#include <stdio.h>
#include <stdlib.h>
/*
** 第1种方式是把声明和定义都放在所有函数的前面。
** int y = 5;
*/
/*
**第2种方式是把声明放在所有函数的前面。
*/
extern int y;
int a( void );
int b( void );
int main( void ){
extern int y;
printf( "y = %d\n", y );
a();
return EXIT_SUCCESS;
}
int y = 5;
int a( void ){
register int x = 1;
printf( "x = %d, y = %d\n", x, y );
return 0;
}
int b( void ){
/*
** can't pass compilation:
** because of [Error] 'x' was not declared in the scope
** printf( "x = %d\n", x );
*/
return 0;
}
输出:
16.假定问题15中的变量被声明为static,答案会不会发生变化?
解析:
不会发生变化。static只是改变了函数里的变量的存储类型,并没有改变变量的作用域。
#include <stdio.h>
#include <stdlib.h>
/*
** 1种方式是把声明和定义都放在所有函数的前面。
** int y = 5;
*/
/* 第2种方式是把声明放在所有函数的前面。 */
extern int y;
int a( void );
int main( void ){
/*
** can't pass compilation:
** because of [Error] 'x' was not declared in this scope
** printf( "x = %d\n", x );
*/
extern int y;
printf( "y = %d\n", y );
return EXIT_SUCCESS;
}
int y = 5;
int a( void ){
static int x;
return 0;
}
输出:
17.假定文件a.c的开始部分有下面这样的声明:
int x;
如果希望从同一个源文件后面出现的函数中访问这个变量。是否需要添加额外的声明?如果需要的话,应该添加什么样的声明?
解析:
不需要添加额外的声明。因为变量是文件作用域,对其声明后面的函数是可见的。
#include <stdio.h>
#include <stdlib.h>
int x = 5;
int access_x( void );
int main( void ){
printf( "in main function, x = %d\n", x );
access_x();
return EXIT_SUCCESS;
}
int access_x( void ){
printf( "in access_x function, x = %d\n", x );
return 0;
}
输出:
18.假定问题17中的声明包含了关键字static。答案会不会有所变化?
解析:
不会发生变化。因为变量的作用域是文件作用域,对其声明后面的函数是可见的。添加static只是改变了变量的链接属性为internal。
#include <stdio.h>
#include <stdlib.h>
static int x = 5;
int access_x( void );
int main( void ){
printf( "in main function, x = %d\n", x );
access_x();
return EXIT_SUCCESS;
}
int access_x( void ){
printf( "in access_x function, x = %d\n", x );
return 0;
}
输出:
19.假定文件a.c的开始部分有下面这样的声明:
int x;
如果希望从不同的源文件的函数中访问这个变量。是否需要添加额外的声明?如果需要的话,应该添加什么样的声明?
解析:
需要添加extern int x用来声明使用的变量。变量x的作用域是文件作用域,链接属性为external,对于其他文件也是可见的。
/*
**problem_19_access_var_in_file.c
*/
#include <stdio.h>
#include <stdlib.h>
int x = 5;
int access_x( void );
int access_x( void ){
printf( "x = %d\n", x );
}
/*
**访问在其他源文件中的链接属性为external的变量或者函数。
**problem_19_access_var_in_file_2.c
**编译和链接:gccproblem_19_access_var_in_file.cpp.c problem_19_access_var_in_file_2.c -o main.exe
**执行:main.exe
*/
#include <stdio.h>
#include <stdlib.h>
/* 声明引用的变量 */
extern int x;
int main( void ){
printf( "x = %d\n", x );
return EXIT_SUCCESS;
}
输出:
20.假定问题19中的声明包含了关键字static。答案会不会发生变化?
解析:
会发生变化。因为变量的作用域是文件作用域,链接属性改变为internal,只对该源文件私有,对于其他文件都是不可见的。
/*
**problem_20_access_static_var_in_file.c
*/
#include <stdio.h>
#include <stdlib.h>
static int x = 5;
int access_x( void );
int access_x( void ){
printf( "x = %d\n", x );
}
/*
**测试能否访问在其他源文件中的全局变量并且链接属性为internal的变量或者函数。
**problem_20_access_static_var_in_file_2.c
**编译和链接:
**gcc problem_20_access_static_var_in_file.c problem_20_access_static_var_in_file_2.c -o main.exe
**执行:main.exe
*/
#include <stdio.h>
#include <stdlib.h>
extern int x;
int main( void ){
printf( "x = %d\n", x );
return EXIT_SUCCESS;
}
输出:
21.假定一个函数包含了一个自动变量,这个函数在同一行中被调用了两次。试问,在函数第2次调用时间开始时该变量的值和函数第1次调用即将结束时的值有无可能相同?
解析:
是的,这是可能的,但不应该指望它。而且,即使不存在其他的函数调用,它们的值也很可能不同。在有些架构上,一个硬件中断将把机器的状态信息压到堆栈上,它们将破坏这些变量。
#include <stdio.h>
#include <stdlib.h>
int return_value( void );
int main( void ){
printf( "return_value = %d, return_value = %d\n", return_value(), return_value() );
return EXIT_SUCCESS;
}
int return_value( void ){
int a;
return a;
}
输出:
22.当下面的声明出现于某个代码块内部和出现于任何代码块外部时,它们的行为有何不同?
int a = 5;
解析:
出现于某个代码块内部a的作用域为代码作用域,链接属性为none,存储类型为自动变量。因此其它函数不能通过变量名访问该变量,并且在函数被调用时创建该变量,函数被调用结束销毁该变量,存储在运行堆栈中。
出现于任何代码块外部时a的作用域为文件作用域,链接属性为external,存储类型为静态变量。因此其它函数可以访问该变量,并且在程序执行之前创建该变量,并设置它的值为5,存储在静态内存中。
/*
** a出现在任何代码块外部时。
** problem_22_global_var.c
*/
#include <stdio.h>
#include <stdlib.h>
int a = 5;
void print( int a );
int main( void ){
print( 1 );
printf( "in main function, a = %d\n", a );
return EXIT_SUCCESS;
}
void print( int a ){
printf( "In print function, a = %d\n", a );
extern int a;
printf( "after extern int a, a = %d\n", a );
}
输出:
/*
** 出现于某个代码块内部。
** problem_22_local_var.c
*/
#include <stdio.h>
#include <stdlib.h>
void print( int b );
int main( void ){
print( 4 );
/*
** can't pass compilation:
** because of [Error] 'a' was not declared in this scope.
** printf( "a = %d\n", a );
*/
return EXIT_SUCCESS;
}
void print( int b ){
int a;
printf( "In print function, a = %d, b = %d\n", a, b );
}
输出:
23.假定你想在同一个源文件中编写两个函数x和y,需要使用下面的变量:
名字 类型 存储类型 链接属性 作用域 初始化为
a int static external x可以访问,y不能访问 1
b char static none x和y都可以访问 2
c int automatic none x的局部变量 3
d float static none x的局部变量 4
应该怎样编写这些变量?应该在什么地方编写?注意:所有初始化必须在声明中完成,而不是通过函数中的任何可执行语句来完成。
解析:
/*
** problem_23_print_value.c
*/
#include <stdio.h>
#include <stdlib.h>
void y( char );
void x( char );
int main( void ){
static char b = '2';
y( b );
x( b );
return EXIT_SUCCESS;
}
void y( char b ) {
printf( "In y( void ) function: \n" );
/*
** can't pass compilation:
** because of [Error] 'a' was not declared in this scope
** printf( "a = %d\n", a);
*/
printf( "b = %c\n", b );
}
int a = 1;
void x( char b ){
printf( "In x( void ) function: \n" );
int c = 3;
static float d = 4;
printf( "a = %d, b = %c, c = %d, d = %f\n", a, b, c, d );
}
输出:
24.确认下面程序中存在的任何错误(你可能想动手编译一下,这样能够踏实一些)。在去除所有错误之后?程序中还有许多同名的标识符,它们所代表的是相同的变量还是不同的变量?程序中的每个函数从哪个位置其可以被调用?
解析:
/*
**int c, d, e = 1; 语句中的c和,要删除。
**program_24_kinds_of_values.cpp
*/
#include <stdio.h>
#include <stdlib.h>
static int w = 5;
extern int x;
static float func1( int a, int b, int c ){
/*int c, d, e = 1;*/
int d = 1, e = 1;
printf( "1:&a = %p, &b = %p, &c = %p\n&d = %p, &e = %p, &w = %p\n", &a, &b, &c, &d, &e, &w );
printf( "1:a = %d, b = %d, c = %d\nd = %d, e = %d, w = %d\n", a, b, c, d, e, w );
/*...*/
{
int d = 2, e = 2, w = 1;
printf( "2:&d = %p, &e = %p, &w = %p\n", &d, &e, &w );
printf( "2:d = %d, e = %d, w = %d\n", d, e, w );
/*...*/
{
int b = 2, c = 2, d = 3;
static int y = 2;
printf( "3:&b = %p, &c = %p, &d = %p, &y = %p\n", &b, &c, &d, &y );
printf( "3:b = %d, c = %d, d = %d, y = %d\n", b, c, d, y );
/*...*/
}
}
/*...*/
{
register int a = 2, d = 4, x = 2;
extern int y;
printf( "4:&a = %p, &d = %p, &x = %p\n", &a, &d, &x );
printf( "4:a = %d, d = %d, x = %d\n", a, d, x );
/*...*/
}
}
static int y;
float func2( int a ){
extern int y;
static int z;
printf( "5:&a = %p, &y = %p, &z = %p, &w = %p\n", &a, &y, &z, &w );
printf( "5:a = %d, y = %d, z = %d, w = %d\n", a, y, z, w );
/*...*/
}
int main( void ){
func1( 34, 35, 36 );
func2( 70 );
printf( "6:&w = %p, &y = %p\n", &w, &y );
printf( "6:w = %d, y = %d\n", w, y );
return EXIT_SUCCESS;
}
输出:
比较变量的地址和值是否相同可以判断是否使用的是同一个变量。