欢迎访问个人博客http://www.jkraise.top
const 关键字
说明: 若果在定义变量的时候前面有const, 那么此变量只能在初始化的时候给其数值,然后此变量就不能修改了
- 可以定义const常量 , 具有不可变性
const int Max=100;
int Array[Max];
- 便于进行类型检查,是编译器对处理内存内容有更多了解,消除了一些隐患
可以用指针去修改值
int a = 100;
const int b=200;
a = 101;
// b = 201; // 如果试图使用通过变量b 来修改其值, 编译失败
int *p = &b;
*p = 201; // 通过变量指针修改, 使用const修饰的变量, 是可以的
printf("b= %d\n", *p)
修饰指针变量
const 修饰指针变量, 指针变量的指向可以改变, 但是不允许通过指针变量修改对应变量的值
const 近距离修饰指针变量, 指针变量对应的变量值可以通过指针修改, 但是不允许修改指针变量的指向
const const 修饰, 既不可以通过指针修改对应变量的值, 也不可以改变指针的指向
内存管理的概念和内存分区
1.内存分区
2.内存管理的基本概念
内存管理, 是指软件运行时对计算机内存资源的分配和使用的技术
其最主要的目的是如何高效快速的分配, 并且在适当的时候释放和回收内存资源
内存分配方式 三种;
(1) 从静态存储区域分配, 内存在程序编译的时候就已经分配好, 这块内存在程序整个运行期间都存在, 例如全局变量, static变量
(2)在栈上创建, 在执行函数时,函数内局部变量的存储单元都可以在栈上创建, 函数执行结束时这些存储单元自动被释放, 栈内存分配运算内置于处理器的指令集中, 效率很高,但是分配内存容量有限
(3)从堆上分配, 亦称动态内存分配, 程序在运行的时候用malloc或new申请任意多个内存, 程序员自己负责在何时用free或delete释放内存.
动态内存的生存期有我们决定, 使用非常灵活,但问题也最多
常见动态分配内存分配函数
需要包含头文件: <stdlib.h>
(1) malloc
void *malloc(unsigned size)
作用:
是在内存的堆区分配一个大小 为size 的连续空间, 如果分配内存成功,函数返回新分配内存的首地址, 否则,返回 NULL
说明:
size 是指的分配内存的字节
void *类型的指针叫通用指针,可以指向任何的变量,C语言允许直接把任何变量的地址作为指针赋给通用指针.
鉴于以上这点, 一般写在程序需要判断分配内存是否成功
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));
}
calloc函数
申请地址是连续的
char *p;
// 参1 内存多大, 参2 几块内存
p = (char *)calloc(100, 2);
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语言构造类型
- 数组和 结构体
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; // 离职时间
};
结构体变量作函数参数
- 成员值做函数的参数
- 结构体成员属性作为函数的参数就是值传递(成员变量是数组除外)
- 结构体变量名作为函数的参数
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;
};
注意
这种传送要将全部成员逐个传送,
特别是成员为数组时将会使传送的时间和空间开销很大, 严重地降低了效率,
使用指针. 即用指针变量作函数参数进行传送从而减少了时间和空间的开销
结构体指针作函数参数
- 结构体指针作为函数的参数
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语言供了一种称为"枚举"的类型
在"枚举"类型的定义中列举出所有可能的取值, 被说明为该"枚举"类型的变量取值不能超过定义的范围
[枚举类型是一种基本数据类型,而不是一种构造类型, 因为它不能再分解为任何基本类型]
定义
enum 枚举类型名{
枚举列表
};
enum weekday{sun, mou, tue, wed, thu, fri, sat};
说明;
-
在枚举值表中应罗列出所有可用值, 这些值也称为枚举元素
-
凡被说明为weekday类型变量的取值只能是七天中的一天
枚举元素本身由系统定义了一个表示序号的数值, 从0开始顺序定义为0,1,2
typedef关键字
- 语法格式
typedef 原类型名 新类型名;
typedef int ZHENGXING;
ZHENGXING a = 10; //等价于 int a =10;
说明;
原类型名中含有定义部分, 新类型名一般用大写表示,以便区别
// 第一种
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<b?a;b
log 日志
替换printf 打印
#define LOG(format,...) printf(format, ## __VA_ARGS__)
LOG("hello world %d\n", 100);
typedef和define的区别
- 区别
- 宏定义; 只是简单的字符串代换, 在预处理阶端完成
- typedef:对类型说明符奇异果别名, 在编译的事处理,用来表示新命名的标示符具有类型定义说明的作用
.