zoukankan      html  css  js  c++  java
  • C/C++ 内存与指针

    内存与指针杂谈

    1、指针

    1、数组指针
    int(*ptr)[n]
    

    ()的优先级高,(*ptr)表示ptr是一个指针,指向一个int类型的一维数组,这个数组的长度为n,也可以说ptr的步长就是n。也就是说执行ptr+1时,ptr要跨过n个int的长度。

    2、指针数组
    int* p[n]
    

    []的优先级高,p和[]先结合表示一个数组,int*表示数组中元素的数据类型为int*。

    3、复杂一点的指针
    int* (*ptr)[n]
    

    ptr是一个指向数组的指针,数组中的每个元素都是指向int的指针。

    4、指针运算

    指针运算:一个指针ptrold加(减)一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。ptrnew的值将比ptrold的值加或减了n乘sizeof(ptrold所指向的类型)个字节。

    5、指针变量和指针所指向的内存空间是两个不同的概念
    6、指针做函数参数,是指针存在的最大意义

    *p间接赋值成立的3个条件:

    1. 2个变量(通常一个实参,一个形参)。
    2. 建立关系,实参取地址赋给形参。
    3. *p形参去间接修改实参的值。

    引申:函数调用时,用n级指针(形参)修改n-1级指针(实参)的值。

    7、一个指针的内容
    1. 指针的类型。

    2. 指针所指向的类型。

    3. 指针的值或者叫指针所指向的内存区或地址

      • 指针的值都是指针本身存储的数值,这个数值将被编译器当做一个地址,而不是一般的数值,在32位程序里所有类型的指针的值都是一个32位整数,因为32位程序里内存地址都是32位长。
      • 指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。
    4. 指针本身所占据的内存区。在32位平台里,指针本身占据了4个字节的长度。

    2、内存

    1、内存四区:
    1. 栈区(stack):由编译器自动分配释放,存放函数参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

    2. 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两个概念。分配方式倒是类似于链表。

    3. 数据区:主要包括静态全局区和常量区,如果站在汇编角度细分的话还可以有很多小的区。

      • 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。
      • 常量区:常量字符串就是放在这里。程序结束后由系统释放。
    4. 代码区:存在函数体的二进制代码。

    2、变量

    变量的本质:一段连续内存空间的别名。

    数据类型的本质:固定大小内存空间的别名。

    1、修改变量的方法
    1. 直接修改,int a = 10;
    2. 间接修改,内存有地址编号,拿到地址编号也可以修改内存,外挂的原理就是通过变量内存地址来修改变量值:&a = 1245024; ((int)(1245024)) = 10。
    3. C++中引用。
    2、声明变量的意义
    1. 建立变量符号表。
    2. 变量的数据类型指示了系统分配多少内存空间。
    3. 变量的数据类型指示了系统如何解释内存空间中的值。
    4. 变量的数据类型确定了变量的取值范围。
    5. 不同的数据类型有不同的操作。
    3、函数内存模型
    • 主调函数可以把堆区、栈区、全局数据内存地址传递给被掉函数。
    • 被掉函数只能返回堆区、全局数据。
    4、避免产生野指针:
    • 定义指针时,把指针变量赋值为NULL。
    • 释放内存时,先判断指针变量是否为NULL。
    • 释放完内存后,把指针变量重新赋值成NULL

    3、void与void*

    1. 如果函数没有返回值,那么应声明为void类型。
    2. 如果函数无参数,那么应声明其参数为void。
    3. 小心使用void指针类型,ANSI标准,不能对void指针进行算法操作。
    4. 如果函数的参数可以是任何无类型指针,那么应声明其参数为void*。

    ​ 例:典型的如内存操作函数memcpy,memset的函数原型:

    void * memcpy(void *dest, const void *src, size_t len);
    void * memset(void *buffer, int c, size_t num);
    

    ​ 这体现了内存操作函数的意思,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。

    1. void不能代表一个真实的变量。
  • 相关阅读:
    SQL server 统计数据库表数量和列出所有表名称
    mybatis 模糊查询 like的三种方式
    jquery 实现按回车键登录功能的写法
    js 各种事件 如:点击事件、失去焦点、键盘事件等
    ssm框架中从controller传值给jsp的方式
    [GDOI2019]小说
    洛谷5113
    2020.9.26模拟总结
    [IOI2015]分组
    9.19 总结
  • 原文地址:https://www.cnblogs.com/chengjundu/p/11232457.html
Copyright © 2011-2022 走看看