目录
int *arr[5]:便是指一个指向5个元素,元素类型为整形指针的指针数组。
int (*arr)[5] 表示一个指向包含 5 个 int 类型元素的数组的指针。
初阶指针
什么是指针
指针是计算机编程中的一个重要概念,它是用来存储变量地址的一种数据类型。简单来说,指针就是变量的内存地址。
例如我定义
int a;
然后指针就=&a,那么我在屏幕上输出这个指针就相当于输出a的地址;
指针类型及定义指针
类型都有:
- 整型指针(int*):指向整型变量的指针。
- 字符型指针(char*):指向字符型变量或字符串的指针。
- 浮点型指针(float*):指向浮点型变量的指针。
- 双精度浮点型指针(double*):指向双精度浮点型变量的指针。
- 结构体指针(struct*):指向结构体类型的指针。
- 枚举类型指针(enum*):指向枚举类型的指针。
- 数组指针(int *arr[]):一个包含5个元素的指针数组,每个元素都是指向整型变量的指针。
还有二级指针及多级指针或者无类型指针{void *}。
野指针
野指针是指指向已经释放或者无效的内存地址的指针。当一个指针被分配了一块内存空间,然后该内存被释放或者指针被重新分配后,原指针仍然保留着之前的内存地址,但是这个地址不再有效。
使用野指针可能导致程序运行时出现不可预测的行为,包括崩溃、数据损坏和安全漏洞等问题。因此,应当避免使用野指针。
int* createInt() {
int num = 10;
return # // 返回局部变量的地址
}
int main() {
int* ptr = createInt(); // 获取指向局部变量的指针
// 在 createInt 函数返回后,ptr 变成了野指针
// 尝试解引用野指针,可能会导致未定义行为
printf("%d\n", *ptr); // 可能输出随机值或者崩溃
return 0;
}
这便是野指针的一种。
在使用过程中,为了避免野指针导致的程序运行错误,我们可以给指针初始化,赋给其一个空值NULL。
指针的运算
指针运算有
-
指针加法:可以将一个整数值加到指针上,用来实现指针的偏移。假设
ptr
是一个指向某种数据类型的指针,n
是一个整数,则表达式ptr + n
将指针偏移n
个单位,并返回偏移后的指针。例如,ptr + 1
将指向下一个相同类型的元素。 -
指针减法:可以将一个整数值从指针上减去,用来计算两个指针之间的距离。假设
ptr1
和ptr2
是指向相同数据类型的指针,则表达式ptr2 - ptr1
将返回两个指针之间的元素个数。例如,如果ptr2
指向数组中的第10个元素,ptr1
指向数组中的第5个元素,则表达式ptr2 - ptr1
将返回 5。 -
指针与整数的加法和减法:可以将一个指针与整数相加或相减,得到一个新的指针。这个整数值会乘以指针指向的数据类型的大小。例如,假设
ptr
是一个指向整型数据的指针,表达式ptr + 1
将返回下一个整型元素的地址。 -
指针递增和递减:可以使用
++
和--
运算符对指针进行递增和递减操作。递增操作将指针移动到下一个相同类型的元素,递减操作将指针移动到前一个相同类型的元素。
int arr[5] = {1, 2, 3, 4, 5};
int* ptr = arr; // 指向数组的第一个元素
// 指针加法和减法
ptr = ptr + 2; // 移动两个元素后的地址,指向数组的第三个元素
ptr = ptr - 1; // 移动一个元素前的地址,指向数组的第二个元素
// 指针与整数的加法和减法
ptr = arr + 3; // 移动3个整型元素后的地址,指向数组的第四个元素
ptr = ptr - 1; // 移动一个整型元素前的地址,指向数组的第三个元素
// 指针递增和递减
ptr++; // 移动到下一个整型元素,指向数组的第四个元素
ptr--; // 移动到前一个整型元素,指向数组的第三个元素
不同类型指针的后(或前)移一个单位时的字节数
在C语言中,指针向后访问一个单位时,不同类型的数据所后退的字节数是不同的。以下是一些常见数据类型及其对应的字节数:
- char: 1字节
- short: 2字节
- int: 4字节
- long: 4或8字节(取决于系统架构)
- float: 4字节
- double: 8字节
二级指针
二级指针是指指向指针的指针。在C语言中,可以使用二级指针来操作指针的指针,通常用于函数参数传递和动态内存分配等情况。
定义一个二级指针需要使用两个星号(**)来声明。例如,int** ptr
表示一个指向 int
类型指针的指针。
使用二级指针可以实现对指针本身的修改,即改变指针指向的地址。例如:
#include <stdio.h>
void changePointer(int** ptr) {
int* newPtr = NULL;
// 分配一个新的int类型变量的内存
newPtr = (int*)malloc(sizeof(int));
*newPtr = 10;
// 修改指针指向的地址
*ptr = newPtr;
}
int main() {
int* ptr = NULL;
changePointer(&ptr);
printf("%d\n", *ptr); // 输出:10
free(ptr); // 释放内存
return 0;
}
指针数组与数组指针的区别
int *arr[5]:便是指一个指向5个元素,元素类型为整形指针的指针数组。
具体来说,int *arr[5]
定义了一个名为 arr
的指针数组,该数组有 5 个元素。每个元素都可以存储一个 int*
类型的指针。
#include <stdio.h>
int main() {
int num1 = 10, num2 = 20, num3 = 30;
int* arr[5] = { &num1, &num2, &num3 };
// 访问指针数组中的元素
printf("%d\n", *arr[0]); // 输出:10
printf("%d\n", *arr[1]); // 输出:20
printf("%d\n", *arr[2]); // 输出:30
return 0;
}
在上述示例中,arr
是一个具有 5 个元素的指针数组。通过初始化 arr
数组,我们将三个整型变量的地址赋值给数组的前三个元素。注意,数组的大小为 5,但只有前三个元素被显式初始化,因此其余两个元素将被默认初始化为 NULL。
int (*arr)[5]
表示一个指向包含 5 个 int
类型元素的数组的指针。
具体来说,int (*arr)[5]
定义了一个名为 arr
的指针,该指针指向一个包含 5 个 int
类型元素的数组。因此,使用 arr
可以访问这个数组的所有元素。
下面是一个简单的示例,说明如何声明和使用 int (*arr)[5]
类型的指针:
#include <stdio.h>
void printArray(int (*arr)[5], int size) {
for (int i = 0; i < size; i++) {
for (int j = 0; j < 5; j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main() {
int array[3][5] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15} };
int (*arr)[5] = array;
printArray(arr, 3);
return 0;
}
在上述示例中,我们定义了一个二维数组 array
,它包含 3 个子数组,每个子数组都包含 5 个 int
类型的元素。然后,我们定义了一个指针 arr
,将其初始化为 array
的地址,即 &array[0]
。这里需要注意的是,arr
只能指向包含 5 个 int
类型元素的数组,不能指向其他大小的数组。
接下来,我们定义了一个函数 printArray
,用于打印一个包含 5 个 int
类型元素的数组。在函数中,我们使用 arr[i][j]
来访问数组中的元素,并打印出来。最后,在 main
函数中,我们调用了 printArray
函数,并将指针 arr
和数组的大小传递给它。
使用 int (*arr)[5]
类型的指针,可以方便地访问和操作包含 5 个 int
类型元素的数组。它常用于函数参数传递,以便函数可以处理不同大小的数组。