讨论/综合讨论/在java和c#中A[m-1]=A[m-- - 1];而在C中A[m-1]!=A[m-- - 1];/
在java和c#中A[m-1]=A[m-- - 1];而在C中A[m-1]!=A[m-- - 1];

简介

在C语言中等号后一个m自减会作用于等号前的m,假如m=3,那么在C语言中上式子就为A[1]=A[2];而在c#和java中上式子又为A[2]=A[2];

c语言:
B0Q3)JK(Z~V2Q1{])3IZ_JN.png
C#:
J[~~67AH4YU5Y9}L9LY5~XD.png
比如leetcode合并排序数字这题,代码相同,测试用例相同,但是输出结果不同,代码如下,感兴趣的可以测试下,另外有没有哪位大佬解释下原因啊
合并两个有序数组

  void merge(int* A, int ASize, int m, int* B, int BSize, int n)//C语言
{
      
    while (m > 0 && n > 0) {
            // 对比选出较大的数放在 m + n - 1 的位置,并将选出此数的指针向前移动
            A[m + n - 1] = A[m - 1] > B[n - 1] ? A[m-- - 1] : B[n-- - 1];
        }
        // 剩下的数都比已经遍历过的数小
        // 如果 m 不为 0,则 A 没遍历完,都已经在 A 中不用再管
        // 如果 n 不为 0,则 B 没遍历完,直接全移到 A 中相同的位置
        while (n > 0) {
            A[n - 1] = B[n - 1];
            n--;
        }
}

class Solution {
    public void merge(int[] A, int m, int[] B, int n) //java语言
{
        // 先确保将其中一个数组中的数字遍历完
        while (m > 0 && n > 0) {
            // 对比选出较大的数放在 m + n - 1 的位置,并将选出此数的指针向前移动
            A[m + n - 1] = A[m - 1] > B[n - 1] ? A[m-- - 1] : B[n-- - 1];
        }
        // 剩下的数都比已经遍历过的数小
        // 如果 m 不为 0,则 A 没遍历完,都已经在 A 中不用再管
        // 如果 n 不为 0,则 B 没遍历完,直接全移到 A 中相同的位置
        while (n > 0) {
            A[n - 1] = B[n - 1];
            n--;
        }
    }
}


展开讨论
Why发起于 2020-03-03
最近编辑于 2020-03-03
共 6 个讨论

抱歉,我不是大佬,解释不了具体的原因,但是还是来答一波。

不论是 m-- 还是 --m 我个人建议独占一行,研究它们之间的差别我个人觉得意义不大。即使是有很多年开发经验的程序员,可能未必都能非常清楚这里的差别。如果工程里写这样的代码会给阅读和调试带来较大的麻烦。

正如楼主所述,同样的代码,在不同编程语言之间迁移的时候,就很有可能出现问题,并且是极其隐蔽、不易察觉的。

我个人偏向于这种编码风格:每一行的长度最短(目标是每一行逻辑尽量少),具体需要做到:

在编码的时候,保证(以下 1、2、3、4、5、8 都是谷歌和阿里巴巴等公司的编码规范要求):

1、每一行只声明一个变量;
2、每一行代码尽可能只执行一个逻辑(包括这里所说的,不写 A[m--],需要拆分成两行);
3、为了体现逻辑层次关系,加上必要的空行;
4、写必要的注释行,一定不写行尾注释;
5、在 if for while 只有一行的情况下,必须写大括号,并且按照相关语法规定写换行和回车;
6、尽量少写三目运算符(我个人习惯,非必要);
7、不刻意压缩变量的命名长度,除了普遍使用的 restmp 或者是上下文清楚的变量命名;
8、如果有明显的主线逻辑和分线逻辑,应该把分线逻辑抽取成私有方法,以突出主线逻辑。

即使是在这种情况下,如果都能保证代码的行数良好,那么程序员的逻辑在一定程度上会是简洁、清楚的。

(上面大概的意思是,在尽量不压缩行的情况下,通过别的办法压缩行数。)

写代码可读性优先,为了保证可读性,有些情况下可以放弃一些性能和效率,并且有些编程语言的编译器考虑到了程序员的编码习惯,会自动做一些性能上的优化,因此有些编码技巧其实是没有必要的,例如 Java 语言里 /2 就写 /2 ,不用写 >> 1,但是 >>> 1 (两个大数相加即使整型溢出,但无符号右移,值依然正确)除外,少量的字符串拼接就用 +,不需要用 StringBuilder。如果编码做到了可读性良好,有很好的自解释能力,注释只需要标注必要的部分。

希望大家不要以代码行数短作为代码好的指标(与本回答无关,题主没有这么说),短代码拿来欣赏一下还不错,但是平常尽量不要写。压缩行数的技巧大家都会,但是为了压缩行数破坏了代码的可读性是得不偿失的,代码的可读性、扩展性应该是更重要的指标。在结合应用场景、恰当使用数据结构、运用算法思想层面,去压缩行数的代码才会更让他人刮目相看。

以上只是个人观点。不适用于写算法竞赛等注重程序运行时间、编码时间、代码写完以后不会被他人阅读、代码不会应用于实际生产环境的编码活动中

9

这种写法不可取,有失公正。就比如c语言写 (i++) +(i++)+(i++),答案会有几种,没有必要去纠结这些“烂代码”引发的问题

2
1

Undefined Behavior.

不光如此,不同的编译器也有不同的行为

你可以查看下他俩的汇编语言。不出意外是因为C和java对A和B在汇编语言下读取顺序不一致。