数组如何赋值给指针变量?

99ANYc3cd6
预计阅读时长 15 分钟
位置: 首页 C语言 正文

这是一个非常核心且重要的概念,理解它能帮助你更好地掌握C语言的内存操作。

c语言 数组赋值给指针变量
(图片来源网络,侵删)

核心要点

请记住一个关键点:在C语言中,数组名 arr 会“衰变”为其首元素的地址。

这意味着,当你把一个数组名赋值给一个指针时,你实际上是把数组第一个元素的内存地址赋给了这个指针。


一维数组与指针

这是最常见的情况,我们来看一个例子。

声明和初始化

int numbers[] = {10, 20, 30, 40, 50};
int *ptr; // 声明一个整型指针
// 将数组赋值给指针
// 这里的 numbers 会被解释为 &numbers[0]
ptr = numbers; 

内存中的样子:

c语言 数组赋值给指针变量
(图片来源网络,侵删)
      numbers (数组名)
        |
        v
+-------+-------+-------+-------+-------+
| 10    | 20    | 30    | 40    | 50    |
+-------+-------+-------+-------+-------+
  ^       ^       ^       ^       ^
&numbers[0] &numbers[1] &numbers[2] &numbers[3] &numbers[4]
  |
  ptr (指针变量)

如何通过指针访问数组元素

一旦指针指向了数组,你就可以使用两种主要的方式来访问数组元素:

a) 使用指针算术

// 获取第一个元素
int first_value = *ptr; // *ptr 解引用指针,获取其指向的值 (10)
// 移动指针到下一个元素
ptr++; // 指针现在指向 numbers[1]
// 获取第二个元素
int second_value = *ptr; // 20
// 你也可以直接计算偏移量
int third_value = *(ptr + 1); // 指针不变,但通过 +1 计算出 numbers[2] 的地址并解引用 (30)

b) 使用数组下标(非常强大!)

C语言有一个非常方便的特性:如果指针指向一个数组,你可以对指针使用数组下标 []

c语言 数组赋值给指针变量
(图片来源网络,侵删)
// 让指针重新指向数组开头
ptr = numbers;
// 使用下标访问
int first_value = ptr[0]; // 等同于 *(ptr + 0),即 10
int second_value = ptr[1]; // 等同于 *(ptr + 1),即 20
int third_value = ptr[2]; // 等同于 *(ptr + 2),即 30

这看起来就像是 ptr 本身就是一个数组。ptr[i] 在编译时总是被解释为 *(ptr + i)


多维数组与指针

多维数组的情况稍微复杂一些,因为它涉及到“数组的数组”。

二维数组

int matrix[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
};

*a) 赋值给指向整型的指针 (`int `)**

这是不推荐的,并且容易出错。

int *ptr;
// ptr = matrix; // 错误!编译器会报错。
// 因为 matrix 的类型是 "int [3][4]",它会衰变为指向其第一个元素的地址。
// 而它的第一个元素是 "int [4]" (一个包含4个整数的数组)。
// matrix 的类型是 "int (*)[4]" (一个指向包含4个整数的数组的指针)。
// 不能将 int (*)[4] 赋值给 int *。

*b) 赋值给指向数组的指针 (`int ()[4]`)**

这是正确且推荐的方式。

// 声明一个指向 "包含4个整数的数组" 的指针
int (*ptr_to_row)[4]; 
// 将二维数组名赋值给这个指针
// matrix 衰变为指向第一行 (一个 int [4] 数组) 的指针
ptr_to_row = matrix; 

内存中的样子:

        matrix (数组名)
          |
          v
+---------------------------------------+
|  (第一行) | (第二行) | (第三行)        |
| +---+---+---+---+ | +---+---+---+---+ | +---+---+---+---+ |
| | 1 | 2 | 3 | 4 | | | 5 | 6 | 7 | 8 | | | 9 |10 |11 |12 | |
| +---+---+---+---+ | +---+---+---+---+ | +---+---+---+---+ |
+---------------------------------------+
   ^
   |
ptr_to_row

如何通过指针访问元素:

// 获取第一行的第一个元素
int value1 = (*ptr_to_row)[0]; // 等同于 matrix[0][0],即 1
// 移动指针到下一行
ptr_to_row++; // 指针现在指向 matrix[1]
// 获取第二行的第二个元素
int value2 = (*ptr_to_row)[1]; // 等同于 matrix[1][1],即 6
// 同样,也可以使用指针算术
int value3 = *(*(ptr_to_row + 1) + 2); // ptr_to_row + 1 指向第三行, *(...) 获取第三行数组, +2 指向第三行的第三个元素, * 解引用得到 11

字符数组与指针

字符数组(字符串)是数组赋值给指针最经典的例子。

char greeting[] = "Hello, World!";
char *str_ptr; // 声明一个字符指针
// 将字符数组赋值给指针
str_ptr = greeting;

内存中的样子:

      greeting (数组名)
        |
        v
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
| 'H' | 'e' | 'l' | 'l' | 'o' | ',' | ' ' | 'W' | 'o' | 'r' | 'l' | 'd' | '!' |
+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+
  ^
  |
str_ptr

如何通过指针访问和操作字符串:

// 打印整个字符串
printf("%s\n", str_ptr); // Hello, World!
// 打印单个字符
printf("First char: %c\n", *str_ptr); // H
// 移动指针
str_ptr++; // 指向 'e'
printf("Second char: %c\n", *str_ptr); // e
// 你也可以用下标
printf("Third char: %c\n", str_ptr[1]); // l (因为 str_ptr 指向 'e', str_ptr[1] 是 'l')

重要区别:数组名 vs. 指针变量

虽然数组名可以像指针一样使用,但它们有本质区别:

特性 数组名 (arr) 指针变量 (int *p)
本质 一个常量,代表数组首元素的地址。 一个变量,用于存储内存地址。
赋值 不能被赋值。arr = p; 是错误的。 可以被赋值。p = arr;p = another_ptr; 都是正确的。
sizeof sizeof(arr) 返回整个数组的大小(int arr[5]sizeof(arr)5 * sizeof(int))。 sizeof(p) 返回指针本身的大小(在64位系统上是8字节,在32位系统上是4字节),无论它指向哪里。
&运算符 &arr 得到的是整个数组的地址,其类型与 arr 的类型略有不同(int (*)[5])。 &p 得到的是指针变量本身的地址。

  1. 基本赋值:将数组名赋给指针,实际上是将其首元素的地址赋给了指针。int *p = arr;
  2. 一维数组:指针可以通过指针算术(p++, *(p+i))或下标(p[i])来访问数组元素,两者是等价的。
  3. 多维数组:必须使用与数组维度匹配的指针。int matrix[M][N] 应该赋给 int (*p)[N]
  4. 字符数组:这是最常见的用法,指针可以方便地遍历和操作字符串。
  5. 核心区别:数组名是地址常量,指针变量是地址变量。sizeof 和赋值行为是它们最显著的区别。

理解了“数组名衰变为首元素地址”这一核心规则,你就能轻松掌握数组与指针的关系。

-- 展开阅读全文 --
头像
Linux下C语言编译器如何选择与使用?
« 上一篇 今天
dede图片模板如何适配手机端显示?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]