c语言练习题扩展 - 反常题系列

本文解析了C语言中几个有趣的编程现象,包括printf函数中表达式的求值顺序、利用setjmp与longjmp实现跨函数跳转及C99对函数返回类型的要求变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计划要好好修炼c语言水平,在学习过程中发现了很多反常有意思的题目列出来,供大家交流讨论。如果有说错的地方,非常欢迎批评指正。也非常欢迎大家提出问题一起讨论。

一、神奇printf - 压栈弹栈规则

int main()
{ 
    int a = 0;
    printf("%d%d%d\n",a,++a,a++);//结果 220
    
    return 0;
}

原理解析:
1.printf函数原型是 printf(const char *format),是一个不定参函数,c语言规定为了提高函数执行效率,不定参函数为从右往左计算;
2.对于不定参依次从右往左进栈。边计算,边压栈,遇到++a或者a,属于左值,先空着,最后更新;遇到i++的,因为它是右值,直接压栈。

分析步骤:
1.a++ //这里++属于右值,直接压栈;
2.++a //属于左值,先计算,值先不给;
3.a //和++a一样,先计算,值先不给;
4.往左没有参数了,挨个给a和++a赋值,已知++一共执行两次,则a和++a结果为2;
5.因为a++属于后操作数,先入栈并且入栈时为0,则值为0。

二、进阶版goto语句

//当时看到这个c语言独有机制感觉很惊奇呀,原来goto还有进化版,可以实现两个函数甚至两个文件之间的跳转

#include <stdio.h>
#include <setjmp.h>
//函数原型
//int setjmp(jmp_buf j);
//void longjmp(jmp_buf j,int i)

jmp_buf buf;

void test(void)
{
    printf("in test fun! \n");
    longjmp(buf,100);
    
    printf("test fun end! \n");
}
int main()
{
    int num = setjmp(buf);
    if(num)
    {
        printf("num = (%d)\n",num);
        printf("in main fun if! \n");

    }
    else
    {
        printf("in main fun else!\n");
        test();
    }
    return 0;
}

//输出结果
in main fun else!
in test fun! 
num = (100)
in main fun if! 

原理解析:
1.setjmp(jmp_buf j)必须首先被调用,它表示“使用变量j记录现在的位置”,该函数第一次调用时返回0;
2.调用setjmp后,可以调用longjmp回到之前调用setjmp记录的j的位置并且将第二个参数传回setjmp;
3.当使用longjmp时,j的内容被销毁,简单理解,从哪里来回哪里去并释放当前资源;
4.setjmp和longjmp在c++中变异为更普通的异常处理机制“casch”和“throw”;
5.该功能大多用在异常处理和预防潜在的风险,在某个地方不符合条件时用longjmp带一个状态跳回到原来的位置。

三、函数返回值

因为语言版本更新导致会出现某些练习题不能及时更新,这里及时备注一下

//C89支持无返回类型的函数,默认返回int型 但是到了C99,这种无返回类型的函数是不能编译通过的,会提示 “ISO C++ forbids declaration of 'fun' with no type”的问题
fun(void);

//C99开始函数必须要有返回值 main函数除外
int fun(void);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值