硬核干货!C语言的变量啊(8)

10 篇文章 0 订阅
10 篇文章 0 订阅

变量

变量的作用域:
	(1).块变量  :语句块中定义的变量,只能在定义的语句块中使用
 		 作用域范围: 从定义开始到}结束(语句块)
 			  if 、for 、while 、do while {}  ...
 			  {
    			//块变量
  			 }
  			 
  	(2). 局部变量  :在函数里面语句块外定义的变量,形参也是局部变量
  		作用域范围:从定义开始到本函数结束(函数内部)
  		
  	(3). 全局变量  :在全局里定义的变量,在函数外面定义的变量,在程序中都可以访问
		 作用域范围:整个函数

① 在同一作用域下面,不能定义和声明同名的变量
② 在不同的作用域下面,可以定义同名的变量
③ 在访问同名变量时遵循局部优先原则 ,局部变量会隐藏全局变量

局部优先原则:在搜索变量时,先找块变量;如果没有块变量,则查找局部变量,如果没有局部变量,则查找全局变量;如果全局还没有,则直接报错“未定义”。
(块变量 -> 局部变量 -> 全局变量)

在同名的情况下,如果要访问全局变量:
(1).提供语句块,然后在语句块中注入全局变

 {
   extern type gloable_var; // extern 类型 变量;   访问到的将是全局变量
  }  

(2).提供一个函数

 type  getX(){
   return gloable_var;
  }

(3).提供一个全局的指针

 type *p = &gloable_var;
C语言程序内存地址分布:

要学习变量的属性存储,就需要了解一下程序的内存地址分布情况。

一个程序(进程)有4G的虚拟内存地址空间
sizeof(指针) == 4
0-3G 用户空间
3G-4G 内核空间

在这里插入图片描述

从低地址到高地址: 用户空间(代码区(text) -> 数据段(data) -> BSS -> 堆区(heap) —> (堆栈缓冲区) —> 栈区(stack)) —> 内核空间

代码区:存储代码文本、字面值
不可修改,只要修改代码区的内容,段错误(核心已转储)
数据取:存储的是已经初始化的全局变量 和 已经初始化的静态变量
BSS : 存储的是未初始化的全局变量 和 未初始化的静态变量 ,程序启动时会对该区域进行自动全部清零(擦除)
堆区: 动态内存(手动申请 ,手动释放) 从小到大扩张使用
栈区: 存储普通的局部变量和块变量 (形参、函数调用时的开销) 从大到小使用
静态内存,不需要程序员自己管理
函数调用之后,函数的内存会回收,不能返回局部变量的地址
命令行环境列表:
内核空间:不能直接访问,只能通过系统调用访问

在这里插入图片描述

变量的存储修饰:
  1. auto :自动变量 声明的变量默认就是auto auto可以省略 (c++中的auto变成了类型自动推导)
  2. static :静态变量 存储在全局数据区

静态变量:如果没有初始化,自动初始化为0
初始化的静态变量存储在数据区
未初始化的静态变量存储在BSS区

普通局部变量 和 静态局部变量:

  (1). 存储位置:
   普通局部变量:存储在 栈区
   静态局部变量:存储在 全局数据区
  (2). 生命周期
   普通局部变量 生命周期:只在函数调用期间
   静态局部变量 生命周期:是整个程序运行期间
  (3). 执行次数
   普通局部变量:每调用一次函数都会定义一次
   静态局部变量:只有第一次执行时才会定义 ,静态局部变量会保存上一次调用结束之后的结果
  (4). 作用域是一样的

普通全局变量 和 静态全局变量:

(1). 存储位置一样
(2). 生命周期一样
(3). 作用域不一样
 	普通全局变量的作用域是整个项目的所有文件
  		可以用extern声明一个变量在其他的文件中已经定义
		(注入在其他文件中已经定义好的全局变量)
 	静态全局变量的作用域是当前文件(只能在当前.c文件中才能访问)

static 的作用:

