数组和指针本质不同,但可互相转换;数组是固定大小的连续内存,不能修改地址,而指针是变量,可随时改变指向。1. 数组名是常量地址,不可赋值;2. 指针保存内存地址,可修改其指向;3. 数组在多数表达式中会退化为指针;4. 传数组给函数时形参自动转为指针;5. 指针无法还原数组长度,需手动记录信息;6. 字符串字面量用指针指向只读内存;7. 注意数组指针与指针数组的区别。理解这些异同有助于写出更清晰安全的c代码。
在c语言中,数组和指针看起来很像,但它们其实是两个不同的概念。简单来说,数组是存储一组相同类型数据的连续内存空间,而指针是一个变量,它保存的是某个内存地址。虽然它们本质不同,但在很多使用场景下可以互相转换和操作。
数组和指针的本质区别
数组是一块固定大小的内存区域,编译器会记住它的长度和起始位置。例如:
int arr[5] = {1, 2, 3, 4, 5};
这个arr不是变量,而是常量地址,不能被赋值,比如你不能写arr = NULL;。
立即学习“C语言免费学习笔记(深入)”;
而指针是一个变量,它保存的是一个地址:
int *p = arr;
这时候p可以随意改变指向,比如你可以写p++;或者p = NULL;,这不会影响原来的数组。
所以总结一下:
- 数组名不是一个变量,不能修改
- 指针是一个变量,可以随时改变它的值(也就是指向)
数组怎么转成指针?
数组在大多数表达式中都会“退化”成指针,也就是说,除了作为sizeof或&运算的操作数外,数组名会自动变成指向其第一个元素的指针。
比如:
int arr[5]; int *p = arr; // 这里arr就退化成了int*
也可以用取地址的方式获取指针:
int *p = &arr[0]; // 和上面等价
还有一种情况是把数组传给函数时,形参会被编译器自动处理为指针:
void func(int arr[]) { // 实际上arr会被当作int* }
指针能还原成数组吗?
严格来说,指针本身并不知道它指向的内存有多大,所以在运行时无法从指针直接还原出数组的长度。除非你自己记录了相关信息。
举个例子:
int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; // 你只能通过p访问元素,但不知道它后面有几个元素 for (int i = 0; i < 5; i++) { printf("%dn", p[i]); }
这里必须你知道数组长度是5,否则无法安全地遍历整个数组。
所以结论是:
- 从指针到数组的转换更多是逻辑上的理解,而不是语法层面的转换
- 需要你自己保留数组长度信息才能安全使用指针访问数组内容
使用时容易混淆的地方
有时候你会看到类似这样的写法:
char *str = "hello";
这是字符串字面量,虽然用的是指针,但它指向的是只读内存中的字符数组。这种情况下,你不应该试图修改内容,比如str[0] = ‘H’;会导致未定义行为。
还有数组指针和指针数组的区别也容易搞混:
int (*p1)[5]; // p1是指向有5个int的数组的指针 int *p2[5]; // p2是5个指向int的指针组成的数组
这两个写法差别挺大,注意括号的位置。
基本上就这些。数组和指针关系密切,但又不完全一样。理解它们之间的异同和转换方式,有助于写出更清晰、安全的C代码。