第三章

作者: 三土垚6 | 来源:发表于2019-12-19 14:56 被阅读0次

    语义“陷阱”

    3.1 指针和数组

    1> c语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来。但是,c语言中数组的元素可以是任意类型的对象。
    2> 对于一个数组,我们只能做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。

    3.2 非数组的指针
    在c语言中,字符串常量代表了一块包括字符串中所有字符以及一个空字符('\0')的内存区域的地址
    为实现将两个字符串s和r连接成单个字符串,我们写出以下代码:

        char *r;
        strcpy(r,s);
        strcat(r,t);
    

    但上述这块代码是不能执行的,原因在于不确定r指向何处。我们在定义指针变量时,不仅要让它指向一个地址,而且r指向的地址还应该有内存空间可供容纳字符串。
    然后,我们稍加修改,给出以下代码:

        char *r,
        r=(char *)malloc(strlen(s)+strlen(t));
        strcpy(r,s);
        strcat(r,t);
    

    我们为r分配了空间,但这段代码还存在三个问题:
    1> malloc函数有可能无法提供请求的内存,即系统内存不够分配空间,这时malloc会返回一个空指针来传递分配失败的信号,但我们没有信号来接收它。
    2> 给r分配内存空间之后应及时释放。
    3> malloc函数没有分配足够的内存空间。字符串末尾还应该有'\0'结束标志。
    为此,我们给出最终的代码:

        char *r,
        r=(char *)malloc(strlen(s)+strlen(t)+1);
        if(!r){
            complain();     //自己编写的警告函数 
            exit(0);
        }
        strcpy(r,s);
        strcat(r,t);
        free(r);
    

    3.3 作为参数的数组声明
    对前一节内容的深挖,我们发现指针变量虽然和数组名在某种意义上可以等同,例如,它们都可作为一个地址。
    但其实它们有着本质的区别:指针变量仅仅是一个指针,但数组名不仅相当于一个指针变量,还会在内存中开辟一块空间。

    3.4 避免“举隅法”
    “举隅法”在牛津英语辞典中是这样解释的:以含义更宽泛的词语代替含义相对较窄的词语,或者相反。

    混淆指针与指针所指向的数据。对于字符串的情形,我们更容易犯这种错误。
    例如:

        char *p,*q;
        p="xyz";
    

    在这种情况下,p的值不是字符串“xyz”,p仅仅是个指针变量,指向了字符串常量在静态存储空间中的首地址。

    3.5 空指针并非字符串
    编译器保证由0转换过来的指针不等于任何有效的指针。

    3.6 边界计算与不对称边界
    先提出一个问题:假定X满足边界调节x>=16且x<=37,那么此范围内的数有多少个?

    如果按照对成边界计算这个问题,不加思索的答案可能是21,但事实是22。也就是31-16+1。
    为了解决这个问题,c语言设计者使数组下标从0开始。
    对于像c这样的数组下标从0开始的语言,不对称边界给程序设计带来的便利尤其明显。

    还有一个应用是在缓冲区读字符的时候。有一部分内容看不懂,日后回写。

    3.7 求值顺序。
    之前在2.2节提到了运算符优先级问题,而求值顺序完全是另一码事。
    c语言中,只有四个运算符(&&、||、?:和,)存在规定的求值顺序。
    运算符&&和运算符||首先对左侧操作数求值,只在需要时才对右侧操作数求值。
    运算符?:有三个操作数;在a?b:c中,操作数a首先被求值,根据a的值再求操作数b或c的值。
    逗号运算符,首先对左侧操作数求值,然后该值被“丢弃”,再对右侧操作数求值。

    3.8 整数溢出
    c员中存在两种整数算术运算,有符号运算与无符号运算。
    无符号运算,没有所谓的整数“溢出”一说,但有符号运算中,如发生整数溢出则是一种灾难。
    因此在进行有符号运算时要进行“溢出”检测,我们给出以下代码:

        if(a>INT_MAX-b)
            complain();
    

    其中INT_MAX是指可能的最大值,complain()是自己写的报错函数。

    有必要了解自己常用常用编译器的各种类型字节,如下是dev-c++ 5.11:
    short 有2个字节
    int 有4个字节
    float 有4个字节
    double 有8个字节

    3.9 为函数main提供返回值
    一般来说,返回值为0代表程序执行成功,返回值为非0则表示程序执行失败。但如果一个程序的main函数并不返回任何值,那么有可能看上去失败。

    目前不知到可能会造成什么严重后果,日后知到补充。

    第三章到此结束!

    相关文章

      网友评论

          本文标题:第三章

          本文链接:https://www.haomeiwen.com/subject/yvjmnctx.html