【C语言】数组和指针一样吗?

目录

为什么可以像指针一样使用数组?

为什么可以像数组一样使用指针?

数组和指针的区别总结


对于一些初学的小伙伴来说,最大的误区就是认为指针和数组是一样的。这是很严重的一个问题,数组本身是来顺序存储一系列同类型数据的,而指针是指向内存地址的,虽然两者在某些地方可以相互替代使用,但这并不代表两者相同。

为什么可以像指针一样使用数组?

举一个非常常见的例子,大家可能在定义函数的时候会写到如下:

cpp 复制代码
void func(int arr[]); 

这里写入的参数是一个 int 类型的数据,但是我们在实际使用的时候可能会既可以传入一个数组,又可以传入一个指针,如下:

cpp 复制代码
int main() {
    // 情况1:传递数组
    int my_array[3] = {1, 2, 3};
    func(my_array); 
    
    // 情况2:直接传递指针
    int *ptr = my_array;
    func(ptr); 
    
    return 0;
}

为什么会这样呢?难道数组和指针的类型相同,是同一个东西吗?

并不是这样的, 这是因为数组在表达式中使用的时候,编译器会有一个隐式的类型转换 ,将他转换成一个指针常量 ,这个指针常量指向的就是数组首元素的地址。要注意,转换的是一个指针常量,我们是不能去修改指针的指针指向的(如a、b都是一个数组,是不可以让 a = b 的)。

但是又两种特殊情况,数组名是不能用指针常量来代替的。当对一个数组名进行 sizeof 或 & 操作的时候,并不会转换成一个指针常量。sizeof() 返回的是一个数组的长度,而不是数组的指针的长度;& 取数组名返回的是一个指向数组的指针,而不是一个指向指针常量的指针。

下面举一个例子:

cpp 复制代码
int a[10];
int b[10];
int *c;

c = &a[0];

表达式 &a[0] 是一个指向数组首元素的一个指针,但那正好是数组本身的值,所以使用 c = a 和上面那条语句执行的任务是完全一样的。

b = a 和 c = a 这两个操作都是非法的。都是去尝试修改指针常量的指向了。

为什么可以像数组一样使用指针?

下面举一个例子,定义一个指针,我们去用数组的方式对其进行访问。

cpp 复制代码
int main()
{
    char *p = "abcdefgh";
    char arr[] = "abcdefgh";
    char a = p[5];
    char b = arr[5];
    printf("a = %c,b = %c",a,b);
    return 0;
}
/* 打印:a = f,b = f */

在上述两种情况下,我们都可以通过下标5拿到 'f',但是两者的途径完全不一样。

使用指针 p[5] 去引用元素的时候,编译器实际会进行以下操作:

  1. 取得符号表中 p 的地址,提取存储于此处的指针。
  2. 把下标所表示的偏移量与指针的值相加,产生一个地址。
  3. 访问上面这个地址,取得字符。

也就是说 p[5] 本质上就是进行了 *(p+5) 这样一个操作,也就是向后便宜了5个 char 的地址,去拿到了 'f' 。

我们使用数组 arr[5] 去引用元素的时候,我们上面已经说过了,数组在表达式中会转化成一个指针常量,所以同样是进行了 *(arr + 5) 这样一个操作。

虽然二者最终结果是一样的,但是两者的最终获取偏移量的一个过程并不相同。

数组和指针的区别总结

上述只是帮助大家分清了为什么有时候数组和指针可以相互替换。下面总结一下本质上的区别:

特性 数组 指针
类型 连续内存块的别名 存储地址的变量
存储内容 直接存储数据元素 存储其他变量的地址
内存分配 编译期静态分配(栈/全局区) 运行时动态分配(可指向堆/栈/全局区)
大小(sizeof) 返回整个数组的字节大小(如char[9]→9) 返回指针本身的字节大小(4或8字节)
地址性质 常量 变量

指针和数组都可以在定义中用字符串常量进行初始化,虽然看着一样,但底层的逻辑并不相同。

cpp 复制代码
char *p = "abcdefgh";

定义指针的时候,编译器并不为指针所指向的对象分配空间,他只是分配指针本身的空间,除非我们在定义的时候就赋值给指针一个字符串常量进行初始化。初始化的时候,字符串常量会被设置为只读。如果通过指针修改这个字符串,就会造成未定义的行为。在有些编译器中,字符串常量存在于只允许读取的数据段中,防止被修改。

cpp 复制代码
char [] = "abcdefg";

但是使用字符串常量初始化的数组是可以通过下标去修改字符串的。

相关推荐
代码游侠3 小时前
日历的各种C语言实现方法
c语言·开发语言·学习·算法
玩转C语言和数据结构13 小时前
C语言编程入门攻略(最新学习路线,适合新手小白)
c语言·c语言入门·c语言下载·c语言知识点总结·c语言自学·c语言教程·c语言怎么学
Bona Sun14 小时前
单片机手搓掌上游戏机(十四)—pico运行fc模拟器之电路连接
c语言·c++·单片机·游戏机
无限进步_15 小时前
C语言数组元素删除算法详解:从基础实现到性能优化
c语言·开发语言·windows·git·算法·github·visual studio
松涛和鸣15 小时前
16、C 语言高级指针与结构体
linux·c语言·开发语言·数据结构·git·算法
口袋物联16 小时前
设计模式之适配器模式在 C 语言中的应用(含 Linux 内核实例)
c语言·设计模式·适配器模式
!停17 小时前
函数递归的应用
c语言
feng_you_ying_li19 小时前
Detailed explanation of being processing
c语言
玖剹19 小时前
递归练习题(四)
c语言·数据结构·c++·算法·leetcode·深度优先·深度优先遍历
序属秋秋秋1 天前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程