一. 头删和尾删
删除:
free():释放掉malloc开出的空间,注意free不是将空间清零,而是将空间的使用权交还给操作系统自由分配。该空间在没被调用复写掉之前,空间内的值仍原样存在。
1.头删:
void popFront(struct Node *head)
{
//1.p指针变量 指向首节点
//2.断开链表 head->next = p->next;
//3.释放p所在的节点
free(p);
}
2.尾删:
void void popBack(struct Node *head)
{
//1.p定位到尾节点的前一个节点
while (p->next->next != NULL)
{
p = p->next;
}
//2.释放 p->next
//3.p所在节点成为了新的尾节点 p->next = NULL;
注意:
1.struct Node head - - - 创建了头链表,内部不储存数据,地址为null,空间开在栈上(在main函数里创建新的节点,一般都开在堆上)。
2.函数不能返回局部变量的地址,因为局部变量的空间开在栈上,在函数运行完之后,空间销毁,所以只能返回一个值,而不是地址。
二. 预处理
#include <stdio.h>
#define N 10
预处理命令: 都是以 # 开头的
预处理:
1.宏定义
2.头文件包含
3.条件编译
编辑程序 --vi
编译程序 --gcc
运行文件 --a.outgcc的编译过程:
.c ---> 机器代码 (0110)
预处理: 把程序中 # 开头的预处理命令 执行了, 形成 --预处理文件 --源代码文件
gcc -E main.c -o main.i
编译: 编译成汇编文件
gcc -S main.i -o main.s
汇编: 将汇编文件 编译 成 目标文件(机器代码)
gcc -c mian.s -o main.o
链接: 需要与用到相关库函数进行链接 ,生成最终可执行文件。
1.宏定义
形式:宏名 --标识符
#define N 10
注意:
a. 标识符一般写成大写。
b. 宏对应的值 是一个常量
c. 宏定义只是做简单的文本的替换,不做计算
d. 宏的嵌套
e.最后不能写分号,因为分号也会作为宏值一部分,参与到文本的替换中
f.#undef 终止宏的定义,后面的代码不能再用这个宏
(2).带参的宏
形式: #define 宏名(参数) 宏值
避免宏展开的副作用: 能加括号的都加上 。
注意:
带参宏:
文本替换 --- 有可能导致,源代码的体积变大 。
快 --预处理阶段干
编译之后,对应的代码就已经在可执行代码中了
函数:
调用 ---- 内存中只有一份代码
会有时空开销。
2.文件包含
#include <>
#include ""#include <stdio.h>
<> 表示包含的文件,在找的时候,直接到编译器默认路径下寻找。
#include "/usr/include/test.txt"
"" 表示先在当前目录下寻找,若没有再到默认目录下寻找。(多了动作,编译可能会变慢)怎么用?
系统相关的标准头文件,用<>自己定义的 ,用 ""
3.头文件重复包含的处理
点.c 源文件 --函数实现
int isLeapYear(int year)
{
}
头文件 .h --- 声明
extern int isLeapYear(int year);
三. 位运算
0 1
计算机
1Byte --存储单位
1Byte = 8bits
软件控制硬件编程 -->CPU-->寄存器(位)--硬件关联
C语言上 位运算
&
运算规则:一假则假 --- 清0
int a = 0x33;
a & 0x55;
0011 0011
0101 0101 &
----------
0001 0001 //0x11
|
运算规则:一真则真 ---置1
int a = 0x33;
a | 0x55;
0011 0011
0101 0101 |
----------
0111 0111 //0x77
~
运算规则: 真假相对int a = 0x33;
a ~
0011 0011 ~
----------
1100 1100 //0xcc
^ 异或:
运算规则: 相同为0 不同为1 (同假异真)用于加密
0x55
0x330101 0101
0011 0011 (0x33) //异或一次加密
---------
0110 0110 //0x66
0011 0011
----------
0101 0101 //0x55 //异或两次还原
左移:<<
数值<<位数int a = 0x33;
a<<1
0110 0110
6 6 //左移一位相当于乘以2右移:>>
数值>>位数
int a = 0x55;
0000 0000 0000 0000 0000 0000 0101 0101
0000 0000 0000 0000 0000 0000 0101 010|1 //右移一位相当于除以2
注意:
看数据类型
有符号类型的数据,此时右移 最高位 补符号位 //算术右移
无符号类型的数据,此时右移 最高位 补0 //逻辑右移左移不用区分以上二者
练习:
int a = 0xffffffff;
编写程序,让所有的偶数位 清0
置1 操作 --- 或运算
int a = 0x55;0101 0101
0000 1000
-----------
0101 1101 //0x5Da = a | 1<<3;
练习:
3210
int a = 0x55555555; //0101所有奇数位置1
练习:
1.不适用第三方变量,实现两个数交换int a = 10;
int b = 20;思路一:
a = a + b; // 10 + 20 = 30 //a
b = a - b; // 30 - 20 = 10 //b
a = a - b; // 30 - 10 = 20 //a思路二:
0000 1010 a
0001 0100 b
----------
0001 1110
0001 0100
----------
0000 1010 b
0001 1110
----------
0001 0100 //
a = a ^ b; 0001 1110
b = a ^ b; 0000 1010
a = a ^ b; 0001 0100
练习:
1.统计int类型中1的个数int a = 1213; //二进制中1的个数