char s[]和char *s的区别,数组和指针的,堆和栈指针的一些思考

2023-09-20 21:59:14

最近在学习的时候看到一个概念,数组不等价于指针,很合理但又很难理解。

例如char s[]和char *s有什么区别,前者是数组,后者是指针,个人学习成果如下:

1.char s[]和char *s的区别

char s[]:

①数组,char s[]定义了一个字符数组

②内存分配: 内存在栈上分配。
③大小固定: 一旦定义,数组的大小就不能改变。
④初始化: 可以用字符串直接初始化。

char s[] = "hello";

⑤可变性: 可以修改数组中的元素。

s[0] = 'H';  // 合法

char *s
①指针: char *s 定义了一个指向字符的指针。
②内存分配: 可以指向栈上或堆上的内存。
③大小灵活: 指针指向的内存块大小可以动态改变(如果是堆内存)。
④初始化: 可以用字符串字面量初始化,但需注意字符串字面量自身是不可修改的。

char *s = "hello";

⑤可变性: 如果指针指向的是字符串字面量,则不能修改内容。

s[0] = 'H';  // 非法,如果 s 指向的是字符串字面量

2.如何理解数组不等价于指针

①内存分配: 数组是在栈上分配内存,而指针可以指向栈或堆上的内存。
②大小信息: 数组名包含了数组大小的信息(通过 sizeof 可以获取),而单纯的指针没有。
③可修改性: 如果指针指向的是字符串字面量,那么这部分内存是不可修改的,而数组是可修改的。
④运算限制: 指针可以进行递增和递减操作来遍历内存,而数组名实际上是一个常量指针,不能进行递增和递减操作。
⑤函数传参: 当数组作为函数参数时,它会退化为指针,但在定义和初始化时,它们是不同的。
⑥类型信息: 从类型系统的角度看,char s[] 和 char *s 是不同的类型。
由于以上差异,数组和指针在 C/C++ 中是不等价的,尽管在某些特定情况(例如作为函数参数)下,数组名会退化为指针。(一般多维数组作为函数形参传递的时候,就会退化为指针)

3.指针可以指向栈或堆上的内存

不知道大家看到《2.如何理解数组不等价于指针》中的 “①内存分配: 数组是在栈上分配内存,而指针可以指向栈或堆上的内存。”会不会很难理解,我看到的时候就会在想,什么时候指向栈,什么时候指向堆。

我们先来理解一下栈和堆

栈:

①自动分配/释放:函数内的局部变量通常在栈上分配内存,当函数调用结束后,这部分内存会自动释放。
②快速访问:访问栈上的内存一般比访问堆上的内存要快。
③有限的大小:栈的大小通常是有限的,超出大小会导致栈溢出。
例子:

void function() {
    int a = 10;  // 在栈上分配
    char *p = &a;  // p 是指针,指向栈上的内存地址
}

堆:

①手动分配/释放:通过malloc()、calloc()、new等函数在堆上分配内存,需要手动释放。
②访问速度较慢:一般来说,访问堆上的内存要比访问栈上的内存慢。
③动态大小:堆的大小可以动态地增长或缩小。
例子:

void function() {
    char *p = (char *)malloc(10);  // p 是指针,指向堆上的内存地址
    // ... 使用 p ...
    free(p);  // 释放 p 指向的堆内存
}

这个时候就好理解了,指针如何指栈和指向堆的内存:

指向栈上的内存:当指针指向一个局部变量时,它指向栈上的内存。

int a = 10;
int *p = &a;

指向堆上的内存:当通过malloc、calloc或new分配内存后,返回的指针指向堆上的内存。

int *p = (int *)malloc(sizeof(int) * 10);

总的来说:指针是内存地址的抽象,可以指向栈上或堆上的内存,具体取决于指针是如何初始化或赋值的。

4.指针本身在堆上还是栈上

3.指针可以指向栈或堆上的内存》知道了指针指向是堆还是栈,那指针本身是在堆上还是栈上?

指针变量本身的存储位置取决于它是如何声明和分配的。

①局部指针变量:如果指针变量是在函数内部定义的,那么它存储在栈上。

void function() {
    int *p;  // p 是局部变量,存储在栈上
}

②全局指针变量:如果指针变量是全局变量,那么它通常存储在全局/静态存储区。

int *p;  // p 是全局变量,存储在全局/静态存储区

③动态分配的指针变量:如果指针变量本身是通过动态内存分配函数(如 `malloc` 或 `new`)获得的,那么这个指针变量(或者说,该指针变量指向的内存块)存储在堆上。

int **pp = (int **)malloc(sizeof(int *));  // pp 是局部变量,但它指向的内存块在堆上

④成员指针变量:如果指针是某个对象的成员变量,那么它的存储位置取决于对象本身的存储位置。如果对象在栈上,指针也在栈上;如果对象在堆上,指针也在堆上。

struct MyStruct {
    int *p;  // p 的存储位置取决于 MyStruct 实例的存储位置
};

