• 回复
  • 收藏
  • 点赞
  • 分享
  • 发新帖

朱兆祺教你C语言笔试、学习与机试难点(连载)

C语言编程中的几个基本概念

1.1 #include< >与#include" "

1. #include< >和#include" "有什么区别?

这个题目考查大家的基础能力,#include< >用来包含开发环境提供的库,

#include" "用来包含.c/.cpp文件所在目录下的头文件。注意:有些开发环境可以在当前目录下面自动收索(包含子目录),有些开发环境需要指定明确的文件路径名。

1.2 switch()

1. switch(c) 语句中 c 可以是 int, long, char, float, unsigned int 类型?

其实这个题目很基础,c应该是整型或者可以隐式转换为整型的数据,很明显不能是实型(float、double)。所以这个命题是错误的。

1.3 const

1. const有什么用途?

虽然const很常用,但是我相信有很多人仍然答不上来。

(1) 欲阻止一个变量被改变,可以使用const 关键字。在定义该 const 变量时,通常需要对它进行初 始化,因为以后就没有机会再去改变它了;

(2) 对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 const,或二者同时指定为 const;

(3) 在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;

(4) 对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不能修改类的成员变量;

(5) 对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返回值不为“左值”。

1.4 #ifndef/#define/#endif

1. 头文件中的 #ifndef/#define/#endif 干什么用?

其实#ifndef、#define、#endif这些在u-boot、linux内核文件中经常见到,在这么大型的程序中大量使用,可见它的作用不可小觑。

这些条件预编译多用于对代码的编译控制,增加代码的可裁剪性,通过宏定义可以轻松的对代码进行裁剪。

#ifndef/#define/#endif最主要的作用是防止头文件被重复定义。

1.5 全局变量和局部变量

1. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

全局变量储存在静态数据库,局部变量在堆栈。 其实,由于计算机没有通用数据寄存器,则函数的参数、局部变量和返回值只能保存在堆栈中。提示:局部变量太大可能导致栈溢出,所以建议把较大数组放在main函数外,防止产生栈溢出。

思考:如程序清单1. 1所示。会出现怎样的情况?

程序清单1. 1 大数组放在main函数中导致堆栈溢出

int main(int argc, char *argv[])

{

int iArray[1024 * 1024];

return 0;

}

全部回复(1)
正序查看
倒序查看
一木01
LV.3
2
2014-02-15 16:46

第二节 数据存储与变量

2.1 变量的声明与定义

1. 如程序清单2. 1所示会不会报错?为什么?如果不会报错,又是输出什么结果?

程序清单2. 1 变量的声明与定义

#include

static int a ;

static int b[] ;

int main( int argc , char *argv[] )

{

printf( "%d %d \n" , a , b[0] ) ;

return 0 ;

}

static int a = 8 ;

static int b[4] ;

这个程序是不会报错的,并且连警告都不会出现。输出的结果是:8 0

static int a ,这句程序是声明全局变量a;static int b[],这句程序是声明全局数组变量b,并且是不完全声明,也就是可以省略数组下标。static int a = 8,这里才是定义全局变量a,static int b[4],这里是定义全局变量b。

2.2 局部变量与全局变量的较量

1. 请问如程序清单2. 2所示输出什么?

程序清单2. 2 局部变量与全局变量

#include

static int a = 8 ;

int main( int argc , char *argv[] )

{

int a = 4 ;

printf( "%d \n" , a ) ;

return 0 ;

}

C语言规定,局部变量在自己的可见范围内会“挡住”同名的全局变量,让同名的全局变量临时不可见。即在局部变量的可见范围内不能访问同名的全局变量。因此本程序输出为:4。

2.3 char、int、float、double的数据存储

1. 请问如程序清单2. 3所示,i和j输出什么?

程序清单2. 3 数据存储

float i = 3 ;

int j = *(int*)(&i) ;

printf( "i = %f \n" , i ) ;

printf( "j = %#x \n" , j ) ;

i是毋庸置疑是:3.000000。但是j呢?3.000000?答案是否定的,j是输出:0x4040 0000。有人会问了,难道j是随机输出?瞎说,j输出0x4040 0000是有依据,是一个定值!

