一、一级指针遍历二维数组
二维数组的传统遍历
#include <stdio.h>
int main() {
// 定义并初始化一个3行4列的二维数组
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int i,j;
// 计算行数:整个数组大小除以第一行的大小
int n = sizeof(a) / sizeof(a[0]);
// 计算列数:第一行大小除以每个元素的大小
int m = sizeof(a[0]) / sizeof(int);
// 遍历二维数组
for (i = 0; i < n; i++) { // 遍历每一行
for (j = 0; j < m; j++) { // 遍历当前行的每一列
printf("%d\t", a[i][j]); // 打印元素,用制表符分隔
}
printf("\n"); // 每行结束后换行
}
return 0;
}
使用一级指针遍历二维数组
#include <stdio.h>
int main() {
// 创建一个3行4列的二维数组
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int i;
// 计算行数和列数
int n = sizeof(a) / sizeof(a[0]);
int m = sizeof(a[0]) / sizeof(int);
// 声明一个指针变量
int *p;
// 当数组赋值给指针时,传递的是数组第一个元素的地址
p = &a[0][0];
// 使用指针遍历所有元素
for (i = 0; i < n * m; i++) {
printf("%d ", *(p + i));
}
printf("\n");
return 0;
}
二、行地址与数组指针
二维数组名的地址特性
二维数组名代表数组的起始地址
#include <stdio.h>
int main() {
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
printf("a + 0: %p\n", a + 0); // 第0行地址
printf("a + 1: %p\n", a + 1); // 第1行地址(移动16字节)
printf("a + 2: %p\n", a + 2); // 第2行地址(移动32字节)
// 计算地址差值
printf("地址差值: %ld 字节\n", (char*)(a+1) - (char*)a);
return 0;
}
行地址与数组指针
二维数组名代表数组的起始地址,数组名+1,是移动一行元素,二维数组名常被称为行地址。
#include <stdio.h>
int main() {
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
// 定义数组指针:指向包含4个int的数组的指针
int (*p)[4] = a; // 行地址
printf("a的地址: %p\n", a);
printf("p的地址: %p\n", p);
printf("a + 1地址: %p\n", a + 1);
printf("p + 1地址: %p\n", p + 1);
printf("a + 2地址: %p\n", a + 2);
printf("p + 2地址: %p\n", p + 2);
return 0;
}
三、数组指针的三种访问方式
p[i][j]、*(p[i] + j)、*(*(p+i) + j) 这三种写法都用于访问二维数组元素,它们是完全等价的。
示例演示
#include <stdio.h>
int main() {
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int (*p)[4] = arr; // p是指向包含4个int的数组的指针
// 访问arr[1][2](值为7)的三种等价方式:
printf("p[1][2] = %d\n", p[1][2]); // 方式一
printf("*(p[1] + 2) = %d\n", *(p[1] + 2)); // 方式二
printf("*(*(p+1) + 2) = %d\n", *(*(p+1) + 2)); // 方式三
// 详细解释每种方式的步骤:
printf("\n=== 详细解释 ===\n");
// 方式一:p[1][2]
printf("p[1][2]: 直接下标访问\n");
// 方式二:*(p[1] + 2)
printf("*(p[1] + 2):\n");
printf(" p[1] = *(p+1) → 指向第1行的指针\n");
printf(" p[1] + 2 → 指向第1行第2列元素的指针\n");
printf(" *(p[1] + 2) → 解引用得到值%d\n", *(p[1] + 2));
// 方式三:*(*(p+1) + 2)
printf("*(*(p+1) + 2):\n");
printf(" p+1 → 指向第1行的指针\n");
printf(" *(p+1) → 第1行的数组名\n");
printf(" *(p+1) + 2 → 指向第1行第2列元素的指针\n");
printf(" *(*(p+1) + 2) → 解引用得到值%d\n", *(*(p+1) + 2));
return 0;
}
四、字符指针与字符串
字符指针的基本使用
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针当中。
#include <stdio.h>
int main() {
char str[] = "Hello World";
char *p = str; // p指向字符串的首地址
printf("字符串: %s\n", str);
printf("指针指向: %s\n", p);
printf("str地址: %p\n", str);
printf("p的值: %p\n", p);
// 通过指针访问字符
printf("第一个字符: %c\n", *p);
printf("第二个字符: %c\n", *(p+1));
return 0;
}
大小写转换示例
在C语言中,字符是用ASCII码表示的:
'A'= 65,'B'= 66, ...,'Z'= 90'a'= 97,'b'= 98, ...,'z'= 122
#include <stdio.h>
int main() {
char s[] = "Hello World";
char *p = s;
printf("原始字符串: %s\n", s);
while (*p != '\0') {
if (*p >= 'A' && *p <= 'Z') {
*p += 32; // 大写转小写
} else if (*p >= 'a' && *p <= 'z') {
*p -= 32; // 小写转大写
}
p++;
}
printf("转换后: %s\n", s);
return 0;
}
五、指针数组
指针数组的基本用法
指针数组的一般说明形式:数据类型 *指针数组名[大小]
#include <stdio.h>
int main() {
int a = 10, b = 20, c = 30;
int *p[3]; // 声明一个包含3个int指针的数组
p[0] = &a;
p[1] = &b;
p[2] = &c;
// 通过指针数组访问值
for(int i = 0; i < 3; i++) {
printf("p[%d] = %p, *p[%d] = %d\n", i, p[i], i, *p[i]);
}
return 0;
}
字符串指针数组
因64位系统下指针数组的大小都是八个字节(包括char ,int),所以在计算数组大小时sizeof(char*)要这么写。
#include <stdio.h>
int main() {
char *s[] = {"BeiJing", "ShangHai", "GuangZhou"};
int i;
// 计算数组元素个数
int count = sizeof(s) / sizeof(char*);
printf("城市列表:\n");
for (i = 0; i < count; i++) {
printf("%d: %s\n", i, s[i]);
}
// 显示每个指针的值
printf("\n指针地址:\n");
for (i = 0; i < count; i++) {
printf("s[%d] = %p, 指向: %s\n", i, s[i], s[i]);
}
return 0;
}
六、数组指针与指针数组的区别
指针数组 int *p[5]
- 指针数组,是一维数组,每个元素都是
int* - 指针数组经常结合二维数组使用,储存每行首元素的地址
- 本质是数组,储存内容是指针
#include <stdio.h>
int main() {
int a = 1, b = 2, c = 3, d = 4, e = 5;
int *p[5] = {&a, &b, &c, &d, &e}; // 指针数组
printf("指针数组示例:\n");
for(int i = 0; i < 5; i++) {
printf("p[%d] = %p, *p[%d] = %d\n", i, p[i], i, *p[i]);
}
return 0;
}
数组指针 int (*p)[5]
- 指向数组的指针
- 本质是指针,指向的内容是含有5个元素的一维数组
- 一维数组名取地址,或者二维数组取名,都可以赋予它
#include <stdio.h>
int main() {
int arr[3][5] = {
{1, 2, 3, 4, 5},
{6, 7, 8, 9, 10},
{11, 12, 13, 14, 15}
};
int (*p)[5] = arr; // 数组指针,指向包含5个int的数组
printf("数组指针示例:\n");
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 5; j++) {
printf("%2d ", p[i][j]);
}
printf("\n");
}
return 0;
}
关键点总结
| 特性 | 指针数组 | 数组指针 |
|---|---|---|
| 声明 | int *p[5] | int (*p)[5] |
| 本质 | 数组 | 指针 |
| 存储内容 | 多个指针 | 一个数组地址 |
| 常用场景 | 字符串数组、多级指针 | 二维数组操作 |