C语言学习笔记(三六)

本文详细讲解了C语言中地址运算的基础概念,如指针自增、增量运算,以及如何通过指针管理内存分配和释放。通过alloc和afree函数演示了如何使用指针进行动态存储空间的管理。还介绍了指针与其他类型的操作,如比较、加减运算及其在字符串长度计算中的应用。

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

C语言学习地三十六天。

5.4 地址算术运算
如果p是一个指向数组中某个元素的指针,那么p++将对p进行自增运算并指向下一个元素,而p+=i将对p进行加i的增量运算,使其指向指针p当前所指向的元素之后的第i个元素。这类运算是指针或地址运算中最简单的形式。
C语言中的地址运算方法是一致且有规律的,将指针、数组和地址的算术运算集成在一起是该语言的一大优点。为了说明这一点,我们来看一个不完善的存储分配程序。它由两个函数组成。第一个函数alloc(n)返回一个指向n个连续字符存储单元的指针,alloc函数的调用者可利用该指针存储字符序列。第二个函数afree(p)释放已分配的存储空间,以便以后重用。之所以数i这两个函数是“不完善的”,是因为对afree函数的调用次序必须与调用alloc函数的次序相反。换句话数,alloc与afree以栈的方式(即后进先出的列表)进行存储空间的管理。标准库中提供了具有类似功能的函数malloc和free,它们没有上述限制。
最容易的实现方式是让alloc函数对一个大字符数组allocbuf中的空间进行分配。该数组是alloc和afree两个函数私有的数组。由于函数alloc和afree处理的对象是指针而不是数组下标,因此,其他函数无需知道该数组的名字,这样可以在包含alloc和afree的源文件中将该数组声明为static类型,使得它对外不可见。
allocbuf中的空间使用状况也是我们需要了解的信息。我们使用指针allocp指向allocbuf中的下一个空闲单元。当调用alloc申请n个字符的空间时,alloc检查allocbuf数组中有没有足够的剩余空间。如果有足够的空闲空间,则alloc返回allocp的当前值(即空闲的开始位置),然后将allocp加n以时它指向下一个空闲区域。如果空闲空间不够,则alloc返回0.如果p在allocbuf的边界之内,则afree(p)仅仅只是将allocp的值设置为p。

    #define ALLOCSIZE 10000  /* 可用空间大小 */

    static char allocbuf[ALLOCSIZE]; /* alloc使用的存储区 */
    static char *allocp = allocbuf;  /* 下一个空闲位置 */

    char *alloc(int n) { /* 返回指向n个字符的指针 */
        if (allocbuf + ALLOCSIZE - allocp >= n) { /* 有足够的空闲空间 */
            allocp += n;
            return allocp - n;  /* 分配前的指针p */
        } else /* 空闲空间不够 */
            return 0;
    }
    void afree(char *p){ /* 释放p指向的存储区 */
        if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
            allocp = p;
    }

如果存储空间的申请可以满足,alloc将返回一个指向所需大小的字符块首地址的指针。如果申请无法满足,alloc必须返回某种形式的信号以说明没有足够的空闲空间可供分配。C语言保证,0永远不是有效的数据地址,因此,返回值0可用来表示发生了异常事件。在本例中,返回值0表示没有足够的空闲空间可供分配。
指针与整数之间不能互相转换,但0是惟一的例外:常量0可以赋值给指针,指针也可以和常量0进行比较。程序中经常用符号常量NULL代替常量0,这样便于更清晰地说明常量0是指针的一个特殊值。符号常量NULL定义在标准头文件<stddef.h>中。
类似于

    if (allocbuf + ALLOCSIZE - allocp >= n)

以及

    if (p >= allocbuf && p < allocbuf + ALLOCSIZE)

的条件测试语句表明指针算术运算有以ixa几个重要特点。首先,在某些情况下对指针可以进行比较运算。例如,如果指针p和q指向同一个数组的成员,那么它们之间就可以进行类似于==、!=、<、>=的关系比较运算。如果p指向的数组元素的位置在q指向的数组元素位置之前,那么关系表达式

    p < q

的值为真(true)    。任何指针与0进行相等或不等的比较运算都有意义。
其次,指针可以和整数进行相加或相减运算。例如,结构

    p + n

表示指针p当前指向的对象之后第n个对象的地址。无论指针p指向的对象是何种类型,上述结论都成立。在计算p+n时,n将根据p指向的对象的长度按比例缩放,而p指向的对象的长度则取决与p的声明。例如,如果int类型占4个字节的存储空间,那么在int类型的计算中,对应的n将按4的倍数来计算。
指针的减法运算也是有意义的:如果p和q指向相同数组中的元素,且p<q,那么q-p+1就是位于p和q指向的元素之间的元素数目。我们由此可以编写出函数strlen的另一个版本,如下所示:

    /* strlen函数:返回字符串s的长度 */
    int strlen(char *s){
        char *p = s;

        while (*p != '\0')
            p++;
        return p - s;
    }

在上述程序段的声明中,指针p被初始化为指向s,即指向该字符串的第一个字符。while循环语句依次检查字符串值中的每个字符,直到遇到标识字符数组结尾的字符'\0'为止。由于p是指向字符的指针,所以每执行依次p++,p就将指向下一个字符的地址,p-s则表示已经检查过的字符数,即字符串的长度。
有效的指针运算包括相同类型指针之间的赋值运算;指针同整数之间的加法或减法运算;指向相同数组中元素的两个指针间的减法或比较运算;将指针赋值为0或指针与0之间的比较运算。其他所有显式的指针运算都是非法的,例如两个指针间的加法、乘法、除法、移位或屏蔽运算;指针同float或double类型之间的加法运算;不经强制类型转换而直接将指向一种类型对象的指针赋值给指向另一种类型对象的指针的运算。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值