C语言 内存 and 结构体

欢迎访问个人博客http://www.jkraise.top

const 关键字

说明: 若果在定义变量的时候前面有const, 那么此变量只能在初始化的时候给其数值,然后此变量就不能修改了

  1. 可以定义const常量 , 具有不可变性
const int Max=100;
int Array[Max];

C语言 内存 and 结构体_第1张图片

  1. 便于进行类型检查,是编译器对处理内存内容有更多了解,消除了一些隐患

可以用指针去修改值

int a = 100;
const int b=200;

a = 101;
// b = 201;   // 如果试图使用通过变量b 来修改其值, 编译失败

int *p = &b;
*p = 201;   // 通过变量指针修改, 使用const修饰的变量,  是可以的

printf("b= %d\n", *p)
修饰指针变量

const 修饰指针变量, 指针变量的指向可以改变, 但是不允许通过指针变量修改对应变量的值
C语言 内存 and 结构体_第2张图片

const 近距离修饰指针变量, 指针变量对应的变量值可以通过指针修改, 但是不允许修改指针变量的指向
C语言 内存 and 结构体_第3张图片

const const 修饰, 既不可以通过指针修改对应变量的值, 也不可以改变指针的指向
C语言 内存 and 结构体_第4张图片

内存管理的概念和内存分区

1.内存分区
C语言 内存 and 结构体_第5张图片

2.内存管理的基本概念
内存管理, 是指软件运行时对计算机内存资源分配使用的技术
其最主要的目的是如何高效快速的分配, 并且在适当的时候释放和回收内存资源

内存分配方式 三种;
(1) 从静态存储区域分配, 内存在程序编译的时候就已经分配好, 这块内存在程序整个运行期间都存在, 例如全局变量, static变量

(2)在上创建, 在执行函数时,函数内局部变量的存储单元都可以在栈上创建, 函数执行结束时这些存储单元自动被释放, 栈内存分配运算内置于处理器的指令集中, 效率很高,但是分配内存容量有限

(3)从上分配, 亦称动态内存分配, 程序在运行的时候用malloc或new申请任意多个内存, 程序员自己负责在何时用free或delete释放内存.
动态内存的生存期有我们决定, 使用非常灵活,但问题也最多

常见动态分配内存分配函数

需要包含头文件:

(1) malloc

void *malloc(unsigned size)
作用:
    是在内存的堆区分配一个大小 为size 的连续空间, 如果分配内存成功,函数返回新分配内存的首地址, 否则,返回 NULL
 说明:
    size 是指的分配内存的字节
    void *类型的指针叫通用指针,可以指向任何的变量,C语言允许直接把任何变量的地址作为指针赋给通用指针.
    鉴于以上这点, 一般写在程序需要判断分配内存是否成功 

C语言 内存 and 结构体_第6张图片

memset

初始化

// 在读取申请一块长度为16个字节的内存
int *p = (int *)malloc(sizeof(int)*4);
// 把新申请的空间用"A"去初始化
memset(p, "A", sizeof(int)*4);
for (int i =0; i<4; i++){
    printf("%d\t", *(p+i));
}   

C语言 内存 and 结构体_第7张图片

calloc函数

申请地址是连续的

char *p;

//   参1   内存多大,  参2 几块内存
p = (char *)calloc(100, 2);

C语言 内存 and 结构体_第8张图片

realloc

修改malloc , calloc申请 内存空间大小
realloc 并不保证调整后的内存空间和原来的内存空间保持在同一内存地址
所以在代码中,我们必须将realloc返回的值, 重新赋值给 p

p = (int *) realloc (p, sizeof(int) *15);
内存泄漏

向系统申请了一块内存, 不用时及时归还


int *p=NULL;
p =malloc(100);
if (p==NULL){
    return 0;

}

for (int i=0; i<100; i++){
    *p=i;
    
}


// free函数归还
free(p);

C语言 内存 and 结构体_第9张图片

c语言构造类型

  1. 数组和 结构体
struct person {
    char name[20];//    名字
    float weight;//    体重
    float hight;//  身高
    char sex; //    性别
} xiaoma, xiaohong; // 可以紧接着在后面放结构体 变量名


struct person xiaoHua, xiaoXue;  // 也可以这样 定义结构体变量

// 给 xiaoma 这个变量中的成员赋值
xiaoma.id = 101;
xiaoma.sex = m; 

str.cpy(xiaoma.name, "xiaoma")

// 获取成员的数据
printf("%d\n", xiaoma.id);
printf("%c\n", xiaoma.sex);
printf("%s\n", xiaoma.name);
结构体初始化
struct person {
    char name[20];//    名字
    float weight;//    体重
    float hight;//  身高
    char sex; //    性别
};

struct person xiaoMing={"小明", 65, 178, m};  // 初始化
printf("名字:%s,  身高:%d, 体重:%d, 性别:%c", xiaoming.name, xiaoming.hight, xiaoming.weight, xiaoming.sex);

// 部分初始化
struct person xiaowang={.name="小王" };

// 方法3
struct person xiaoJin;
xiaoJin = (struct person){"小金", 45, 176, m};

结构体数组
struct car{
    char color;
    float hight;

};

struct car num[4];

struct 结构体{
    成员列表
} 数组名 [数组长度];

