• 关于“烫烫烫烫烫烫烫”的程序员笑话


    环境

    • Microsoft Visual Studio Community 2022
    • Windows 11 家庭中文版

    笑话

    小明在超市买了3瓶汽水,他先打开第0瓶汽水,咕咚咕咚喝光了,接着打开第1瓶汽水,又咕咚咕咚喝光了,然后又打开第2瓶汽水,咕咚咕咚喝光了,然后又打开第3瓶汽水,刚喝了一口,突然喊道:“烫烫烫烫烫烫烫!”

    解释

    在Visual Studio中,未分配的内存空间,其初始值用 0xCC (1个字节)填充,而查询编码表可知, 0xCCCC (2个字节)代表字符

    如果转换为10进制,比如int数值,int是4个字节,也就是说,把 0xCCCCCCCC (4个字节)转换为10进制,其值是 -858993460

    在该笑话中,小明买了3瓶汽水,假设使用的是数组,那么能访问的数组下标为0、1、2,如果访问下标3,显然越界了。

    在C语言中,对字符串的处理,稍不注意,就很容易出现越界的情况,而且编译和运行可能都不会报错,所以要格外小心。具体来讲,字符串是以 \0 结尾的,也就是说,在访问字符串的时候, \0 相当于一个哨兵,找到这里,就知道字符串结束了,否则会一直找下去,产生不可预知的结果。

    测试

    准备

    在Visual Studio中创建一个新项目,选择 Empty Project

    在这里插入图片描述
    右键单击Source Files,Add -> New Items… ,创建 Test0527.cpp 文件:

    在这里插入图片描述

    测试1

    打开 Test0527.cpp 文件,编辑如下:

    #include 
    
    using namespace std;
    
    int main() {
    	char str[4];
    
    	str[0] = 'a';
    	str[1] = 'b';
    	str[2] = 'c';
    	str[3] = 0;
    
    	cout << str << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这是正确的用法,要想使用字符数组来存储字符串 abc ,数组长度应该是4而不是3,最后一个元素 str[3] 要填入 \0 ,表示字符串结束。

    运行程序,结果如下:

    在这里插入图片描述

    测试2

    如果忘了最后需要一个 \0 ,而把字符数组的长度设置为3,则在打印 str 时,依次访问到 abc 之后,并不会结束,而是会继续访问下去。如果接下来是未分配的内存空间,即 0xCCCCCCCCCCCCCCCCCCCCCCCC... ,就会出现 烫烫烫... 的字样。

    修改程序如下:

    #include 
    
    using namespace std;
    
    int main() {
    	char str[3];
    
    	str[0] = 'a';
    	str[1] = 'b';
    	str[2] = 'c';
    	
    	cout << str << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行程序,结果如下:

    在这里插入图片描述

    注:本例中,数组可以直接初始化:

    char str[3] = {'a', 'b', 'c'};
    
    • 1

    要想查看其int值,可以用一个int指针指向未初始化的元素,比如 str[3] (注:编译器会发现此处越界,可以使用 str + 3 指针):

    	int* p = (int*)(str + 3);
    	cout << *p << endl;
    
    • 1
    • 2

    其输出结果为 -858993460

    测试3

    实际上,静态分配的内存,如果没有初始化,其初始值也是 0xCC

    修改程序如下:

    #include 
    
    using namespace std;
    
    int main() {
    	char str[3];
    	
    	cout << str << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    运行程序,结果如下:

    在这里插入图片描述

    其它

    动态分配且未初始化的内存

    对于动态分配的内存,如果没有初始化,其初始值是 0xCD ,转换为中文字符为 0xCDCD ),其4字节( 0xCDCDCDCD )对应的int值为 -842150451

    编辑程序如下:

    #include 
    
    using namespace std;
    
    int main() {
    	char* p = new char[100];
    	
    	p[0] = 'a';
    	p[1] = 'b';
    	p[2] = 'c';
    
    	cout << p << endl;
    
    	delete[] p;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行程序,结果如下:

    在这里插入图片描述

    要想查看其int值,可以用一个int指针指向未初始化的元素,比如 p[3]

    	int* p2 = (int*)(p + 3);
    	cout << *p2 << endl;
    
    • 1
    • 2

    其输出结果为 -842150451

    动态分配且已释放的内存

    一块动态分配的内存,在释放掉之后,系统会用 0xDD 来填充。此时,如果又去访问它,则转换为中文字符为 0xDDDD ),其4字节( 0xDDDDDDDD )对应的int值为 -572662307

    编辑程序如下:

    #include 
    
    using namespace std;
    
    int main() {
    	char* p = new char[100];
    
    	char* p2 = p;
    
    	delete[] p;
    
    	cout << p2 << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行程序,结果如下:

    在这里插入图片描述

    要想查看其int值,可以用一个int指针指向 p (在释放 p 之前),或者指向 p2

    	int* p3 = (int*)p2;
    	cout << *p3 << endl;
    
    • 1
    • 2

    上述代码放在 p 释放之后,其输出结果为 -572662307

  • 相关阅读:
    STM32的中断
    六、Big Data Tools安装
    Unity热更新
    删除vxe-table右上角的工具栏
    数据集 | 语音合成音库助力机器人客服“声入人心 ”
    Android 12(S) 图像显示系统 - drm_hwcomposer 简析(上)
    ThreeJS - 封装一个GLB模型展示组件(TypeScript)
    巨好看的登录注册界面源码
    Pytorch学习:神经网络模块torch.nn.Module和torch.nn.Sequential
    SpringBoot轻松实现项目集成Knife4j接口文档
  • 原文地址:https://blog.csdn.net/duke_ding2/article/details/130907027