1. 指针和指针变量的基本概念
-
指针的定义:指针是变量的地址,指向某个数据类型的值。声明指针时,需要指定指针指向的数据类型。
-
语法:
数据类型 *指针名;
int *p; // 定义指针变量
p = &var_runoob;
- 指针变量:就是存储这个地址的变量
- 语法:
数据类型 *指针变量名 [初始地址值];
1.1 const修饰的指针变量
从左往右看,跳过类型,看修饰那个字符:
* ,值不能修改 //const int *p=&a;
指针变量 ,指向不能改 //int * const p1=&a
2. 指针的基本操作
-
取地址运算符
&
:
使用&
可以获取变量的地址。int a = 10; int *p = &a; // p 指向 a 的地址
-
解引用运算符
*
:
使用*
可以访问指针指向地址的值。int b = *p; // b 被赋值为 a 的值,即 10
2.1 间接修改变量的值
//通过指针间接修改变量的值
int num=10;
int *p=#
*p=20;
printf("%d\n",*p);
2.2 指针常用运算
格式: 指针+(-)整数
指针与整数的加减运算,表示指针所指向的内存地址和移动。指针移动的单位,与指针指向的数据类型有关。数据类型占据多少个字节,每单位就移动多少个字节。
2.3 指针步长
指针指向的地址相对于当前地址的偏移量。步长取决于所指向的数据类型。
注!!!指针p+ 不是地址加一,而是指针指向的下一个数据遍历数组
只有连续的同类型区域,指针加减才有意义
2.4 指针遍历
// 一维数组的遍历
// 1、利用sizeof遍历
for (int i = 0; i < sizeof(list1) / sizeof(list1[0]); i++) {
printf("%d===", list1[i]);
}
printf("\n");
// 2、利用指针进行遍历
int* p = list1;
for (int i = 0; i < 4; i++) {
printf("%d=====", *(p + i));
}
//二维数组遍历
int list[3][3] = { {1,4,7},{2,5,8},{3,6,9} };
//索引遍历
for (int i = 0;i < 3;i++) {
for (int j = 0;j < 3;j++) {
printf("%d ", list[i][j]);
}
printf("\n");
}
// 利用指针遍历二维数组
int* p = &list[i][j];
for (int i = 0;i < 9;i++) {
printf("%d ", *(p + i));
if ((i + 1) % 3 == 0) {
printf("\n");
}
}
2.5 指针大小
sizeof()测得是指针变量指向存储地址的大小
32位平台,指针都是32位(4字节)
64位平台,指针都是64位(8字节)
2.6 指针的类型
- 基本类型指针:如
int*
、char*
、float*
等 - 指向指针的指针:指向另一指针,例如
int** pp;
- 函数指针:指向函数的指针,能够通过指针调用函数
3. 二级指针(多级指针)
二级指针:就是指向一个一级指针变量地址的指针。
多级指针:就是指针的指针。
格式:数据类型** 指针变量
int a=10;
int *p=&a;
int* *pp=&p;
重!!! 指针本身也是个变量,需要内存取存储,指针也有自己的地址
指针内存存储的是他所指向变量的地址
//动态创建二维数组
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3; // 行数
int cols = 4; // 列数
int **array; // 二级指针
// 动态分配内存
array = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
array[i] = (int *)malloc(cols * sizeof(int));
}
// 初始化数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
array[i][j] = i * cols + j; // 填充一些值
}
}
// 打印数组
printf("二维数组的内容:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d ", array[i][j]);
}
printf("\n");
}
// 释放内存
for (int i = 0; i < rows; i++) {
free(array[i]); // 先释放每一行
}
free(array); // 再释放行指针
return 0;
}
4. 指针与数组
- 数组名在大多数情况下被视为指向数组首元素的指针,可以使用指针遍历数组。
4.1 一维数组和指针
#include <stdio.h>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr; // 指针指向数组的首元素
// 输出数组元素和指针指向的元素
for (int i = 0; i < 5; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
printf("ptr[%d] = %d\n", i, *(ptr + i));
}
return 0;
}
4.2 指针访问数组元素
int a[10]={1,2,3,4,5};
int *p=&a[0];
a[0]; 表示a[0]的值
地址;&s[0],p,a
值;a[0],*p,*a
a[i]; 表示a[i]的值
地址;&a[i],p+i,a+i
值; a[i],*(p+i),*(a+i)
重!!*和[ ]效果一样,都是操作指针所指向的内存
4.3 指针带下标使用
获取数组元素值得三种表示形式:
(1)a[i][j] 下标法
(2)*(a[i]+j) 一维数组名
(3)*(*(a+i)+j) 二维数组名
5. 示例代码
示例 1:基本指针操作
#include <stdio.h>
int main() {
int a = 5;
int *p = &a; // p 保存 a 的地址 printf("a 的值: %d\n", a);
printf("p 指向的值: %d\n", *p); // 解引用 p,得到 a 的值 *p = 10; // 通过指针修改 a 的值
printf("修改后 a 的值: %d\n", a);
return 0;
}
字符数组和字符指针变量
字符数组由若干个元素组成,每个元素放一个字符。 数组名是个常量,不可重新赋值
字符指针变量中存放的是地址,绝不是将字符串放入字符指针变量。指针变量是个变量,可以多次赋值。
字符指针可直接赋值为字符串,保存实际上是字符串得首地址是个常量。这时不能修改
字符串数组的表示
二位字符数组:
#include <stdio.h>
int main() {
// 定义一个3行5列的二维字符数组
char array[3][5] = {
{'H', 'e', 'l', 'l', 'o'},
{'W', 'o', 'r', 'l', 'd'},
{'C', '!', '!', '!', '!'}
};
// 打印二维字符数组内容
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 5; j++) {
printf("%c ", array[i][j]);
}
printf("\n");
}
return 0;
}
字符指针数组:
#include <stdio.h>
int main() {
// 定义一个字符指针数组,存储三条字符串
char *array[] = {
"Hello",
"World",
"C Programming"
};
// 获取数组的大小
int size = sizeof(array) / sizeof(array[0]);
// 打印字符指针数组内容
for (int i = 0; i < size; i++) {
printf("%s\n", array[i]);
}
return 0;
}
示例 2:
数组指针
数组指针:能够指向数组的指针
#include <stdio.h>
int main() {
int array[] = {1, 2, 3, 4, 5};
int *p = array; // p 指向数组的首元素
for (int i = 0; i < 5; i++) {
printf("array[%d] = %d\n", i, *(p + i)); // 使用指针访问数组
}
return 0;
}
指针数组
是数组,是存放指针的数组
格式;数据类型 *指针数组名[大小]; //int *arr[5];
#include <stdio.h>
int main() {
// 定义一个指针数组,数组中的元素是指向字符串的指针
const char *fruits[] = {
"Apple",
"Banana",
"Cherry",
"Date",
"Elderberry"
};
// 计算数组的大小
int size = sizeof(fruits) / sizeof(fruits[0]);
// 遍历指针数组并打印每个字符串
for (int i = 0; i < size; i++) {
printf("%s\n", fruits[i]);
}
return 0;
}
示例 3:指向指针的指针
#include <stdio.h>
int main() {
int a = 10; int *p = &a; // p 是指向 a 的指针
int **pp = &p; // pp 是指向指针 p 的指针
printf("通过 pp 访问 a: %d\n", **pp); // 二级解引用 **pp = 20;
// 通过指向指针的指针修改 a 的值
printf("修改后 a 的值: %d\n", a);
return 0;
}
示例 4:函数指针
#include <stdio.h>
void greet() {
printf("Hello, World!\n");
}
int main() {
void (*func_ptr)() = greet; // 定义函数指针指向函数 greet func_ptr(); // 调用函数 return 0;
}
示例 5:通过指针修改函数参数
#include <stdio.h>
void modify(int *p) {
*p = 30; // 修改指针指向的值
}
int main() {
int a = 20;
printf("修改前 a 的值: %d\n", a);
modify(&a); // 传递 a 的地址
printf("修改后 a 的值: %d\n", a);
return 0;
}
6. 动态内存分配
使用指针可以动态地分配内存(使用 malloc
、calloc
、realloc
),并在使用完后释放内存(使用 free
)。
示例 6:动态内存分配
#include <stdio.h>
#include <stdlib.h>
int main() {
nt *arr; int n = 5; // 动态分配内存
arr = (int *)malloc(n * sizeof(int));
if (arr == NULL) {
printf("内存分配失败\n");
return 1;
}
// 初始化数组 for (int i = 0; i < n; i++) {
arr[i] = i + 1; // 数组元素初始化为 1 到 5
}
// 打印数组元素 for (int i = 0; i < n; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
// 释放分配的内存
free(arr);
return 0;
}
结论
指针是 C 语言的核心组成部分,理解指针的操作对于有效使用 C 语言至关重要。指针能够提高程序的灵活性和效率,但也需要小心管理,以避免内存泄漏和非法内存访问等问题。希望以上内容能帮助你更深入地理解 C 语言中的指针。