存储类别autoauto说明的变量只能在某个程序范围内(局部)使用,通常在函数体内或函数中的复合语句里。(默认是随机值),在函数体的额某程序段内说明auto存储类型的变量一般省略关键字auto,如下:auto int k;in...
 
                
存储类别
auto
auto说明的变量只能在某个程序范围内(局部)使用,通常在函数体内或函数中的复合语句里。(默认是随机值),在函数体的额某程序段内说明auto存储类型的变量一般省略关键字auto,如下:
auto int k; int j; double x;
register
register称为寄存器变量,register变量是想将变量放入CPU寄存器中,这样可以加快程序的运行速度,如申请不到就使用一般内存,如auto
注意:
register变量必须是能被CPU所接受的类型,这通常意味着register变量必须是一个单个的值,并且长度应该小于或等于整型长度;
不能使用`&`来获取register变量的地址
static
static变量称为静态变量,既可以在函数体内,也可以在函数体外说明(默认是0);static在内存中以固定地址存放,而不是以堆栈方式存放的,只要没结束就不会随着说明它的程序段的结束而销毁,它下次再调用该函数,该存储类型不会重新声明,且保存上次调用的值(升级为全局变量的生命周期)
static修饰的变量,在其他文件不能使用
#include  <stdio.h>
void test1();
void test2();
int main(int argc, const char *argv[]) {
//    test1(); // out 0 0 0 0 0
    test2(); // out:0 1 2 3 4
}
void test1() {
    for (int j = 0; j < 5; ++j) {
        int i; // i为随机值
        i = 0;
        printf("%d\n", i++); // 每次循环到都是重新声明
    }
};
void test2() {
    for (int j = 0; j < 5; ++j) {
        static int i; // i默认值为0
        printf("%d\n", i++); // 每次循环i不会销毁 程序结束i销毁
    }
};
extern
当变量在一个文件中的函数体外声明(全局变量),所有的而其他文件中的函数或程序段都可以引用这个变量;
extern称为外部参照引用型,使用extern声明的变量是从外部拿来的;
如果引用static修饰的全局变量,是无法引用的
// test.c
int i = 10;
// main.c
#include  <stdio.h>
int main(int argc, const char *argv[]) {
    extern int i; // 告诉编译器 i变量是外部的 从其他文件中寻找
    printf("%d\n", i); // 想使用test.c中的全局变量i
    return 0;
}
// shell
$ gcc main.c test.c
$ ./a.out
out: 10
动态内存
- C/C++定义了4个内存区间:
- 代码区
- 全局变量与静态变量区(全局变量、static修饰的额静态变量、字符串常量)
- 局部变量区(栈区:函数内部的局部变量,函数结束变量随之销毁,不能进行人工干预)
- 动态存储区(堆区)
- 静态存储分配
通常定义变量,编译器在编译时都可以根据该变量的类型知道所需内存空间的大小,从而系统在适当的时候为他们分配确定的内存空间
- 在栈上创建
在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,
栈内存分配运算内置与处理器的指令集中,效率很高,但是分配的内存容量有限
动态内存分配
- 有些操作对象只有在程序运行时才能确定,这样编译器在编译时就无法为他们预定存储空间,只能在程序运行时,系统跟你局运行时的要求进行内存奶粉恩平,这种方法称为动态内存分配;
- 所有动态存储分配都在堆区中进行
- 从堆上分配,亦称动态分配。程序在运行的时候用malloc申请任意多少的内存,程序员自己负责在何时用free释放内存。动态内存的额生存期由程序员本身来决定,使用非常灵活,但问题也最多
堆内存的分配与释放
- 当程序运行到需要一个动态分配的变量或对象时,必须向系统申请取得堆中的一块所需大小的存储空间,用于存储该变量或对象。当不再使用该变量或对象时,也就是它的声明结束时,要显示释放它所占用的存储空间,这样系统就能对该堆空间再次分配,做到重复使用有限的资源
- 堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化
malloc/free
使用需要引入
#include <stdlib.h>
void *malloc(size_t num); void free(void *p);
- malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数
- malloc申请到的时候一块连续的内存,有时候可能会比所申请的空间大。其有时会申请不到内存,返回NULL
- malloc返回值的类型是 void * ,所以在调用malloc时要显式的进行类型转换,将void * 转换为所需要的指针类型
- 如果free的参数是NULL的话,没有任何效果
- 释放一块内存中的一部分是不被允许的
#include  <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char *argv[]) {
    char *p = NULL;
    // 申请地址
    p = (char *) malloc(10 * sizeof(char));
    if (p == NULL) { // 判断是否申请成功
        printf("申请失败");
        return 0;
    }
    printf("申请成功:%p\n", p);
    strcpy(p, "测试1"); // 内存赋值
    printf("%s\n", p);
    free(p); // 释放内存
    return 0;
}
Ps:如果出现 说明free释放内存不是malloc创建的或不完整的
hello(54168,0x11289adc0) malloc: *** error for object 0x7ffe0c4058f1: pointer being freed was not allocated hello(54168,0x11289adc0) malloc: *** set a breakpoint in malloc_error_break to debug
注意事项:
- 删除一个指针p(free(p);),实际意思是删除了P所指向的目标(变量或对象等),释放了它所占的堆空间,而不是删除p指针,释放堆空间后,p成了空悬指针
- 分配失败返回一个空指针(NULL),发生异常资源不足导致分配失败
- malloc与free是配对使用的,free只能释放堆空间。如果malloc返回的指针值丢失,则所分配的堆空间无法回收,称内存泄露,同一时间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存malloc返回的指针,以保证不发生内存泄露,也必须保证不会重复释放堆内存空间
- 动态分配的变量或对象的生命周期。无名对象的生命周期并不依赖建立它的作用域,比如在函数中建立的动态对象在函数返回后仍然可以使用。我们也称堆空间为自由空间(Free Store)就是这个原因。但必须记住释放该对象所占堆空间,并且只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错
野指针
不是指向NULL的指针,是指向"垃圾"内存的指针,"野指针"是很危险的
野指针形成的主要原因
- 指针变量没有被初始化
- 指针p被free后,没有置为NULL,让人误以为是合法指针
- 指针超越了变量的作用范围,这种情况让人防不胜防
Demo:
#include  <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct student {
    char name[10];
    int age;
    float core;
} stu; // 别名 stu = struct student
stu *newStu() {
    stu *p;
    if ((p = (stu *) malloc(sizeof(stu))) == NULL) {  // 申请内存
        printf("申请内存失败");
        return NULL;
    }
    strcpy(p->name, "小明");
    p->age = 20;
    p->core = 99.2;
    return p;
}
int main(int argc, const char *argv[]) {
    stu *s;
    s = newStu();
    if (s == NULL) {
        return 0;
    }
    printf("name:%s age:%d core:%f\n", s->name, s->age, s->core);
    free(s); // 释放内存
    s = NULL; // 处理野指针
}
本文标题为:C语言基础-存储类别、链接和内存管理
 
				
         
 
            
        基础教程推荐
- C语言文件操作与相关函数介绍 2023-06-13
- C语言实现简易停车场管理系统 2023-03-13
- C++类和对象到底是什么 2022-11-12
- C语言预编译#define(预处理) 2023-04-03
- 使用C/C++读写.mat文件的方法详解 2023-03-05
- C++高级数据结构之并查集 2023-04-20
- 如何告诉 MinGW 链接器不要导出所有符号? 2022-10-07
- C/C++ Qt StatusBar底部状态栏应用教程 2023-01-10
- 漫画讲解C语言中最近公共祖先的三种类型 2023-01-01
- 使用VS2022开发在线远程编译部署的C++程序(图文详解) 2023-01-15
 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
    	 
						 
						 
						 
						 
						 
				 
				 
				 
				