内存空间C语言

内存空间

如何访问一个空间

有名访问

通过定义变量,以变量名为名称进行访问。

int a; char b; struct buffer data;

变量定义在内存上,内存资源为了能让CPU访问的到,必须编址

通过名字访问时,对CPU来说,变量名只是地址的一个代号而已

无名访问

空间的本质:用一个地址进行编址,使CPU可以访问

如何保存地址的值?

数字概念:足够存储地址的大小

物理含义:和普通数字有什么区别?

C语言如何用地址来描述一个空间

一个地址描述空间,这个地址要满足的要素:

  1. 具备存储地址大小的容器,如32位系统和64位系统
  2. 地址从1个单位到下一个单位,该如何访问
    • 为什么要提到单位这个概念?
      • 软件最底层的单位大小是:1B
      • C语言定义了不同的单位大小:int , short, char, struct xx

C语言编译器如何识别地址的二要素?

int * p1 这个占据的地址有多大其实是不确定的,如果是32位系统就是4个字节,如果是64位系统就是8个字节;

(在面试题中要小心问你这种题,一定要看清楚是32位还是64位系统,如果不告诉你那么就是不确定)

而对于p1地址如何访问呢?前面的int 不是修饰p1的大小,而是修饰p1从这个空间到另外一个空间是怎么访问的,就是一个int一个int(四个字节)

char *p2 练习

代码验证-地址二元素

空间大小和你目标系统的位数有关.

64位系统下

int main ()
{
    int *p1;
    char *b2;
    printf("%d,%d", sizeof(p1), sizeof(b2));
    return 0;
}

image-20221122000658680

32位系统下

image-20221122000933949

验证访问方式

#include<stdio.h>
int main ()
{
    int *p1= (int *)100;
    char *b2;(char *)100;
    printf("%d,%d\n", sizeof(p1), sizeof(b2));
    printf("%p,%p\n", p1, b2);
    printf("%p,%p\n", p1+1, b2+1);
    return 0;
}	

image-20221122001545327

自己该如何判断变量属性

定位变量名 向右看 再左看

  • int a1;
  • int a2[5]; 定位到a2向右看到数组,a2升级为数组名,要回答两个问题1. 有多少个数组2.每一个元素是怎么存的。5个元素,5个int空间
  • int * a3; a3升级为地址,这把钥匙四个字节的操作
  • int *a4[5];a4向右看是一个5个元素的数组,右边没有了再向左看是 *那么* 表示的是a4里5个元素每个都存了一把钥匙,再向左int,表示访问方式一个int一个int的访问———>即我有五把钥匙,每个钥匙都是4个字节4个字节访问的
  • int (*a5)[5]a5向右看是括号,所以向左是* 这时候a5升级为一把钥匙,*a5向右看是[5]是数组相当于是一串一串的访问,再看int即5个int,5个int的访问
  • int a6[3][5]a6和a5类似是都是五个int五个int的访问,只是a6明确的告诉我们他有三串
  • int*a7[3][5]a7向右看升级为数组,二维数组15个元素,每个元素都存了一把钥匙,访问方式是一个int一个int访问
  • int*a8[3][4]a8是一把钥匙,开门的方式是三行四列的开。

代码验证-多维空间存储

/*
 * 设计一个指针,可以存储二维空间,或三维空间的首地址
 * */
#include<stdio.h>
int main()
{
    int a[3][4];
    int *k1;
    k1=a;
    printf("a = %p , a+1 = %p\n",a,a+1);
    printf("k1 = %p , k1+1 = %p\n",k1,k1+1);
    return 0;
}

image-20221122094551679

证明,a是4个int访问,k1是1个int访问

改进

int a[3][4];
    int (*k1)[4];
    k1=a;
    printf("a = %p , a+1 = %p\n",a,a+1);
    printf("k1 = %p , k1+1 = %p\n",k1,k1+1);

image-20221122094847984

把k1升级为一把钥匙让他以4个int访问就可以和上面的a相同

三维

  int a[5][3][4];
    int (*k1)[3][4];

a是5个面,每个面三行四列的存储,而k1是一把钥匙,他不管你有几个面,他关注的是每个面的情况,

但是以要定义一个int *p1让p1=a也不是不行,就比如你有五十平的房子,你非要用十平米十平米来度量房子也不是不行。(但是c++不行)//C语言更偏向于底层,C++更偏向于业务。

函数地址的保存

