C语言进阶教程(再论指针和数组(2))

简介: C语言进阶教程(再论指针和数组(2))

前言

本篇文章我们继续讲解指针和数组,因为指针和数组对于刚刚学习C语言或者是学习了不久C语言的同学都会造成一些困扰,所以这里多用几篇文章来帮助大家理解。


一、指针的加1减1运算

指针的加1减1运算是指针进行后移或前移一个元素的操作。对指针进行加减操作时,指针的值会根据指针所指向的数据类型的大小进行相应的增加或减少。

具体来说,假设 ptr 是一个指向某种数据类型(如整数、字符等)的指针,那么 ptr + 1 就会将指针的值增加一个元素大小的偏移量,使其指向下一个元素。相应地,ptr - 1 将指针的值减少一个元素大小的偏移量,使其指向上一个元素。

例如,考虑一个整型指针的例子:

int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr;
printf("%p\n", ptr);       // 输出 arr 的地址
printf("%p\n", ptr + 1);   // 输出 arr 的下一个元素的地址
printf("%p\n", ptr - 1);   // 输出 arr 的上一个元素的地址

输出结果:

0x7ffeed06b3b0
0x7ffeed06b3b4
0x7ffeed06b3ac

在这个例子中,ptr 指向数组 arr 的第一个元素。通过 ptr + 1,指针的值增加了一个整型数据的大小(通常是4个字节)的偏移量,指向了 arr 的下一个元素。相反,通过 ptr - 1,指针的值减少了一个整型数据的大小的偏移量,指向了 arr 的上一个元素。

需要注意的是,指针进行加减运算时,移动的距离取决于指针所指向的数据类型的大小。这保证了指针正确地指向连续的内存位置。此外,指针运算也受限于有效的内存边界,不应越界访问或指向无效的内存位置。

二、指针的减法运算

指针的减法运算用于计算两个指针之间的偏移量(以元素个数为单位)。它可用于确定两个指针之间的元素数量或计算指针相对于基准指针的偏移量。

假设我们有两个指针 ptr1 和 ptr2,它们指向同一类型的元素。可以使用减法运算符 - 计算它们之间的差值,并得到它们之间元素的个数。

例如,考虑以下示例,其中 ptr1 和 ptr2 是指向整型数组中的不同元素的指针:

int arr[5] = {1, 2, 3, 4, 5};
int* ptr1 = &arr[2];
int* ptr2 = &arr[0];
ptrdiff_t diff = ptr1 - ptr2;
printf("Elements between ptr1 and ptr2: %td\n", diff);

输出结果:

Elements between ptr1 and ptr2: 2

在这个例子中,ptr1 指向数组 arr 的第3个元素(值为3),而 ptr2 指向数组 arr 的第1个元素(值为1)。通过 ptr1 - ptr2 计算两个指针之间的偏移量,得到结果为2,表示 ptr1 与 ptr2 之间有2个元素。

需要注意的是,减法运算的结果的类型是 ptrdiff_t,它是 stddef.h 头文件中定义的整数类型。它根据平台的位数和编译器的实现可能有所不同。因此,在打印结果时,可以使用 %td 格式说明符来匹配 ptrdiff_t 类型的值。

此外,减法运算也可用于计算指针相对于基准指针的偏移量。通过将一个指针减去另一个指针,可以获得它们之间的偏移量,以字节数为单位。这对于在数组或缓冲区中位置计算非常有用。

注意:

1.只有当两个指针指向同一个数组中的元素时,指针相减才有意义,其意义为指针所指元素下标差。

2.当两个指针指向的元素不在同一个数组中时,结果未定义。


三、指针的关系运算

指针的关系运算符用于比较指针的大小关系,判断它们在内存中的相对位置。以下是指针的关系运算符及其示例用法:

