C语言竟支持这些操作:C语言神奇程序分享

简介: 近期在网上冲浪的时候发现几个十分有趣的C语言程序,它们运行之后会产生一些看似不是很合理,但其实是十分合理的结果,让我们一起来看看吧!
✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。
🍎个人主页: 小嗷犬的博客
🍊个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。
🥭本文内容:C语言竟支持这些操作:C语言神奇程序分享

@TOC


近期在网上冲浪的时候发现几个十分有趣的C语言程序,它们运行之后会产生一些看似不是很合理,但其实是十分合理的结果,让我们一起来看看吧!

1.神奇的死循环

下面这段程序运行之后可能会造成死循环:
#include<stdio.h>

int main()
{
    int a[10], i;
    for (i = 0; i <= 10; i++)
    {
        a[i] = 0;
    }
    return 0;
}
初学C语言的小伙伴可能死活也想不出为什么会有死循环,这个结构隐藏在平时的作业中,让我们的初学者不停挠头。

产生错误的原因首先是因为数组的访问越界,大小为10的数组只能访问0-9,毕竟咱们程序员数数是从零开始的。

循环中从0访问到10,就造成了访问越界,这在C语言中是可以编译通过的,因为在C语言中,数组名其实是一个地址,编译器不会知道这个地址管到了多少位,它只会把访问的索引看作偏移量进行访问。

然后是因为内存地址的问题,在这个程序中,我们先定义了数组a,然后又定义了整型变量i,此时绝大多数编译器都会先为数组a分配内存地址,然后紧挨着数组a再为整型变量i分配内存地址。

这就造成了:当我们在访问a[10]时,其实是在访问变量i,循环最后会将a[10]设置为0,即将变量i设置为0,循环就无法满足退出条件,于是产生了死循环。


2.神奇的隐式转换

在某些弱类型语言中, 隐式转换是十分常见的,如在JavaScript中,用一个数字去减去一个形如数字的字符串,JavaScript会将字符串隐式转换为数字,再进行数字之间的减法运算。

下面的C语言程序似乎也出现了隐式转换的现象:

#include<stdio.h>

int main()
{
    puts("-0.5" + 1);
    // 输出:0.5
    return 0;
}
这段程序竟然会输出 0.5,似乎就是将字符串 "-0.5"隐式转换成了浮点数 -0.5,再与数字 1进行加法运算的。

难道我们的C语言也支持类似JavaScript那种隐式转换吗?

C语言当然是不支持这样的隐式转换的,那程序为什么会输出0.5呢?

其实输出的0.5并不是一个数字,其实它是以一个字符串的身份输出的。

这就要从C语言的字符串说起了,在C语言中,没有字符串类型,字符串其实都是用以'\0'结尾的字符数组储存的,而数组名则表示字符串的首地址。

字符串常量也是类似,程序中的字符串"-0.5"其实也是表示储存了"-0.5"中的各个字符和字符'\0'的字符数组的首地址。

而其后的+1则并不是表示数学运算上的加一,而是表示地址向后偏移一个单位的地址,即原来字符串第二个字符的地址。

这样就能让puts()函数跳过第一个字符'-'负号来输出字符串,自然输出的结果就是0.5了。

所以其实上面那个程序就等价于以下程序:

#include<stdio.h>

int main()
{
    char* p = "-0.5";
    puts(&p[1]);
    // 输出:0.5
    return 0;
}

3.神奇的**指数运算

在Python中,我们可以使用 **运算符来表示数学上的指数运算,而在C语言中通常是用 pow()函数。

下面的程序似乎显示,C语言也可以使用**运算符来进行指数运算:

#include<stdio.h>

int main()
{
    printf("%d\n", 50 ** "2");
    // 输出:2500
    return 0;
}
但细看就可以发现一部分问题,首先那个 "2"是字符串,如果真的能够进行 **指数运算,那也一定是两个数字之间的。

也许字符串"2"被编译器隐式转换成数字2了呢?

在上一节我们提到,C语言中的字符串是用字符数组存的,也就是说字符串"2"其实是一个字符数组,其中包含两个字符:'2''\0',将一个包含两个字符的字符数组转换成一个数字,这显然是做不到的。

在Python中,有字符串类型,通过强转型函数可以将字符串转换为其他类型,但是即便是Python,也不支持上述那种隐式转换,即无法将一个数组与一个字符串进行**指数运算。

排除了隐式转换,让我们来分析一下原因。

首先,在C语言中没有**这种运算,所以两个星号*应该是拆开来理解。

我们知道,在C语言中,星号*不止可以用来进行乘法运算,还可以连接地址用来表示取值运算,这也能够解释为什么后面的"2"是字符串了,上节我们说过,字符串常量在C中也是一个地址,于是正确的运算结合顺序就出来了:

#include<stdio.h>

int main()
{
    printf("%d\n", 50 * (*"2"));
    // 输出:2500
    return 0;
}
"2"表示一个含有两个字符( '2''\0')的字符数组的首地址,那么 *"2"就等价于 "2"[0],即等价于字符 '2'

我们又知道,C语言中的char类型其实是整数到ASCII表的一组映射,其值为它的ASCII码值,刚好字符'2'的ASCII码的十进制值为50

所以我们最终可以得到以下等价关系:

    50 ** "2"
=>    50 * (*"2")
=>    50 * "2"[0]
=>    50 * '2'
=>    50 * 50
所以上面的程序也可以写成这样:
#include<stdio.h>

int main()
{
    printf("%d\n", 50 * 50);
    // 输出:2500
    return 0;
}
这样程序运行自然就会输出 2500了,是不是觉得很合情合理呢?
目录
相关文章
|
3月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
5月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
123 1
|
5月前
|
NoSQL 编译器 程序员
【C语言】揭秘GCC:从平凡到卓越的编译艺术,一场代码与效率的激情碰撞,探索那些不为人知的秘密武器,让你的程序瞬间提速百倍!
【8月更文挑战第20天】GCC,GNU Compiler Collection,是GNU项目中的开源编译器集合,支持C、C++等多种语言。作为C语言程序员的重要工具,GCC具备跨平台性、高度可配置性及丰富的优化选项等特点。通过简单示例,如编译“Hello, GCC!”程序 (`gcc -o hello hello.c`),展示了GCC的基础用法及不同优化级别(`-O0`, `-O1`, `-O3`)对性能的影响。GCC还支持生成调试信息(`-g`),便于使用GDB等工具进行调试。尽管有如Microsoft Visual C++、Clang等竞品,GCC仍因其灵活性和强大的功能被广泛采用。
160 1
|
5月前
|
编译器 C语言 计算机视觉
C语言实现的图像处理程序
C语言实现的图像处理程序
244 0
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
86 5
|
2月前
|
C语言
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性
C语言编程中,错误处理至关重要,能提升程序的健壮性和可靠性。本文探讨了C语言中的错误类型(如语法错误、运行时错误)、基本处理方法(如返回值、全局变量、自定义异常处理)、常见策略(如检查返回值、设置标志位、记录错误信息)及错误处理函数(如perror、strerror)。强调了不忽略错误、保持处理一致性及避免过度处理的重要性,并通过文件操作和网络编程实例展示了错误处理的应用。
82 4
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
79 1
|
2月前
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
64 2
|
2月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
53 1
|
3月前
|
存储 文件存储 C语言
深入C语言:文件操作实现局外影响程序
深入C语言:文件操作实现局外影响程序

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等