(1). 修饰局部变量: 相对于普通局部变量,它的存储位置发生变化,保存到全局数据区,生命周期为整个程序
(2). 修饰全局变量: 相对于普通全局变量,作用域发生变化,只能在当前文件中访问
(3). 修饰函数:     只能当前文件中调用该函数,通过#include头文件也能调用
  1. register :寄存器变量(保存在寄存器上面)

     申请把变量作用寄存器变量    提高访问效率
     (1). 只是一种请求,可能被拒绝
     (2). 声明为register变量时,不能取内存地址,不能取&
     (3). 一般来说寄存器变量只能是4字节(寄存器相当于一个地址)
    
  2. volatile :易变变量

     拒绝效率优化,每次读取volatile变量时,都会去内存中重新加载一遍,以确保是正确的结果
     一般用于中断程序处理中    多线程中
     表示该变量可能遭遇意想不到的改变,所以每次在读取该值时都必须重新加载
    
  3. const :

     const修饰的变量表示只读,不可以修改(可以通过其他方式修改)
     const修饰的局部变量保存在栈区,可以通过指针修改内存区域的值
     const修饰的全局变量保存在代码区,如果直接修改编译报错,如果通过指针修改,会段错误
    
const修改局部变量:
	const int b = 10;
	int *p = &b;
	*p = 111;
	printf("%d",b);
const char *p;   常量指针
  	const修饰*p  *p只读  p本身的值可以修改
char const *p;   常量指针
   	等同于 const char *p;
char * const p;  指针常量
   	const修饰p   p只读   *p的内容可以修改  
const char * const p;  常量指针常量
   	p 和 *p 都是只读

const的作用:

 (1). 修饰参数,防止在函数中意外修改实参的值
 (2). 增强代码的健壮性
 (3). 定义常量,增加代码可读性
 const double PI = 3.1415926
  1. extern:

     (1).局部变量和全局变量同名时,在语句块中注入全局变量   访问到的是被局部同名变量隐藏掉的全局变量
     (2).声明变量在其它文件中定义过(声明外部变量 或者 函数)的变量和函数 
    
动态内存:

存在堆区,如果需要使用,需要自己申请,然后使用完之后手动释放。

头文件:#include <stdlib.h>

void *malloc(size_t size);

// 申请动态内存 size为申请的字节数
返回值为 void * (万能指针)可以转换为任意指针
如果申请失败 返回 NULL
需要对申请的动态内存进行成功的判断

void free(void *ptr);

// 释放动态内存
一定要确保参数ptr为malloc/calloc/realloc返回的值
如果ptr前面的控制块被修改,将会导致核心段错误
即使释放掉所有的动态内存,第一次申请的33页内存将一直会保留

注意:
(1)动态内存如果没有被释放将造成内存泄漏(这个问题很严重)
(2)动态内存不能被重复多次释放
(3)malloc虽然是申请size个字节的动态内存,但实际上却不是这个数字
第一次malloc分配了至少33页的内存空间,1页等于4096(4kb=4*1024byte)个字节
(4)在该内存没有全部使用之前,不会再申请更多的内容(只是在之前申请的内存中划一部分出来)
(5)申请多少个字节的内存,严格控制使用多少个字节的内存,不要越界

动态内存:堆内存 手动申请 手动释放
内存泄漏:申请的动态内存没有释放 或者 没有及时释放
内存碎片:多次申请和释放内存,会造成一些动态内存块中内存无法使用

需要使用大片的内存时用动态内存, 少部分的内存直接用栈内存

void *calloc(size_t nmemb, size_t size);

申请nmemb个size字节大小的连续内存 总共有nmembsize个字节
等同于malloc(nmemb
size)
malloc申请的动态内存不一定会擦除内存中的数据,calloc一定会擦除
返回NULL表示失败

void *realloc(void *ptr, size_t size);

ptr:必须是指向动态内存
size:想要最终调整为size个字节大小的动态内存
调整动态内存大小为size个字节

注意:
(1) 调整动态内存之后必须重新接收该函数的返回值,调整大小之后,动态内存的位置可能发生改变(返回值和ptr可能不一样)
(2) 如果在扩大的时候,后面的动态内存已经被使用,那么将重新申请一块size个字节的动态内存,然后把之前的内存中的数据拷贝过来,释放之前的内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值