指针数组
指针数组是一个数组,是指由指针构成的数组,在这个数组中的所有元素都是指针,每个指针占用相同的字节。
我们知道整型数组是用来存储整型数据的数组:
int arr[5]={11,20,32,62,0};
数组arr有5个元素,每个元素都是整型数据。
指针数组就是用来存储指针的数组,声明指针数组需要在数据类型的后面添加“*”符号,表示这是一个指针数组。
例如:
int* a[6];
//定义了一个整型指针数组,名称为a,数组中的元素类型是指向整型数据的指针,数组大小为6个元素。
float* score[3+3];
//定义了一个浮点数组,名称为score,数组中的元素类型是指向浮点数据的指针,数组大小为5个元素。
例1:指针数组的使用
案例定义了一个指针数组,每个指针都指向一个整数。然后遍历这个指针数组并打印出所有整数。
程序清单
#include <stdio.h>
int main() {
// 声明一个指针数组,每个元素都是一个字符串指针
char *array[] = {
37,
12,
0,
101,
19
};
// 获取数组的长度
int length = sizeof(array) / sizeof(array[0]);
// 遍历数组并打印每个整数
for (int i = 0; i < length; i++) {
printf("%d\n", array[i]);
}
return 0;
}
案例代码首先定义了一个包含5个整数的指针数组。然后,通过计算sizeof(array) / sizeof(array[0])获取数组的长度。接着,使用一个for循环遍历数组,并使用printf函数打印每个整数。
例2:猜数游戏
案例使用指针数组创建一个猜数字的小游戏。游戏会随机生成一个1到100之间的数字,然后让用户尝试猜测这个数字。用户每次输入猜测的数字后,程序会告诉用户猜测的数字比生成的数字是高、低、还是正确。
程序清单
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 函数声明
void playGame();
int generateRandomNumber();
void getUserGuess(int *guess);
void checkGuess(int number, int guess);
int main() {
// 开始游戏
playGame();
return 0;
}
// 游戏主循环
void playGame() {
int randomNumber = generateRandomNumber();
int guess;
int attempts = 0;
printf("欢迎来到猜数字游戏!\n");
printf("我已经想好了一个1到100之间的数字。\n");
do {
getUserGuess(&guess);
attempts++;
checkGuess(randomNumber, guess);
} while (guess != randomNumber);
printf("恭喜你,你猜对了!数字是 %d。\n", randomNumber);
printf("你总共尝试了 %d 次。\n", attempts);
}
// 生成1到100之间的随机数字
int generateRandomNumber() {
srand(time(NULL)); // 使用当前时间作为随机数种子
return rand() % 100 + 1;
}
// 获取用户的猜测并将其存储在指针所指向的位置
void getUserGuess(int *guess) {
printf("请输入你的猜测:");
scanf("%d", guess);
while (*guess < 1 || *guess > 100) {
printf("输入无效,请重新输入一个1到100之间的数字:");
scanf("%d", guess);
}
}
// 检查用户的猜测并给出相应的反馈
void checkGuess(int number, int guess) {
if (guess < number) {
printf("太低了!再试一次。\n");
} else if (guess > number) {
printf("太高了!再试一次。\n");
}
}
案例输出:
欢迎来到猜数字游戏!
我已经想好了一个1到100之间的数字。
请输入你的猜测:50
太低了!再试一次。
请输入你的猜测:75
太高了!再试一次。
请输入你的猜测:62
太低了!再试一次。
请输入你的猜测:68
恭喜你,你猜对了!数字是 68。
你总共尝试了 4 次。
注意:每次运行程序时,由于generateRandomNumber函数使用当前时间作为随机数种子,因此生成的随机数字都会不同。此外,为了确保程序的健壮性,getUserGuess函数会检查用户的输入是否在有效范围内,如果不是,则要求用户重新输入。
数组指针
指针变量也可以指向数组元素的内存地址,可以利用指针来访问数组的元素。当声明一个数组变量后,C编译器会为该数组分配连续的存储空间,用于存储数组内的元素,每个元素占用的空间为该元素所属数据类型的空间大小。
一个指针变量可以指向一个数组,也可以指向一个数组元素。将一个数组的地址赋值给指针变量可以写为:
p = a;
该语句将数组a的首地址赋值给指针变量p。当把一个数组元素的首地址,一般是数组第一个元素的地址赋值给指针变量时,该指针变量是指向了数组第1个元素的内存地址,然后应用指针的加减运算就可以访问数组的全部元素。

上图描述了指针与数组元素内存地址的关系。array为具有三个短整型元素的数组,p为短整型的指针,p=array将数组array首地址赋值给p,此时指针变量p指向数组array的第1个元素,p+1指向第2个元素,p+2指向第3个元素。
一个指针变量既可以指向一个数组,也可以指向一个数组元素。如果要使指针指向数组的第一个元素,可以把数组名或第一个数组元素的地址赋值给该指针变量。如果需要该指针指向第i个元素的地址,可以把第i个元素的内存地址或数组名加i赋值给该指针。
int data[]={11,21,23};
int *p;
// 数组data第2个元素地址赋值给p
p = data+1;
// 或者
p = &data[1];
上面的代码将data数组的第2个元素的内存地址赋值给指针变量p。当指针变量p指向了数组元素或数组首地址后,就可以通过指针变量的自增或自减来访问数组的各个元素。
例3:遍历数组的元素
程序清单 sample.c
#include<stdio.h>
void main()
{
// 声明数组data
int data[]={11,21,23,8,9,100};
// 声明执行int类型的指针变量
int *p,i;
// 数组首地址赋值给data
p = data;
// 输出数组全部元素
for(i=0;i<6;i++)
{
printf(第%d个数组元素=%d,内存地址=%d\n",i+1,*p,p);
p++;
}
}
程序输出结果如下图所示:

例3演示了如何使用指针遍历数组元素。指针变量p指向数组元素data的首地址,在第一次fou循环时,p存储的值为16250656,存储在该地址的值为11,然后p做自增操作,p存储的地址为16250660,该地址为data数组第2个元素的内存地址,存储在该地址的值为21,此过程持续到for循环结束。
使用指针访问数组元素时,需要注意指针指向的是数组元素的内存地址,当把数组名称赋值给指针变量时,实际是把数组第1个元素的内存地址赋值给了指针变量,然后通过指针的加减算术运算让指针指向数组不同元素的内存地址。在进行指针加减算术运算时,要特别注意指针不能越界,不能让指针指向数组元素以外的内存地址,否则程序会抛出异常。