【C语言】指针----初阶(下)

简介: 【C语言】指针----初阶(下)

四、指针运算



4.1 指针+-整数


指针加+-运算用于将指针移动指定的偏移量,以便访问其他地址处的数据。例如,如果有一个指向整型数组的指针p,可以使用p+n或p-n将指针移动n个整型长度的位置。

#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}


4.2 指针-指针


可以对两个指针进行减法运算,得到它们之间的距离(以元素个数为单位)。这在处理数组或动态内存分配时非常有用。例如,假设有两个int类型的指针ptr1和ptr2,我们可以进行如下操作:


int distance = ptr2 - ptr1; // 计算ptr2和ptr1之间的距离(以int元素个数为单位)


需要注意的是,指针运算应该谨慎使用,确保指针指向的内存是有效的。否则,可能会导致未定义行为或内存错误。此外,不同类型的指针之间不应进行直接算术运算,因为它们可能引用不同大小的数据。只有在指向同一数组的元素或有效分配的内存区域时,指针之间的运算才是有效的。


4.3 指针的关系运算


在C、C++等编程语言中,指针的关系运算用于比较指针的地址或者判断指针是否为NULL。下面是指针的关系运算符及其含义:


📌相等(==):用于判断两个指针是否指向同一个内存地址。如果两个指针指向相同的地址,则关系表达式为真,否则为假。

1. int* ptr1;
2. int* ptr2;
3. 
4. if (ptr1 == ptr2) {
5. // 指针ptr1和ptr2指向相同的地址
6. }


📌不相等(!=):用于判断两个指针是否指向不同的内存地址。如果两个指针指向不同的地址,则关系表达式为真,否则为假。

int* ptr1;
int* ptr2;
if (ptr1 != ptr2) {
    // 指针ptr1和ptr2指向不同的地址
}


📌大于(>)、小于(<)、大于等于(>=)、小于等于(<=):这些关系运算符用于比较两个指针所指向的地址之间的顺序关系。只有当指针指向同一个数组中的元素或者在有效的内存范围内时,这些关系运算符才有定义。

int* ptr1;
int* ptr2;
if (ptr1 > ptr2) {
    // ptr1指向的地址在ptr2指向的地址之后
}
if (ptr1 < ptr2) {
    // ptr1指向的地址在ptr2指向的地址之前
}
if (ptr1 >= ptr2) {
    // ptr1指向的地址在ptr2指向的地址之后或相同
}
if (ptr1 <= ptr2) {
    // ptr1指向的地址在ptr2指向的地址之前或相同
}


📌空指针检查:指针的关系运算还可以用于检查指针是否为空(指向NULL)。在C和C++中,NULL是一个预定义的宏,用于表示一个空指针。

int* ptr = NULL;
if (ptr == NULL) {
    // 指针ptr是空指针
}
if (ptr != NULL) {
    // 指针ptr不是空指针
}


需要注意的是,对于关系运算符(>, <, >=, <=),只有在指针指向同一数组的元素或有效分配的内存区域时,比较的结果才是有效的。在进行指针比较之前,最好确保指针指向的内存是有效的,否则可能会导致未定义行为。


五、 指针和数组



我们来看一个例子:

#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
return 0;
}


运行结果:

84605158ecb14cd3b1b6c0e64f979eef.png


可见数组名和数组首元素的地址是一样的。

结论:数组名表示的是数组首元素的地址。(一般情况下)

那么这样写代码是可行的:

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址


既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能。

例如:

#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr)/sizeof(arr[0]);
for(int i=0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}


运行结果: 


4de3aa19bc2e42fa93cec043bfe7af65.png


所以 p+i 其实计算的是数组 arr 下标为i的地址。

那我们就可以直接通过指针来访问数组。

如下:

#include<stdio.h>
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}


运行结果:

c2cee5b5480843ac833fee72442c40ee.png


六、二级指针



二级指针(double pointer)是指指向指针的指针。我们可以使用指向指针的指针来处理指针的引用或修改。它们在一些情况下非常有用,特别是在涉及到函数参数传递和动态内存分配等方面。


定义二级指针的语法为在指针类型名称前加上两个星号(**):

int** doublePtr;


6.1二级指针与多级指针


#include<stdio.h>
int main()
{
  int a = 10;
  int* pa = &a;
  int** ppa = &pa;
  int*** pppa = &ppa;
  printf("%p\n", a);
  printf("%p\n", &a);
  printf("\n%p\n", pa);
  printf("%p\n", &pa);
  printf("\n%p\n", ppa);
  printf("%p\n", &ppa);
  printf("\n%p\n", pppa);
  printf("%p\n", &pppa);
  return 0;
}


20bf9ebef3c241efa7a35fef93b95428.pnge68d56345d64404587cc15821a846f27.jpg


6.2二级指针运算


📌*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .

1. int b = 20;
2. *ppa = &b;//等价于 pa = &b;


📌**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .

1. **ppa = 30;
2. //等价于*pa = 30;
3. //等价于a = 30;


七、指针数组



指针数组是一个数组,其中的每个元素都是指针。我们可以创建指针数组来存储一组指向不同数据类型的指针。这些指针可以指向数组、字符串、函数等各种数据类型,从而实现更灵活的数据结构和操作。


定义指针数组的语法为在指针类型名称后加上方括号([]):

int* ptrArray[5]; // 定义一个包含5个int指针的数组


c6b46e3b0abc4d22bf3d7acf0a32ed99.jpg

指针数组非常适用于存储字符串数组。在C语言中,字符串被表示为字符数组,并且每个字符串都以空字符('\0')结尾。使用指针数组可以更方便地管理字符串的集合:

const char* names[] = { "Alice", "Bob", "Charlie" };


在上面的示例中,我们创建了一个包含3个指针的指针数组,每个指针都指向一个字符串常量。

需要注意的是,指针数组中的每个指针应该指向有效的内存地址。否则,当我们尝试通过这些指针访问数据时,可能会导致未定义行为或者出现野指针的问题。确保在使用指针数组之前,为每个指针分配合适的内存或者让它们指向有效的数据。同时,记得在不再需要这些指针数组时,及时释放其所指向的内存,避免内存泄漏。


🔥今天的分享就到这里,如果觉得博主的文章还不错的话,请👍三连支持一下博主哦🤞


image.png

目录
相关文章
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
52 0
|
10天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
58 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
10天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
34 9
|
10天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
32 7
|
20天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
81 12
|
13天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
13天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
43 3
|
14天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
20天前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
42 10
|
13天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
29 1