大于运算符 (>):用于比较两个指针的大小,如果左侧指针指向的地址在内存中比右侧指针的地址大,则关系表达式的结果为真。

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int* ptr1 = arr[0];
    int* ptr2 = arr[2];
    if (ptr2 > ptr1) {
        printf("ptr2 is greater than ptr1.\n");
    } else {
        printf("ptr2 is not greater than ptr1.\n");
    }
    return 0;
}

输出结果:

ptr2 is greater than ptr1.

在这个例子中,我们定义了一个整型数组arr,并使用指针ptr1和ptr2分别指向数组的不同元素。通过使用大于运算符(>)比较ptr2和ptr1,我们可以判断ptr2指向的地址是否在ptr1指向的地址之后。

小于运算符 (<):用于比较两个指针的大小,如果左侧指针指向的地址在内存中比右侧指针的地址小,则关系表达式的结果为真。针对上述示例进行修改:

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int* ptr1 = arr[2];
    int* ptr2 = arr[4];
    if (ptr1 < ptr2) {
        printf("ptr1 is less than ptr2.\n");
    } else {
        printf("ptr1 is not less than ptr2.\n");
    }
    return 0;
}

输出结果:

ptr1 is less than ptr2.

在这个例子中,我们修改了指针ptr1和ptr2分别指向了数组arr的不同元素。通过使用小于运算符(<)比较ptr1和ptr2,我们可以判断ptr1指向的地址是否在ptr2指向的地址之前。

需要注意的是,指针的关系运算符只能用于两个指针之间的比较,不能用于指针和其他类型的变量之间的比较。此外,比较时需要确保两个指针指向相同的数组或在相同的内存块中,否则结果可能是未定义的。


四、指针比较运算

指针的比较运算可以用于判断两个指针是否指向同一个对象或确定它们在内存中的相对位置。以下是一个示例,展示了指针比较运算的用法:

#include <stdio.h>
int main() {
    int var1 = 5;
    int var2 = 10;
    int* ptr1 = &var1;
    int* ptr2 = &var2;
    int* ptr3 = &var1;
    // 比较ptr1和ptr2
    if (ptr1 == ptr2) {
        printf("ptr1 and ptr2 point to the same location.\n");
    } else {
        printf("ptr1 and ptr2 point to different locations.\n");
    }
    // 比较ptr1和ptr3
    if (ptr1 == ptr3) {
        printf("ptr1 and ptr3 point to the same location.\n");
    } else {
        printf("ptr1 and ptr3 point to different locations.\n");
    }
    return 0;
}

输出结果:

ptr1 and ptr2 point to different locations.
ptr1 and ptr3 point to the same location.

在这个例子中,我们定义了两个整数变量var1和var2,并使用指针ptr1、ptr2和ptr3分别指向它们。通过使用相等运算符==来比较指针,我们可以判断指针是否指向相同的内存位置。

在第一个比较中,ptr1和ptr2指向不同的变量var1和var2,因此输出是"ptr1 and ptr2 point to different locations."。

在第二个比较中,ptr1和ptr3都指向同一个变量var1,因此输出是"ptr1 and ptr3 point to the same location."。

需要注意的是,指针比较运算只比较指针的值,即它们所指向的内存地址。它们并不比较指针所指向的对象的值。如果需要比较指针所指向对象的值,应该使用间接引用运算符*来获取指针所指向的对象的值,并进行比较。


总结

本篇文章我们主要就是讲解了指针的运算,这些大家必须牢牢掌握。


相关文章
|
10天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
24 3
|
22天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
44 0
|
9天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
18 2
|
18天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
24 1
|
24天前
|
存储 编译器 C语言
【c语言】数组
本文介绍了数组的基本概念及一维和二维数组的创建、初始化、使用方法及其在内存中的存储形式。一维数组通过下标访问元素,支持初始化和动态输入输出。二维数组则通过行和列的下标访问元素,同样支持初始化和动态输入输出。此外,还简要介绍了C99标准中的变长数组,允许在运行时根据变量创建数组,但不能初始化。
35 6
|
21天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
21天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
21天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
27天前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
27天前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。