或者
struct 数组名 [数组长度];

// 结构体初始化
struct car num[9]={{"r", "xiaom", "1.8"},{},{}} // 给第0个元素赋值
结构体指针
struct stu{
    int num;
    char name[20];
    int age;
};

struct stu boy;

struct stu *p=NULL;
p= &boy;

// struct stu *p=&boy;

(*p).num = 101;
printf("%d\n", (*p).num);

scanf("%d", &(p->num));

// 方法二 取值
p->score = 99.9;
printf("%d\n", p->score); 
结构体嵌套

说明;
成员也可以又是一个结构, 即构成了嵌套的结构
结构体嵌套; 结构体定义的是里面有其它的结构体
在这里插入图片描述

struct Data{
    int month;
    int day;
    int year;
   
};

struct stu{
    int num;
    int *name;
    char sex;
    struct Date birthday;
    float score;
};

2、对嵌套结构体成员的访问

struct stu boy;

boy.birthday.month = 11;
boy.birthday.day = 11;
boy.birthday.year = 2000;
三层嵌套结构体
// 定义 ""时分秒"" 的结构体
struct Time{
    int hh;     // 时
    int mm;     // 分
    int ss;    //秒
};

struct Date{
    int year;   // 年
    int month;      // 月
    int day;    //日
    struct Time datetime;       //时间
};

struct Person{
    char name;      //姓名
    struct Date inDate;     //入职时间
    struct Date GoDate;     // 离职时间
};

C语言 内存 and 结构体_第10张图片

结构体变量作函数参数
  1. 成员值做函数的参数
    1. 结构体成员属性作为函数的参数就是值传递(成员变量是数组除外)
  2. 结构体变量名作为函数的参数
struct Time{
    int year;
    int  month;
    int day;

};

void changeTime(struct Time tempTime){
    tempTime.year = 2001;
    tempTime.month = 12;
    tempTime.day = 12;
};

int  main(int argc, const char * argv[]){
    struct Time t = {2000, 11, 11};
    changeTime(t);
    printf("%d年%d月%d日\n", t.year, t.month, t.day);
    
    return 0;
};
 

在这里插入图片描述

注意

这种传送要将全部成员逐个传送,

特别是成员为数组时将会使传送的时间和空间开销很大, 严重地降低了效率,
使用指针. 即用指针变量作函数参数进行传送从而减少了时间和空间的开销

结构体指针作函数参数
  1. 结构体指针作为函数的参数
struct Time{
    int year;
    int month;
    int day;
   
};

void changeTime(struct Time *tempTime){
    (*tempTime).year = 2001;;
    tempTime->month =12;
    tempTime->day =12;
};

int  main(int argc, const char * argv[]){
    struct Time t = {2000, 11, 11};
    changeTime(&t);
    printf("%d年%d月%d日\n", t.year, t.month, t.day);
    
    return 0;
};

C语言 内存 and 结构体_第11张图片

枚举介绍, 定义

[]
C语言供了一种称为"枚举"的类型
在"枚举"类型的定义中列举出所有可能的取值, 被说明为该"枚举"类型的变量取值不能超过定义的范围

[枚举类型是一种基本数据类型,而不是一种构造类型, 因为它不能再分解为任何基本类型]

定义
enum 枚举类型名{
    枚举列表
};

enum weekday{sun, mou, tue, wed, thu, fri, sat};

说明;

  • 在枚举值表中应罗列出所有可用值, 这些值也称为枚举元素
    
  • 凡被说明为weekday类型变量的取值只能是七天中的一天
    
枚举元素本身由系统定义了一个表示序号的数值, 从0开始顺序定义为0,1,2
typedef关键字
  1. 语法格式
typedef 原类型名 新类型名;

typedef int ZHENGXING;
ZHENGXING a = 10;   //等价于 int a =10;

说明;
原类型名中含有定义部分, 新类型名一般用大写表示,以便区别
C语言 内存 and 结构体_第12张图片

// 第一种
struct car{
    int height;
    color;
};

typedef struct car Car;

// 第二种
typedef struct car{
    int height;
    color;
}Car2;

// 第三种
typedef struct {
    int height;
    color;
}Car3;

只是给类型名起个别名 , 原来的还能用

宏以及宏替换的过程
// 宏定义
#define N 100

int main(){
    int num[N]:

};

// 有参数
#define ADD(x,y) x+y 
#define SUB(x,y) x-y 
#define MUL(x,y) (x)*(y)    // 以后遇到乘法加括号 
#define DIV(x,y) x/y 

// 宏名与参数表不能有空格
#define PM (x.y)    // 这是错误的



默认 大写字母
宏仅仅是替换

练习

#define MAX(a,b) a>b?a:b
#define MIN(a,b) a
log 日志
替换printf 打印
#define LOG(format,...) printf(format, ## __VA_ARGS__)

LOG("hello world %d\n", 100);
typedef和define的区别
  1. 区别
    1. 宏定义; 只是简单的字符串代换, 在预处理阶端完成
    2. typedef:对类型说明符奇异果别名, 在编译的事处理,用来表示新命名的标示符具有类型定义说明的作用

.

你可能感兴趣的:(#,编程语言,C语言,指针,内存管理,数据结构,c语言)