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


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

    例如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.如何理解数组不等价于指针》中的 “①内存分配: 数组是在栈上分配内存,而指针可以指向栈或堆上的内存。”会不会很难理解,我看到的时候就会在想,什么时候指向栈,什么时候指向堆。

    我们先来理解一下栈和堆

    栈:

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

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

    堆:

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

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

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

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

    1. int a = 10;
    2. int *p = &a;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • 相关阅读:
    软件课程设计--仓库管理系统
    被忽视的数据中心非业务网络规划
    20230903-闹钟
    ES全文检索支持繁简和IK分词检索
    zkPoT:基于机器学习模型训练的ZKP
    初识Docker
    「技术」智能温室可升降吊挂式草莓立体无土栽培技术分析
    JAVA编程思想N刷
    [附源码]Java计算机毕业设计SSM房车营地在线管理系统
    <七>理解多态
  • 原文地址:https://blog.csdn.net/weixin_41653613/article/details/133102654