指针是 C 语言中一种强大的数据类型,它存储了变量的内存地址。通过指针,可以直接访问和修改内存中的数据,使得程序能够更加高效地操作数据。
目录
一.指针和指针变量的概念
指针实际上是内存地址。指针变量是用于存储指针的变量。
一个指针变量的值就是,某个内存单元的地址(或指针)。
“指针”是地址,是常量。
”指针变量“是指取值为地址的变量。
二.指针变量的定义和引用
1.变量值的存取方法
通过变量名来引用变量的内存单元值的方法被称为直接引用。
而通过内存地址引用内存单元值的方法称为间接引用。
2.指针的声明和指针变量的定义
在 C 语言中,声明指针需要使用 * 符号来标识,如下所示:
int *ptr; // 声明一个 int 类型的指针变量 ptr
指针变量的定义格式为:
staic int *p;// [存储类型] 数据类型符 *变量名;
3.指针变量的赋值
可以使用 & 符号来获取变量的地址,即取址操作。例如:
int num = 10; int *ptr = # // 将 num 的地址赋值给指针变量 ptr
4.空指针
空指针表示不指向任何有效的地址,使用 NULL 或 0 来表示空指针。可以用于判断指针是否指向有效的内存。
int *ptr = NULL; // 声明一个空指针
if (ptr == NULL) {
printf("指针为空\n");
}
5.指针变量的引用
通过解引用操作,可以使用指针来访问和修改指针所指向的内存中的数据。使用 * 符号进行解引用,如下所示:
int num = 10;
int *ptr = # // ptr 指向 num 的地址
printf("%d\n", *ptr); // 输出:10,通过解引用操作访问 num 的值
*ptr = 20; // 通过解引用操作修改 num 的值为 20
printf("%d\n", num); // 输出:20
三.指针和地址运算
1.指针变量的加减运算
指针是地址,地址是一种无符号的整数。
事实上,p是以sizeof(ptype)为单位进行加减的,而不是简单地将p的值加减n。
#include <stdio.h>
int main() {
int nums[] = { 1, 2, 3, 4, 5 };
int *ptr1 = &nums[1];
int *ptr2 = &nums[2];
printf("%p\n", ptr1);//输出ptr1的地址值(十六进制格式)
printf("%p\n", ptr2);//输出ptr2的地址值(十六进制格式)
return 0;
}
可以发现,ptr2的地址值比ptr1大4,正好是int的大小。
2.指针变量的关系运算
两个指针变量的关系运算就是表示它们所指向的内存单元之间的关系。(还可与零指针比较)
四.指针与数组
指针与数组密切相关,可以通过指针进行数组的遍历和操作。
1.数组的指针和指向数组的指针变量
1.1.数组的指针
数组的指针其实就是数组在内存中的起始地址。
1.2指向数组的指针变量
如果将数组的起始地址赋值给某个指针变量,那么该指针变量就是指向数组的指针变量。
int nums[] = {1, 2, 3, 4, 5};
int *ptr = nums; // 指针指向数组的第一个元素
for (int i = 0; i < 5; i++) { printf("%d ", *(ptr + i)); // 输出数组元素
}
2.指向多维数组的指针——数组指针
2.1.利用一般指针变量来访问多维数组
当使用一般指针变量来访问多维数组时,我们需要将多维数组转换为一维数组来处理,然后使用指针进行访问。下面是一个示例:
#include <stdio.h>
int main() {
int arr[2][3] = { {1, 2, 3}, {4, 5, 6} };
int *ptr = (int *)arr; // 将多维数组转换为一维数组
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", *(ptr + i * 3 + j)); // 使用指针访问数组元素
}
printf("\n");
}
return 0;
}
在这个例子中,我们定义了一个2x3的二维数组arr,并使用一般指针变量ptr将其转换为一维数组。通过指针ptr,我们可以使用指针算术运算来访问数组中的元素。
在嵌套的循环中,我们通过指针ptr和指针算术运算来访问数组元素。使用(ptr + i * 3+ j)可以计算出对应元素的地址,然后使用*(ptr + i * 3+ j)来获取该地址处的值。
输出结果将按照二维数组的行列顺序打印出来:
1 2 3
4 5 6
2.2.利用行指针来访问多维数组
3.元素为指针的数组——指针数组
指针数组是一种数组,其中的每个元素都是指针类型。下面是一个示例,展示了一个元素为指针的数组:
#include <stdio.h>
int main() {
int num1 = 10, num2 = 20, num3 = 30;
int *ptr[3] = { &num1, &num2, &num3 }; // 指针数组
for (int i = 0; i < 3; i++) {
printf("%d\n", *(ptr[i])); // 使用指针访问数组元素
}
return 0;
}
在这个例子中,我们定义了三个整型变量num1、num2和num3,并声明了一个包含三个指针变量的指针数组ptr。每个数组元素都是一个指向整型变量的指针。
通过循环遍历指针数组,我们可以使用指针解引用操作符*来访问数组元素的值,即*(ptr[i])
。这将获取指针数组中第i个元素所指向的值。
最后,我们打印出每个数组元素所指向的值:
10
20
30
五.指针与动态内存分配
1.静态内存分配
当程序中定义变量或数组后,系统就会给变量或数组按照其数据类型及大小来分配相应内存单元,这种分配内存的方式叫做静态内存分配。如:
int k; //系统将给变量k分配4字节的内存单元
char ch[10]; //系统将给ch数组分配10字节的内存块,首地址就是ch的值
2.动态内存分配和释放
C 语言中提供了动态内存分配函数 malloc,可以在运行时动态地分配内存空间。需要注意的是,在使用完内存后,必须使用 free 函数释放内存,以避免内存泄漏问题。
int *ptr = (int*)malloc(sizeof(int)); // 动态分配一个 int 类型大小的内存块
*ptr = 10; // 对该内存块进行赋值操作
printf("%d\n", *ptr); // 输出:10
free(ptr); // 释放内存
六.总结
指针在 C 语言中应用广泛,对于理解和掌握指针的概念和用法,对于编写高效、灵活的程序非常重要。
七.常见错误
1.定义多个指针变量时,只在第一个变量名前加*号。
2.指针变量未正确赋值就引用。
3.使用指针造成数组越界。
4.使用指针变量输入数据时多用了&。
5.直接将void*类型指针引用指针所指向的单元,未进行类型转换。
6.利用malloc函数时,忘记在malloc前加强制类型转换转换符。