C++ 零散基础笔记

用字符串字面值初始化

char s[4] = "str";//数组长度至少为4,因为字符串常量最后还有看不见的结束符
const char *p = "str";

1)"str"是一个字面值,它的类型将会先被转换为const char[4]。由于这里不存在指针,所以"str"就是顶层const,然后赋值操作,顶层const可以被忽略,所以左边为char s[4]
2)"str"是一个字面值,它的类型将会先被转换为const char[4]。但由于左边类型为字符指针,所以类型就会转换为const char *,这个指针指向第一个字符s,之所以有const是因为它是字面值。所以等号右边的值就是底层const,赋值操作时,底层const不能被忽略。所以这句不能是char *p = "str",因为将会丢失了底层const。

无符号的0减1

float sum(float a[], unsigned length) {
	int i;
	float result=0;
	for (i = 0; i <= length - 1; i++) {
		result += a[i];
	}
	return result;
}

此题来自CSAPP练习2.25。当参数length为0时,运行这段代码会抛出异常,内存错误。
原因:length为无符号数,展开为二进制是全为0,减去1后(实际效果为加上-1,-1明显是一个有符号数即补码数字,在补码数字中-1的二进制全为1,实际效果就是二进制全为0加上二进制全为1),二进制全为1,全为1的无符号数的值即为Umax(int为4字节,即32位二进制)即为 2 32 2^{32} 232-1即为4294967296-1。
所以for的条件判断实际为i<=4294967295u。又因为作比较运算时,会将有符号的隐式转换为无符号的再比较,所以这里会把i先转换为一个无符号的副本来比较,虽然这里对程序没什么影响。

strlen返回类型为unsigned

int strlonger(char *s, char * t) {
	cout << strlen(s) - strlen(t);
	return strlen(s) - strlen(t) > 0;
}

int main(){
	char p1[4] = "str";
	char p2[5] = "str1";
	cout << " "<<strlonger(p1,p2);
}

运行结果为:4294967295 1
此题来自CSAPP练习2.26。当数组s的长度小于t的长度时,本应该返回0即假,但却返回了1即真。
原因:strlen的函数原型为size_t strlen(const char *s),而在头文件stdio.h中数据类型size_t是定义成unsigned int的。所以返回的是-1的unsigned,即为4294967295。

形参实参与底层const

1)实参为底层const,形参无const。

int strlonger(char *s, char * t) {
	return strlen(s) - strlen(t) > 0;
}

int main() {
	const char *p1 = "str";
	const char *p2 = "str1";
	cout << " " << strlonger(p1, p2);
}

在这里插入图片描述
结论:这里相当于形参=实参。本文第一章已经提到,赋值时底层const不能被忽略掉,就会丢失限定符。所以这里出错。
2)实参为无const,形参为底层const。

int strlonger(const char *s, const char * t) {
	cout << strlen(s) - strlen(t);
	return strlen(s) - strlen(t) > 0;
}

int main() {
	char p1[4] = "str";
	char p2[5] = "str1";
	cout << " " << strlonger(p1, p2);
}

结论:不存在丢失限定符的情况,所以这里没有错误。p1传进去的是char *p1。但是在strlonger函数中,由于传进来的两个指针都是底层const,所以无法通过解引用这两个指针来对数组元素赋值了。

无符号数加法

unsigned short a = 65535;
unsigned short b = 1;
auto c= a + b;
cout << (unsigned short)(a + b);

c的类型为int,值为65536。输出为0。
原因:unsigned short是两个字节,16位二进制。执行a+b后为int型的65536,展开二进制为00000000 00000001 00000000 00000000。按照16位截断之后,所以就是0了。
换个思路,65536取余 2 16 2^{16} 216,所以为0。因为在unsigned short里最大二进制位的权值为 2 15 2^{15} 215,根本不可能有 2 16 2^{16} 216

补码数:正溢出、负溢出

使用short int,字节为2,二进制为16位。w=16。
1)正溢出:当a+b之和大于了Tmax即 2 15 − 1 2^{15}-1 2151即32768-1=32767。

short a = 32767;
short b = 1;
auto c= a + b;
cout << (short)(a + b);

在这里插入图片描述
a + b结果为32768大于了Tmax。截断结果即输出为-32768。直观的计算方法是和减去 2 w 2^w 2w。因为正溢出是因为得到第17位的权值 2 16 2^{16} 216,而这里不应该有第17位的权值,所以就是和减去 2 16 2^{16} 216
2)负溢出:当a+b之和小于了Tmin即 − 2 16 -2^{16} 216即-32768。

short a = -32768;
short b = -1;
auto c= a + b;
cout << (short)(a + b);

在这里插入图片描述
a + b结果为-32769小于了Tmin。截断结果即输出为32767。直观的计算方法是和加上 2 w 2^w 2w。因为负溢出是因为得到第17位的权值 − 2 16 -2^{16} 216,而这里不应该有第17位的权值,所以就是和加上 2 16 2^{16} 216。-32769+65536=32767。

总结:
1)当且仅当a>0,b>0,但和<=0时,此时计算的和发现了正溢出。
2)当且仅当a<0,b<0,但和>=0时,此时计算的和发现了负溢出。

你可能感兴趣的:(C++)