由于i是float数据类型,而j是int数据类型。理论上说,j是取了i的地址然后再去地址,应该得到的就是i的值:3。但是问题的关键就是float数据类型的存储方式和int数据类型不一样,float是占用4个字节(32位),但是float存储是使用科学计数法存储,最高位是存储数符(负数的数符是0,正数的数符是1);接下来8位是存储阶码;剩下的23位是存储尾数。上面i=3.000000,那么3.000000(10进制) = 11(2进制) = (二进制)。数据在电脑中存储都是二进制,这个应该都没有疑问。那么这里的数符为:0 ,阶码为:E – 127 = 1 ,那么阶码为:E = 128 即为:1000 0000 (2进制) ,尾数为:100 0000 0000 0000 0000 0000 。那么存储形式就是:0100 0000 0100 0000 0000 0000 0000 0000。这个数据转换成16进制就是0x4040 0000。

 

图2. 1 数据存储方式

char、int、float、double的存储方式如图2. 1所示。

提问:如果i = -3.5 的话,请问j输出多少?

i = -3.500000

j = 0xc0600000

这个希望读者自行分析。

再问:如果如程序清单2. 4所示。

程序清单2. 4 数据存储

double i = 3 ;

int j = *(int*)(&i) ;

printf( "i = %lf \n" , i ) ;

printf( "j = %#x \n" , j ) ;

这样的话,j又输出多少呢?

提示:double( 8个字节(64位) )的存储方式是:最高位存储数符,接下来11位存储阶码,剩下52位存储尾数。

是不是得不到你想要的结果?double是8个字节,int是4个字节。一定别忘记了这个。用这个方法也同时可以验证大小端模式!

2.4 容易忽略char的范围

1. 如程序清单2. 5所示,假设&b=0x12ff54,请问三个输出分别为多少?

程序清单2. 5 char的范围

unsigned int b = 0x12ff60 ;

printf("( (int)(&b)+1 ) = %#x \n" , ( (int)(&b)+1 ) ) ;

printf("*( (int*)( (int)(&b)+1 ) ) = %#x \n" , *( (int*)( (int)(&b)+1 ) ) ) ;

printf("*( (char*)( (int)(&b)+1 ) ) = %#x \n" , *( (char*)( (int)(&b)+1 ) ) ) ;

很显然,&b是取无符号整型b变量的地址,那么(int)(&b)是强制转换为整型变量,那么加1即为0x12ff54+1=0x12ff55。所以( (int)(&b)+1 )是0x12ff55。

 

图2. 3 指针加1取字符型数据

由于( (int)(&b)+1 )是整型数据类型,通过(int *)( (int)(&b)+1 )转化为了整型指针类型,说明要占4个字节,即为:0x12ff55、0x12ff56、0x12ff57、0x12ff58,再去地址*( (int *)( (int) (&b)+1 ) )得到存储在这4个字节中的数据。但是很遗憾,0x12ff58我们并不知道存储的是什么,所以我们只能写出0x**0012ff。**表示存储在0x12ff58中的数据。如图2. 2所示。

 

图2. 2 指针加1取整型数据

以此类推,*( (char *)( (int) (&b)+1 ) ) = 0xff。如图2. 3所示。

但是,*( (char *)( (int) (&b)+1 ) )输出的却是:0xff ff ff ff !

问题出现了,为什么*( (char *)( (int) (&b)+1 ) )不是0xff,而是0xff ff ff ff?char型数据应该占用1个字节,为什么会输出0xff ff ff ff?

使用%d输出,

printf("*( (char*)( (int)(&b)+1 ) ) = %d \n" , *( (char*)( (int)(&b)+1 ) ) ) ;

结果为-1???

问题出在signed char 的范围是:-128~127,这样肯定无法储存0xff,出现溢出。所以将

printf("*( (char*)( (int)(&b)+1 ) ) = %#x \n" , *( (char*)( (int)(&b)+1 ) ) ) ;

改成

printf("*( (unsigned char*)( (int)(&b)+1 ) ) = %#x \n" ,

*( (unsigned char*)( (int)(&b)+1 ) ) ) ;

就可以输出0xff,因为unsigned char 的范围是:0~255(0xff)。

0
回复