⑤函数参数:作为函数参数传入的指针通常也是存储在栈上的。

void function(int *p) {  // p 作为函数参数,存储在栈上
    // ...
}

总体来说,指针变量本身就像其他任何变量一样,它的存储位置取决于它是如何被声明和分配的。指针变量存储的是内存地址,这个地址可以指向栈上、堆上或全局/静态存储区的内存。

更多推荐

go学习之函数知识

函数文章目录函数1.函数入门(1)为什么需要函数?(2)什么是函数:2.包3.函数的调用机制通俗理解调用过程:return语句递归调用4.函数注意事项和细节讨论5.init函数6.匿名函数7.闭包8.defer9.函数参数的传递方式10.字符串中常用的函数11.时间和日期相关的函数12.内置函数13.go的错误处理机制

车载多通道语音识别挑战赛(ICMC-ASR)丨ICASSP2024

由希尔贝壳、理想汽车、西工大音频语音与语言处理研究组、新加坡南洋理工大学、天津大学、WeNet开源社区、微软、中国信通院等单位发起的“车载多通道语音识别挑战赛”(ICMC-ASR)将作为IEEE声学、语音与信号处理国际会议(ICASSP2024)的旗舰赛事,正式启动。报名参加此次赛事,您将获得:业界首个新能源车智能座舱

SpringMvc第六战-【SpringMvcJSON返回&异常处理机制】

前言:小编讲述了:JSR303的概念,应用场景和在具体实例的使用;和拦截器的应用今天小编来讲述的为cJSON返回&异常处理机制,json返回就不用多说,毕竟大部分数据都是通过Json来传递数据的,异常返回的作用小编也就不多说了反正很重要!目录一.SpringMVC之JSON数据返回1.在pom.xml导入Json依赖2

【性能优化下】组织结构同步优化二,全量同步/增量同步,断点续传实现方式

看到这一篇文章的xdm,应该对组织结构同步有一些想法了吧,如果没有,可以看前面两篇文章,可以通过如下地址查看一下:【性能优化上】第三方组织结构同步优化一,你get到了吗?坑爹,线上同步近3w个用户导致链路阻塞引入发的线上问题,你经历过吗?这类文章,主要是期望能给xdm带来不一样的思考,如有表述不当的地方,还请不吝赐教,

Vue的模板语法(下)

一.事件处理事件修饰符Vue通过由点(.)表示的指令后缀来调用修饰符,.stop,.prevent,.capture,.self,.once.stop:阻止事件冒泡。当一个元素触发了事件,并且该元素包含嵌套的父元素时,使用.stop修饰符可以防止事件被传递到祖先元素。.prevent:阻止默认事件。当一个元素上触发了某

【Linux】共享内存

共享内存系统接口创建共享内存区域shmget关联共享区域shmat去除共享关联shmdt删除共享内存区域共享内存特性共享内存当多个进程需要在其间共享数据时,共享内存提供了一种高效的方式。它允许多个进程将同一块内存映射到它们的地址空间中,使得它们可以直接读写该内存,而不需要通过消息传递或其他形式的通信。系统接口在Linu

Java笔记:JVM参数调优

1.堆大小设置JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在WindowsServer2003系统,3.5G物理内存,JDK5.0下测试,最大可设置为147

学内核之二十一:系统调用栈结构分析

目录一构建分析环境二栈的位置三栈开头8字节四寄存器环境五R4和R5六如何确定系统调用的具体函数一构建分析环境为了分析方便,做了如下测试环境:内核实现一个简单的创建字符设备的驱动应用层实现一个c程序,操作为打开内核创建的字符设备文件内核在处理open设备文件的接口中,将指针设置为空,并在该空指针上赋值。这样,就触发内核的

JVM内存模型及JAVA程序运行原理

目录平台JVM简介内存结构方法区堆一个对象的内存分配流程栈局部变量表操作栈动态连接方法返回地址程序计数器Metaspace元空间本地方法栈直接内存CodeCacheJAVA程序在JVM内是如何执行的平台Java是一种可以跨平台的编程语言。Java可以跨平台得益于JVM(java虚拟机)。我们把CPU处理器与操作系统的整

springboot大学生体质测试管理系统springboot009

大家好✌!我是CZ淡陌。一名专注以理论为基础实战为主的技术博主,将再这里为大家分享优质的实战项目,本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目,希望你能有所收获,少走一些弯路,向着优秀程序员前行!🍅更多优质项目👇🏻👇🏻可点击下方获取🍅文章底部或评论区获取🍅Java项目精品实

flask要点与坑

简介Flask是一个用Python编写的Web应用程序框架,该框架简单易用、模块化、灵活性高。该笔记主要记录Flask的关键要点和容易踩坑的地方Flask日志配置Flask中的自带logger模块(也是python自带的模块),通过简单配置可以实现将日志记录到日志文件中(记录关键日志有助于以后分析问题);更详细的log

热文推荐