定义了一个函数,那么函数也是一个地址

  • 函数是空间

    • 函数名就是这个空间地址的常量值的代号
  • 如何用一个变量保存这个代号吶?

    • 保存这个代号,首先必须是一个地址

    • 案例:printf的换名

      • myshow=printf这个思路
      • myshow("hello world!\n");
      • 关键是怎么让myshow=printf呢?
      • 只要明白printf访问内存的方式告诉钥匙,就可以了
      • 假设printf长成int xxx (void)那么你的myshow要长成int (*myshow)(void)首先你的myshow应该是一把钥匙,这把钥匙读内存的方式应该和替换的一样。xxx叫做函数的名字常量,myshow叫做函数地址的变量
    • 代码——模拟计划执行表的案例

      • 一周7天,每天做不同的事情

        • 方法一 swich /case (缺点:1.代码长不利于维护2.代码过于死板,必须要该case里面的内容才可以,不够灵活。)

          #include<stdio.h>
          void do_music(){
              printf("play music\n");
          }
          void do_game(){
              printf("play game\n");
          }
          void do_book(){
              printf("read book\n");
          }
          int main()
          {
              int day;
              printf("input day");
              scanf("%d",&day);
              switch (day){
                  case 1:
                      do_music();
                      break;
                  case 2:
                      do_game();
                      break;
                  case 3:
                      do_book();
                      break;
              }
              return 0;
          }
          
        • 方法二 我们可以把无序的东西编程有序的东西,可以考虑用一个数组来实现

          先假设定义三个箱子int data[3]

          如果我们想访问第二天那就是data[1],我们拿到data[1]过后如果他是把钥匙而且是函数我们可以直接data[1]()进行访问,那么就完成第二天要做的事情。

          那么第二天里面装什么呢?

          我们可以对data[1]赋值,因为data[1]是可变的,我们可以吧data[1]做一个借口让用户去执行

          #include<stdio.h>
          void do_music(){
              printf("play music\n");
          }
          void do_game(){
              printf("play game\n");
          }
          void do_book(){
              printf("read book\n");
          }
          int main ()
          {
              int i;
              //定义一个数组空间,保存了钥匙,每把钥匙都是函数行为
              void (*events[3])(void);
              //设置每天做到事情
              events[0]=do_game;//赋值函数的首地址
              events[1]=do_book;
              events[2]=do_music;
              //循环执行每天的事情
              for(i=0;i<3;i++)
              {
                  events[i]();
              }
          

空间属性的概述

  • 引例: 空间可以随意访问吗?
#include<stdio.h>
int main()
{
    1. char *s ="Aallo";
    2. char s[]="Aallo";
    s[0]='H';
    printf("%s\n",s);
}

在执行代码1.时,直接终端直接退出了不显示任何东西

在执行代码2.时,显示Hello

    • 为了便于管理,空间进行分段
内存结构
			         段          		属性
4G - 3G            OS kernel		不可读不可写,一旦操作被操作系统终止

--向下--(从大到小)----------------------------------------------------
                    stack段	        所有的函数局部变量都在这里  可读可写     存临时区域
		                             每个子函数都拥有一个独立的栈空间
		                             每个子函数的栈空间有大小限制,一旦超过这个限制,栈溢出
	                堆段			          C语言编译器不维护,由程序员自己来维护
	                                       空间没有限制           可读可写
	                                       通过malloc申请空间
					                       通过free释放空间,释放了空间,该空间仍然可以访问
					                       如果不释放,导致系统内存泄露 变慢
					数据段		                   不依赖于函数的调用而诞生
					                             生命周期是从程序运行开始,到程序运行结束
					                             全局变量、静态变量
                     只读数据段	                  双引号 常量数字
		              代码段		                     只读
		 ---------------------------------------------
		             操作系统保护区            不可读不可写
	0x0---------------------------------------------
	

刚才1.里的代码s存了只读段里的钥匙,而我们写写只读段里的东西是不被允许的

  • 不同的变量,默认定义在不同的段内。

    • 函数代码段:代码段 .text段 只能读
    • 字符串、常量值:只读数据段 .rodata段
    • 全局的变量:数据段 .data段
    • 堆段:malloc申请的,必须通过free释放
    • 栈段:函数的局部变量,函数返回后,出栈释放
    • static的变量:静态数据段 .data段

空间权限之边界访问

空间访问权限要考虑哪些?

  • 读写权限

  • 边界要求

    • 无越界检查
    char buf[4];
    int a=0x123456789;
        buf[0]=0x11;
        buf[1]=0x22;
        buf[2]=0x33;
        buf[3]=0x44;
        buf[4]=0x99;
       printf("the a is %x\n",a);
    

    image-20221122193613429

    我们只定义了四个数组,而这第五个数组就越界了。

    image-20221122194129315

    以后工作的时候不需要画图考虑,可能先入a也可能先入buf,只要考虑它越不越界。

    即使你在int a前面加上const, a的值还是会被改。因为const是一个建议符号,即在编译的时候,告诉编译器如果把这个值放到等号的左端,就不要改了。在编译的时候保证它只读,而在运行的时候,不归const管了,运行的时候值本身就是内存,天然是可读可写的,因为这属于栈空间,操作系统也不会管,而越界是可以修改的。

    • 如何定义边界
      • 数量
      • 特殊结束符号—–>字符串 特殊结束标志 C编译器认可

字符串空间的行为

有默认的结束标志:数字0 == ‘\0’

int main()
{
    char*s1="123456";
    printf(" the s1 size:%d ; the str size:%d",sizeof(s1),sizeof("123456"));
}

image-20221122200227769

s1是把钥匙在64位体系中字节是8;对于字符串C语言自动的会在它的结尾,加上一个‘\0’

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tian Meng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值