每日一题(十)

10.11 函数形参问题

分析如下程序的输出:

void fun(int m, int n)
{
    printf("m = %d, n = %d\n", m, n);
}

int main(void)
{
    int k = 3;
    fun(k += 3, ++k);
    printf("k = %d", k);
    
    return 0;
}

主要考察是调用函数的时候参数的入栈顺序以及变量的运算,参数入栈顺序一般是从右到左,所以先执行++k,将4传给n;再执行k += 3将7的值传给m。注意这里是k做运算之后才传入的函数,所以k += 3, ++k并不是在调用函数的栈中执行的,所以k的值是保存下来的,所以最终输出为:

m = 7, n = 4

k = 7

这种方式和编译器中得函数调用关系相关即先后入栈顺序。不过不同编译器得处理不同。也是因为 C 标准中对这种方式说明为未定义,所以各个编译器厂商都有自己得理解,所以最后产生得结果完全不同。因为这样,所以遇见这种函数,我们首先要考虑我们得编译器会如何处理这样得函数,其次看函数得调用方式,不同得调用方式,可能产生不同得结果。最后是看编译器优化。

10.12 二级指针偏移

分析下面程序:

#include <stdio.h>

void fun(int b[][3])
{
	++b;
    b[1][1] = 120;
}

int main(void)
{
    int a[][3] = {
        {1, 2, 3},
        {4, 5, 6},
        {7, 8, 9}
    };
    
    fun(a);
    printf("a[2][1] = %d\n", a[2][1]);
    
    return 0;
}

首先要了解数组传入函数后的变化**:我们知道数组传入函数的时候,会转换为指针,但是对于二维数组,只转换一次**,即int b[][3]传入函数的时候是以

int (*b)[3]的形式,即一个指向数组的指针,数组中有三个元素。所以传入a后,相当于b = a[0]

++b代表指针b移动一个步长的位置,这里b指向一个三个元素的int型数组,所以++b之后b = a[1][]

指向b[1][1] = 120, 其中b[1][1]相当于*(*(b+1)+1),相当于指针b偏移了一个步长之后又偏移了一个元素的位置,用a表示a[1+1][0+1]a[2][1] = 120,所以printf输出的就是120。

10.13 #ifdef与#if define 的区别

用一段程序说明:

#include <stdio.h>
#define A
#define B
void test(int a,int b)
{
}

int main(void)
{
#if 0
    #ifdef A&&B
    test(printf("a\n"),printf("b\n"));
#endif
#endif

#if  defined(A)&&defined(B)
    test(printf("a\n"),printf("b\n"));
#endif

    return 0;
}

如果是#if defined(A)&&defined(B)的形式,输出:

b

a

如果是#ifdef A&&B的形式,会提示:
image-20201017102017535

因为#ifdef虽然我们最常见也用得最多,可是#if defined(XXX)却可以有 &&,||,!,逻辑与,逻辑或,逻辑非等操作,而#ifdef却不支持这样的特性。

10.14指针实现交换数据时的溢出情况

程序如下:

void swap(int *a, int *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}

请问上述程序可否实现两个int数据的交换?看起来没毛病,可是容易忽略一个问题,那就是int是有符号数据的溢出!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nwq6O0su-1602905143136)(…/…/…/%E8%BD%AF%E4%BB%B6%E7%AE%A1%E5%AE%B6/Typora/%E5%9B%BE%E7%89%87%E5%BA%93/image-20201017103737242.png)]

**只有当a、b同符号的时候才可能发送溢出!!!**因为这里有加减操作,所以当两个同符号的数据相加的时候就有可能溢出。

比如:

交换-5, -7。 以4bit为例。

-5 = 1011 (补码) -7 = 1001 (补码)

(-5)+ (-7)= 10100=0100=4 (溢出后为4)

4-(-7)= 4 +7=0100 + 0111 = 1011 = -5的补码

4-(-5)= 4 + 5 = 0100 + 0101 = 1001 = -7的补码

注意,函数是在第一步的时候可能溢出,但是后面的操作是基于溢出的数据的,而且后面又可以把溢出的部分减回来,所以这里虽然可能会发送溢出,但是仍然可以得到正确的数据。

10.15 三目运算的数据转换

程序如下:

#include <stdio.h>

void test()
{
    printf("int:    %d\n", sizeof(int));
    printf("double: %d\n", sizeof(double));
    printf("test1: %d\n", sizeof(100 < 1 ? 0.1 : 1));
    printf("test2: %d\n", sizeof(100 > 1 ? 0.1 : 1));
}

int main(void)
{
    test();
    return 0;
}

输出结果为:

int:    4
double: 8
test1: 8
test2: 8

如果按照我们分析,(100 < 1 ? 0.1 : 1)输出的会是1,也就是int型数据,但是实际上被转换为double类型了。

实际上三目运算最后输出的是一个变量,在一个表达式中,数据格式要统一,所以在得出运算之前就将所有变量转换为同一种数据格式了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值