一、枚举类
"枚举"(Enumeration,简称 Enum)是一种数据类型,它允许程序员定义一组命名的整型常量,这组常量代表了一个集合中的成员。枚举类型使得代码更加清晰易读,同时提高了代码的可维护性和安全性。
作用:
1.为了提高代码可读性
2.提高代码的安全性
1. 定义
语法:
enum 枚举名
{
列举各种值1, //枚举元素//枚举常量
列举各种值2,
};
enum fire
{
LITTLE_FIRE,
MIDDILE_FIRE,
LARGE_FIRE,
};
列举各种值,之间用逗号隔开,不需要写类型名
2.注意
1. 表示 定义了一种 枚举类型
2. 枚举中逐个列举的值,默认是从0开始
如果有给定的值,则后续没有给值的 枚举元素 依次 加1
3. 枚举类型的 本质 实际是一个int类型的数据
4. 枚举类型的变量 与 整型类型的变量通用的
与 宏定义对比
区别:使用阶段不同 宏定义 --- 预处理阶段
枚举 --- 编译阶段 要检查语法 运行阶段 参与代码运行
可读性
都提高了可读性
枚举,更能说明有相关性的一些值间关系
练习:
从键盘输入 1~7
打印对应的星期英文
#include<stdio.h>
enum weekday
{
Monday=1,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
};
int main(void)
{
typedef int INT ;
INT n,a=9;
scanf("%d",&n);
switch(n)
{
case Monday:
printf("Monday!\n");
break;
case Tuesday:
printf("Tuesday!\n");
break;
case Wednesday:
printf("Wednesday!\n");
break;
case Thursday:
printf("Thursday!\n");
break;
case Friday:
printf("Friday!\n");
break;
case Saturday:
printf("Saturday!\n");
break;
case Sunday:
printf("Sunday!\n");
break;
default:
printf("No!\n");
break;
}
}
二、typedef
typedef是 C 语言中的一个关键字,用于为现有的数据类型定义新的名称或别名。它的主要作用是简化代码,使得代码更加易读、易维护,尤其是在处理复杂数据类型时。
typedef (type define)
本意 不是定义类型,而是给类型起别名
用法:
#include <stdio.h>
typedef int Integer; // 将 int 类型重命名为 Integer
int main() {
Integer a = 10; // 使用新的类型别名
printf("Value of a: %d\n", a);
return 0;
}
三、位运算
位运算:可以直接操作二进制位 ,控制硬件。
1.按位与 (&)
运算规则:一假则假
eg:
0xaa
1010 1010
0011 0011 &
---------
0010 0010 0x22
作用:可以用来‘置0’
2.按位或(|
)
运算规则:一真则真
1010 1010 // 0xaa
0011 0011 | // 0x33
---------
1011 1011 //0xbb
3.按位取反 (~)
运算规则:真假相对
int a = 5; // 二进制:0000 0101
int c = ~a; // 结果:1111 1010,即 -6 (在32位系统中)
4. 按位异或 (^)
运算规则:相同为 0,不同为 1
1010 1010 // 0xaa
0011 0011 ^ // 0x33
---------
1001 1001 //0x99
作用:加密,交换。
交换:
a = a + b; //
b = a - b; //b = a
a = a - b; //
a = a ^ b;
b = a ^ b;
a = a ^ b;
注意:浮点数不能做位运算
5.左移 (<<)
写法:a<<n //表示将 a这个数据 左移 n位
左移1位 相当于乘 2
6.右移 (>>)
写法:a>>n //表示将 a这个数据 右移 n位。(右移1位 相当于除 2)
右移分为算术右移和逻辑右移:
算术右移
看符号位 看数据类型
如果是有符号类型的数据,右移时,最高位补的是符号位
如果是无符号类型的数据,右移时,最高位补的0
逻辑右移:高位补0。
练习:
1.统计int类型数据中1的个数
int a = 121314;
#include <stdio.h>
int main (void)
{
int a =121314;
int i = 0;
int k = 0;
for(i = 0;i < 32;++i)
{
if ((a & 1<<i) != 0)
++k;
}
printf("k = %d\n",k);
return 0;
}
2.实现一个循环左移
#include <stdio.h>
int main (void)
{
// int a =0xf0000001;
int a =0xcd;
int i = 0;
for (i = 0;i < 8;++i)
{
if (a & 0x80000000)
{
a = a<<1;
a += 1;//a = a|1;
}
else
a = a<<1;
printf("%#x\n",a);
}
return 0;
}
四、malloc
函数 free
函数
头文件:#include <stdlib.h>
函数指针 指向函数类型的指针 //基类型为函数类型的指针
指针函数 返回值为指针类型的函数
堆内存定义: 堆内存是计算机内存的一部分,程序在运行时可以动态分配和释放。与栈内存不同,堆内存的生命周期由程序员控制,而不是由函数调用的自动管理。
1.malloc
函数
定义: malloc
(memory allocation)用于在堆上分配指定大小的内存块,并返回指向该内存块的指针。
void* malloc(size_t size);
参数:size //表示申请的空间的大小,单位字节
返回值:
成功 返回 申请到内存空间的地址
失败 返回 NULL
2.free
函数
定义: free
用于释放之前使用 malloc
、calloc
或 realloc
分配的内存块,释放后的内存块可以被再次分配使用
void free(void* ptr);
参数:ptr 一定是之前申请到堆上空间的地址
free释放后的空间
1.一般不再使用
2.指向这块空间的指针 --- 是个野指针
3.free之后对应空间上的内容 ---也不要使用
注意:
1. 成对出现
2. free只是释放了空间 --- 表示这块空间 又自由了
但是 这块空间上的数据 并不会清零
3. 不要多次free
3.常见问题
内存泄漏: 如果程序分配了内存但没有释放,这部分内存就无法再次使用,最终可能会导致程序内存不足。使用 malloc 时应确保所有分配的内存都用 free 释放。
悬空指针: 一旦释放了内存,指向该内存的指针会变成悬空指针。如果继续使用这些指针,可能会导致未定义的行为。释放内存后应将指针设置为 NULL。
双重释放: 不应对同一块内存调用多次 free,这会导致程序崩溃或不稳定。每块内存应只被释放一次。
内存分配失败: malloc 可能会失败,特别是在内存不足的情况下。始终检查 malloc 的返回值是否为 NULL,以处理内存分配失败的情况。
内存对齐: 某些平台可能要求内存对齐,因此分配内存时需要确保对齐需求得到满足。通常,malloc 处理这些细节,但在某些情况下,可能需要更精细的控制。
练习: 定义整型一维数组 5个元素把数组放在堆上,给5个值,打印输出
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
int i = 0;
int *p = malloc(sizeof(int)*5);
for (i = 0;i < 5;++i)
{
p[i] = i*2;
}
for(i = 0;i < 5;++i)
{
printf("%d ",p[i]);
}
putchar('\n');
free(p);
return 0;
}