龙空技术网

C|指针变量的算术运算和比较运算

小智雅汇 330

前言:

现在同学们对“c语言字符串相加减”大致比较注重,小伙伴们都需要知道一些“c语言字符串相加减”的相关知识。那么小编也在网摘上网罗了一些对于“c语言字符串相加减””的相关文章,希望各位老铁们能喜欢,你们快快来了解一下吧!

指针是具有类型信息的地址,对于32位平台的系统,其内存地址的值域是0x00000000~0xFFFFFFFF,指针变量可以支持一定类型的算术运算和比较运算。

指针是C语言为什么如此流行的一个重要原因。指针可以有效地实现诸如tree和list这类高级数据结构。其他有些语言,如Pascal和Modula-2,也实现了指针,但它们不允许在指针上执行算术或比较操作,也不允许以任何方式创建指向已经存在的数据对象的指针。正是由于不存在这方面的限制,所以,用C语言可以比使用其他语言编写出更为紧凑和有效的程序。同时,C对指针使用的不加限制正是许多令人欲哭无泪和咬牙切齿的错误的根源。不论是初学者还是经验老道的程序员,都曾深受其害。

1 指针算术运算

由于指针是一个内存地址,有意义的指针算术运算主要包括:指针与整数的加减运算(包括指针与1之间的加减运算)、 指针与指针之间的减法运算。地址相加,相乘没有意义。

1.1 指针与整数的加减运算(包括加减1)

指针与整数的加减运算主要适用于静态或动态数组以及字符串,是指将指针作为地址量加上或减去一个整数n, 其意义是指针当前指向位置的前方或后方第n个数据元素的位置。 由于指针可以指向不同数据类型,即数据长度不同的数据,所以这种运算的结果取决于指针指向的数据类型。

以指针目标类型的长度为移动(或偏移)步长,而不是目标类型元素内部的字节(没有实际意义)。 对一个指针加1将使它指向下一个变量。

也就是说,指针加减某个整数,其效果等同于将指针移动整数个变量大小。假设一个整型指针p指向整型变量x(占用 4个字节的内存), 而x的地址是1000。 则p+1 指向的地址就是 1004, p-3指向的地址就是988。一般来说,指针加减n, 就相当于指针的地址值加减n*sizeof( 数据类型)。

void arrcopy(int x[],int y[]){    register int *pl, *p2;    for(pl = x, p2 = y; pl < &x[SIZE];)        *pl++ = *p2++;}

对于数组的下标运算,其实质是指针与整数的加减运算的语法糖:

int arr[3][4];arr[i][j] = 0; // *(*(arr+i)+j) = 0;// arr的类型是int[4],arr+i 相当于(int *)((int)arr+sizeof(int[4]))// 以下输出相同的地址值:printf("%x\n",arr+2);printf("%x\n",(int *)((int)arr+sizeof(int[4])*2));

需要注意的是,指针与整数的加减运算,容易引起上溢和下溢错误,特别是加1或减1的相差一个元素的区别。

1.2 指针相减

如果两个指针都指向同一个数组中的元素, 那么它们之间可以相减。指针减法的结果经过调整(除以数组元素类型的长度), 表示两个指针在数组中相隔多少个元素。如果两个指针所指向的不是同一个数组中的元素, 那么它们之间相减的结果是未定义的。

两个指针相减的结果的类型是ptrdiff_t, 它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(以数组元素的长度为单位,而不是以字节为单位),因为减法运算的结果将除以数组元素类型的长度。例如, 如果pl指向array[i]而p2指向array[j], 那么p2-pl的值就是j-i的值。

int strlen(char* str){    char* p = str;    while(*p++);    return p-str-1;}
2 指针的比较运算

指针最常用的比较运算就是一个指针与0值(NULL或'\0')的比较,用于确定指针变量是否有效或动态内存分配是否成功?或者字符串是否已到结束位置(C风格字符串用'\0\做字符串的结束标志)。

如果两个指针都指向同一个数组中的元素, 那么它们之间还可以执行<、<=、>和>=等关系运算, 用于判断它们在数组中的相对位置。对两个不相关的指针执行关系运算, 其结果是未定义的。

以下是两个非空指针比较的经典应用。

/*memmove() copies a source memory buffer to a destination memory buffer.This routinerecognize overlapping buffers to avoid propogation.For cases where propagation is nota problem, memcpy() can be used.memmove()由src所指定的内存区域赋值count个字符到dst所指定的内存区域。 src和dst所指内存区域可以重叠,但复制后src的内容会被更改。函数返回指向dst的指针。*/void * my_memmove(void * dst,const void * src,int count){    void * ret = dst;    if(dst <= src || (char *)dst >= ((char *)src + count))    {        while(count--)        {            *(char *)dst = *(char *)src;            dst = (char *)dst + 1;            src = (char *)src + 1;        }    }    else    {        dst = (char *)dst + count - 1;        src = (char *)src + count - 1;        while(count--)        {            *(char *)dst = *(char *)src;            dst = (char *)dst - 1;            src = (char *)src - 1;        }    }    return(ret);}int main(){    char a[12];    puts((char *)my_memmove(a,"ammana_babi",16));    system("pause");    return 0;}
3 总结一下

指针运算只有作用于数组中其结果才是可以预测的。对任何并非指向数组元素的指针执行算术运算是非常危险的(且常常很难被检测到)。如果一个指针减去一个整数后,运算结果产生的指针所指向的位置在数组第一个元素之前, 那么它也是非常危险的。加法运算稍有不同, 如果结果指针指向数组最后一个元素后面的那个内存位置仍是合法(但不能对这个指针执行间接访问操作),不过再往后就可能有问题了。

应当说,指针变量的赋值也是一种运算,表示指针指向或与另一个变量建立联系。

另外,解引用表示对某指针目标取值,也是一种运算操作。

-End-

标签: #c语言字符串相加减