c语言关于char类型的几道面试题

数据是以二进制补码存放在计算机中的,其中signed char类型的范围是[-128,127],unsigned char类型的范围是[0,255]。这是因为signed char类型在32位机器中占8个字节,最高位是符号位,所以正数的范围是:00000000——01111111(0到127),负数的范围是:10000000——11111111,因为不可以出现负0,所以10000000被规定值是-128。所以整个signed char的取值范是[-127,128]。那么unsigned char 就更好理解:00000000——11111111(0到255)。

下面我们来看几个典型试题和面试题。

1.

#include <stdio.h>
#include <windows.h>
int main(){
	char a = -1;
	unsigned char b = -1;
	printf("%d %d\n", a, b);
	system("pause");
	return 0;
}

 

这道题的结果为什么会是这样呢?明明都赋值为-1,而b打印出来确是255,下面来简要分析一下代码的执行流程:

赋值: 数字在计算机中都是以二进制补码存储的,所以整形-1在32位机器下计算机中的存储形式是:11111111111111111111111111111111。在把int型的变量赋值给char形会发生截断现象,取int的低8位,因为char类型占1个字节(8比特位),所以这时在变量a和b中存储的都是:11111111(存储时与变量类型无关,只看当前数字的二进制补码)。

打印:因为%d打印的是有符号整型,所以在打印字符型变量时,发生整型提升,整型提升关键看变量类型(指的是a或者b,与它们之中存储的数据无关)。如果是有符号数(signed),先看符号位为几(负数为1正数为0),就在前面的高位补24个1或者24个0。如果是无符号(unsigned),前面的高位补24个0。a是有符号数,整型提升时,符号位是1,所以整型提升后的补码为:11111111111111111111111111111111,计算机识别它为-1,所以就打印出了-1。而b是无符号char型,整型提升时直接补上24个0,补码为:00000000000000000000000011111111,因为正数的补码和原码相同,所以计算机直接识别它为255。

2.

#include <stdio.h>
#include <windows.h>
int main(){
	char a = -128;
	printf("%u", a);
	system("pause");
	return 0;
}

看完第一题,这个代码就好理解多了,因为在signed char中规定,-128的二进制表示为:10000000(即是原码又是补码)。在赋值时所以在打印时发生整型提升,因为是有符号数,先看符号位,符号位是1,直接补上24个1:11111111111111111111111110000000。又因为是按照无符号打印(%u,直接把内存中的补码数据按照正数打印),所以出现了4294967168,它的二进制补码就是:11111111111111111111111110000000。

3.

#include <stdio.h>
#include <windows.h>
int main(){
	int a = -20;
	unsigned int b = 10;
	printf("%d", a + b);
	system("pause");
	return 0;
}

这个代码很有意思,如果没有接触过c语言,可能会直接给出正确答案,那不就是-10嘛。但是等你学完c语言的隐式类型转换后可能会对这道题犯愁了, 因为a和b的类型不同,不能直接进行算数计算。所以要把int型转换成unsigned int型(规定),1111 1111 1111 1111 1111 1111 1110 1100和00000000000000000000000000001010直接进行加法运算(符号位也参与运算)得到:1111 1111 1111 1111 1111 1111 1111 0110。因为按照有符号数打印,所以补码转原码后是:-10。

4.

#include <stdio.h>
#include <windows.h>
int main(){
	unsigned int i;
	for (i = 9; i >= 0; i--){
		printf("%u\n", i);
		Sleep(500);//睡眠函数,让程序睡眠0.5秒后执行
	}
	system("pause");
	return;
}

这是一个死循环,这个代码应该非常好理解,因为i是unsigned int 类型,i的值永远大于等于0。

那么到0后后边那个很大的数字怎么理解呢? 

因为0的二进制补码是:00000000000000000000000000000000,在进行减1操作后,变成:11111111111111111111111111111111,在按照无符号打印就是 4294967295了。

5.

#include <stdio.h>
#include <windows.h>
unsigned char i = 0;
int main(){
	for (i = 0; i <= 255; i++){
		printf("hello word\n");
	}
	system("pause");
	return;
}

毫无疑问,这个程序也是死循环,站在宏观的角度上,unsigned char类型变量的取值范围是[0,255],所以i的值一直满足条件,所以死循环。

在进一步分析,当i的值是255时,在计算机中存的是255的补码:11111111。当这个值加1后,变成:100000000 ,因为char类型只有1个字节(8位),所以只取低八位,此时i又从0开始,死循环。

6.

#include <stdio.h>
#include <windows.h>
#include <string.h>
int main(){
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++){
		a[i] = -1 - i;
	}
	printf("%d\n", strlen(a));
	system("pause");
	return;
}

 这道题就有点难了,首先要知道strlen是求字符串的长度的,遇到'\0'就会停止。

在for循环中对a数组进行赋值,依此赋值为:-1,-2,......-127,-128。当i=128时-1-i是-129,但是int char类型是存不下-129的,那么这个-129要如何去理解呢?

-129的补码是:1111 1111 1111 1111 1111 1111 0111 1111。当把-129放入char类型数组时,会发生截断,只取后8位:011111111。此时计算机识别这个int char类型的值是127。

那么当i是129时,-1-i的值就是-130,-130的补码是:1111 1111 1111 1111 1111 1111 0111 1110。依然出现截断,此时数组中存的是:011111110。此时这个值就是126。

当i的值是255时,-1-i的值就是-256,-256的补码是: 1111 1111 1111 1111 1111 1111 0000 0000。存入数组时依然发生截断,取后八位:00000000。此时这个值就是0。

当使用strlen时,碰到了'\0'就结束,而'\0'的ASLL码就是0,所以碰到0也就停止了。当第一次a[i]==0时,i的值是255。所以a[255]==0。那么字符串长度此时就是从a[0]到a[254]一共255个值,那么strlen(a)就是255了。程序执行结果如下:

 

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值