此笔记仅供大家免费学习参考所用
https://www.bilibili.com/video/BV18p4y167Md/
archlinux
的manjarolinux
发行版的物理机,大家自己搭建linux环境的话推荐试用或租用云服务器或者尝试WSL
gcc
版本是 10.2.0vim
(推荐vim配置vimplus)#inlcude <stdio.h>
#include
int main(void){
printf("hello world\n");
exit(0);
}
gcc 编译c的源文件过程
gcc -v
C源文件->预处理->编译->汇编->链接->可执行文件
完整过程
gcc -E hello.c > hello.i
gcc -S hello.i
gcc -c hello.s
hello.o//目标文件
gcc hello.o -o hello
或者
gcc hello.c
gcc hello.c -o hello
又或者
make hello
执行
./hello
hello world
以函数为单位来进行程序编写
声明部分+实现部分;return 0; 多用空格空行;添加注释;
防止写越界,防止内存泄露,谁打开水关闭,谁申请谁释放;
程序员的约定:在c中,如果没有出现函数原型,就默认函数的返回值是int
#include
int main()
{
<<<<<<< HEAD
int *num = malloc(sizeof(int));
*num = 100;
printf("%d\n",*num);
=======
int *num = (int *)malloc(sizeof(int));
>>>>>>> d8201497ccb6ce60411ef4f1d6347921a54e7c22
return 0;
}
hello.c: 在函数‘main’中:
hello.c:5:23: 警告:隐式声明函数‘malloc’ [-Wimplicit-function-declaration]
5 | int *num = (int *)malloc(sizeof(int));
| ^~~~~~
hello.c:5:23: 警告:隐式声明与内建函数‘malloc’不兼容
#include
#include
int main()
{
int *num = (int *)malloc(sizeof(int));
return 0;
}
254 -> unsigned int -> 32bit
(254)10 = (1111 1110)2 = (376)8 = (FE)16
(以上括号外面表示进制)
254
B11111110(c不认识这个表示)
0376
0xFE
int i;
float f;
doubel d;
char ch;
(隐式和显式(强制类型转换))
ch + i -> i
f -d -> d
(ch + i) - (dloat -double) -> double
#incldue <stdio.h>
#include
#include
int main() {
bool a = false;
printf("a = %d\n", a);
exit(0);
}
float类型的数本身精度不精确
int func(float f) {
if (f < 0) {
return -1;
} else if (fabs(f-0) <= 1e-6) {
return 0;
} else {
return 1;
}
}
浮点数
比喻1e1(科学计数法)
e后面跟的是10的指数(也就是1的10次方,e表示10次方),f表示浮点数
1e1表示1×10¹,其实就是10
再例如5e2f,表示5×10²,也就是500
========================================================================================================================
-1.56E+12 的常量表示法怎么计算?
理解为1.56的12次方的负数?也就是:-1560000000000?
-1.56*10^12=-1560000000000
理解为-1.56*10的12次方-1560000000000
========================================================================================================================
0.1101101111
+ 0.0000000001
---------------
0.110110000
因为在任何区间内(比如1.0和2.0之间)都存在无穷多个实数,所以计算机浮点数不能表示区域内所有的值。浮点数往往只是实际值的近似。例如7.0可能以浮点数值6.99999存储。
解释
十进制转化为二进制的方法是 依次与2^(-n)作比较(n从1开始)
若大于该值则为1,且减去此值,否则为0;然后继续下一轮比较
举例说明:将0.842356转换成二进制,你会发现比较将会是无穷无尽的。
如果你截取到某位,必须做一些取舍。取舍的标准是:其后一位若为1则进1;后一位为0则不进。
若要截取9位,因为第10位为0,故不进位,则最终的结果为:0.110101111;
若要截取到8位,因为第9位为1,故要进位,则最终的结果为:0.110110000(即0.1101101111 + 0.0000000001)。
从这个例子可以看出十进制小数的转换成二进制时只是一个近似值。其实大部分浮点数保存在计算机中都只是一个近似值。至于是稍微大于原值还是稍微小于原值,要看截取时有无进位。
0.842356
0.110101111 0 1001001010010010001111100101101110000101011 截取第9位 第10位为0,所以不进位=0.110101111
0.11010111 1 01001001010010010001111100101101110000101011 截取第8位 第9位为1,所以进位 =0.110110000
在iso c中 char
有无符号是未定义行为
0(整型) '0'(字符常量) "0"(字符串常量) '\0'(字符常量)
数据类型要和后续代码中所使用的输入输出要相匹配(小心自相矛盾)
精度超出部分会从输出的类型范围的最小值开始累积计算
#include
#include
int main() {
unsigned int a;
a = 1 << 31;
printf("%d", a);
}
#include
#include
#include
int main(){
unsigned a=4146464646;
printf("a=%d \n",a);
exit(0);
}
输出:a=-148502650
4294967295 - 4146464646 = 148502650
正确
#include
#include
int main() {
unsigned int a;
a = 1 << 31;
printf("%ud", a);
}
在程序执行过程中值不会发生变化的量
整形常量 1 890
实型常量 1.2 3.14
字符常量:由单引号引起来的单个的字符或转义字符,如 :
‘\t’ ‘\n’ ‘\0’ ‘\015’(8进制) ‘\x7f’ (16进制)‘\018’(错误的表示!!)
字符串常量:由双引号引起来的一个或多个字符组成的序列,如:
“” “a” “abXYZ” “abc\n\021\010”(a b c \n \021 \0 1 8)
标识常量 :#define,处理在程序的预处理阶段,占编译时间;特点一改全改;缺点:不检查语法,只是单纯的宏体与宏名之间的替换。
#include
#include
#define PI 3.1415926
#define ADD 2+3
// 正确写法
//#define ADD (2+3)
int main() {
printf("%f\n", PI);
printf("%d\n", ADD * ADD);
}
#ifndef Tool1_H_
#define Tool1_H_
//如果没有Tool1_H_,那就define一个Tool1_H_
# 6 "pi.c"
int main() {
printf("%f\n", 3.1415926);
printf("%d\n", 2+3 * 2+3);
}
#include
#include
#define MAX(a,b) ({int A=a,B=b; ((A) > (B) ? (A) : (B));})
//define MAX(a,b) ((A) > (B) ? (A) : (B))
int main() {
int a = 3, b = 5;
printf("%d\n",MAX(a++, b++));//较大的值会自增两次
printf("%d\n",MAX(a++, b++));
}
#include
#include
//typeof函数获取a的类型
#define MAX(a,b) ({typeof(a) A=a,B=b; ((A) > (B) ? (A) : (B));})
int main() {
int a = 3, b = 5;
printf("%d\n",MAX(a++, b++));
printf("%d\n",MAX(a++, b++));
}
在程序的预处理阶段,占编译时间,不占运行时间(没有函数调用的消耗),但不检查语法(比较危险)
用来保存一些特定内容,并且在程序执行过程中值随时会发生变化的量。
[存储类型] 数据类型 标识符 = 值
TYPE NAME = VALUE
标识符:由字母,数字,下划线组成且不能以数字开头的一个标识序列。写标识符尽量做到见名生义。
数据类型:基本数据类型+构造类型
值:注意匹配
存储类型:
auto 默认 自动分配空间,自动回收空间。
register (建议型) 寄存器类型 只能定义局部变量,不能定义全局变量,大小有限制,只能定义32位大小的数据类型,比如double就不可以。因为寄存器没有地址,所以一个register类型的变量无法打印出地址查看或使用。
static (静态型) 自动初始化为0值或空值 并且static变量的值有继承性。另外常用来修饰一个变量或者函数(防止当前函数对外扩展)
#include
#include
void func() {
static int x = 1;
x++;
printf("%d\n", x);
}
int main() {
func();
func();
func();
}
2
3
4
变量的生命周期和作用范围
1.全局变量和局部变量 2.局部变量和局部变量 3.图片
#ifndef EXTERN_H__
#define EXTERN_H__
void func();
#endif
#include "extern.h"
extern int i; // 不定义 而是引用了其他地方的i
int func() {
printf("[%s]%d\n", __FUNCTION__, i);/*gcc自带的宏函数,当前所在的函数名*/
}
#include "stdlib.h"
#include "stdio.h"
#include "extern.h"
int i = 10;
int main() {
printf("[%s]%d\n", __FUNCTION__, i);
}
linux命令
vim * -p 打开当前目录所有文件
gt 或 gT 左右切换
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2TPlmFha-1693146368195)(E:\Git_study\LinuxC\C\image-20230729175127822.png)]
表达式与语句的区别
运算符部分:1.每个运算所需要的参与运算的操作数个数
2.结合性
3.优先级
4.运算符的特殊用法; 如:% 、==和=、 逻辑运算符(&&,||)的短路特性;
5.位运算的重要意义:将操作数中的第n位置1 其他位不变: num = num | 1 << n;// num | (1 << n)
将操作数中的第n位置0 其他位不变: num = num & ~(1< 测试第n位: if(num & (1< 应用 :小重点 将操作数中的第n位置1 其他位不变: num = num | 1 << n;// num | (1 << n) 将操作数中的第n位置0 其他位不变: num = num & ~(1< 测试第n位: if(num & (1< 从一个指定宽度的数中取出其中的某几位: 比如对于1101, 你要第二位(1) 1101 & 0100 = 0100 0100 >> 2 = 01 = 1 假设 i = B1100 =12 ~i --> B0011; i >> 1 --> 110 =6; 110 << 1 --> 1100 = 12; input & output -> I/O(标准IO,文件IO) 格式化输入输出函数:scanf,printf int printf(const char *format, …); format:“%[修饰符] 格式字符” 参照图片标准输出修饰符与输入输出格式字符。 int scanf(const char *format, …);//省略的是地址表 format:抑制符* scanf 在使用 字符输入输出函数:getchar,putchar 字符串输入输出函数:gets(!),puts gets非常危险,不要用,用fgets()或者getline()来代替 正确写法 scanf 在使用 scanf 在循环中使用的时候要特别小心 处理换行 //逗号表达式的值,去最后一个表达式的值。 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g6eXxCz3-1693146368196)(E:\Git_study\LinuxC\C\watermark,type_ZmFuZ3poZ34.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WK54bbMQ-1693146368196)(E:\Git_study\LinuxC\C\watermark,type_ZmFuZ34.jpg)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bLNSby8N-1693146368196)(E:\Git_study\LinuxC\C\20210816235525146.png)] 此时的执行结果为: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aE4geTmN-1693146368197)(E:\Git_study\LinuxC\C\20210816235600523.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ltbZY2r2-1693146368197)(E:\Git_study\LinuxC\C\20210817215700216.png)] 构造类型之一,连续存放 [存储类型] 数据类型 标识符[下标] 不初始化,全部初始化,部分初始化,static c对数组不进行越界检查,需要格外小心 定义,初始化:[存储类型] 数据类型 标识符 【行下标】【列下标】 3.存储形式:顺序存储,按行存储 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WOMyIF0s-1693146368197)(E:\Git_study\LinuxC\C\image-20230805104538945.png)] a[2][3] = b[3] + c[3] [存储类型] 数据类型 标识符 [下标]… 单个字符初始化;用字符串常量初始化 注意部分初始化的时候,尾部会自动初始化为’\0’;这个出错的情况是不确定的,例如如果有一个变量的地址刚好在str[N]的后面,你的输出也没问题,但是那个变量的内容就被改了,之后再访问那个变量就是乱码,又如你的输入特别长,遇到一块不可写的内存,会段错误 输入输出:scanf 无法获取带有分隔符的字符串( 单词统计 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vx8JTCL3-1693146368198)(E:\Git_study\LinuxC\C\image-20230806194815821.png)] 64位环境 指针类型占用8个字节 变量是对某块内存的抽象表示 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kqD75Uzq-1693146368198)(E:\Git_study\LinuxC\C\image-20230806201226144.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6G4zkOLt-1693146368198)(E:\Git_study\LinuxC\C\image-20230812102659888.png)] & * 关系运算 ++ – [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gADMCmqT-1693146368198)(E:\Git_study\LinuxC\C\image-20230814213143790.png)] 先看到指针就是指针 先看到常量就是常量 如何区分指针常量和常量指针,看const在后还是前,*在前指针常量,*在后常量指针 指针数组排序 没啥好说的 数据类型 函数名 (【形式参数说明表】) 【形式参数说明表】:数据类型 形参名,数据类型 形参名,… [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TXzWpZNh-1693146368199)(E:\Git_study\LinuxC\C\image-20230816205029075.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3pHCy7Y-1693146368199)(E:\Git_study\LinuxC\C\image-20230819145110344.png)] 函数指针 如:int ( *p )(int); [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oR439BUl-1693146368199)(E:\Git_study\LinuxC\C\image-20230819182222168.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iVDeSlGb-1693146368199)(E:\Git_study\LinuxC\C\image-20230819182303198.png)] 函数指针数组 如:int (* arr[N]) (int); [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-satfjstC-1693146368200)(E:\Git_study\LinuxC\C\image-20230819184022607.png)] 指向指针函数的函数指针数组 实际例子 描述复杂的数据类型 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jh6zStHz-1693146368200)(E:\Git_study\LinuxC\C\image-20230822212958596.png)] N选一 多个成员共用一块空间 取最大的成员的类型大小作为共用体的类型大小 ; 别名:联合体; 同结构体 可以互相嵌套 成员引用: 32位的无符号数的高16位和低16位相加 另一种写法 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DlLwqg4a-1693146368200)(E:\Git_study\LinuxC\C\image-20230826131938301.png)] malloc calloc realloc free 原则:谁申请谁释放,在同一模块成对申请释放,就像IO的使用一样 动态数组 内存申请与函数传值 typedef(type define):为已有的数据类型改名 typedef 和 define 的区别,一个别名一个是替换 数组 结构体 函数 指向指针函数 工程管理 依赖管理 $^ 表示在上一句依赖关系中被依赖的所有文件 % 表示同一个名字 typedef 和 define 的区别,一个别名一个是替换 数组 结构体 函数 指向指针函数 工程管理 依赖管理 $^ 表示在上一句依赖关系中被依赖的所有文件 % 表示同一个名字逻辑运算符的短路性
#include
sizeof
#include
位运算
int i = B1100;
int j = B1001;
i | j
1100
| 1001
---------
1101
i & j
1100
& 1001
---------
1000
i ^ j
1100
^ 1001
---------
0101
if i=B1000
int i=i|1<<2
1000
| 100
---------
1100
从一个指定宽度的数中取出其中的某几位:
比如对于1101, 你要中间两位
1101 & 0110 = 0100
0100 >> 1 = 010 = 10
IO
%s
的时候要特别小心,已经越界却不报错,放在循环结构中要注意能否接收到正常有效的内容。
变长参数
int main() {
int i = 123;
printf("%4d\n", i);
int d=65;
printf("%c\n",d);\\A
float f = 1.23455;
printf("%.3f\n", f);
char* s= "helloworld";
printf("%10.5s\n", s);
}
//定参 变参
刷新缓冲区
int main() {
printf("[%s:%d] before while().", __FUNCTION__, __LINE__);
while(1);
printf("[%s:%d] after while().", __FUNCTION__, __LINE__);
}
/n还有刷新缓冲区的意思,
__LINE__打印该语句行号
exit()会刷新io流
#include
int main() {
int i;
scanf("%d", &i);
printf("%d\n", i);
}
//空格 回车 tab键
%s
的时候要特别小心,已经越界却不报错#include
int main() {
int ret = 0;
int d = 0;
while(1) {
ret = scanf("%d", d);//加scanf返回值的校验
if (ret == -1) {
perror("Error enter");
break;
}
printf("%d\n", d);
}
exit(0);
}
int main() {
int i = 0;
char c = 0;
scanf("%d", &i);
scanf("%*c%c", &c);//%*c,抑制符用法
// 或者
//getchar();
//scanf("%c", &c);
printf("i = %d, c = %c", i, c);
}
10是换行符号,32是空格的ASCII码
流程控制
1.goto语句(慎用)
goto语句是一种无条件转移语句,goto 语句的使用格式为:
goto 语句标号;
其中语句标号是一个有效的标识符,这个标识符加上一个 ":" 一起出现在函数内某处,执行goto语句后,程序将跳转到该标号处并执行其后的语句;
另外语句标号必须与goto语句同处于一个函数中,但可以不在一个循环层中;通常goto语句与if条件语句连用,当满足某一条件时,程序跳到标号处运行;如下例子:
#include
3.switch语句
switch的语法格式为:
switch (表达式)
{
case 常量1:语句1
case 常量2:语句2
...
default: 语句n+1
}
注意:
1)switch后面括号内的表达式,其值类型应该为整数类型,包括字符型;
2)可以没有default语句,此时流程转到switch语句的下一条语句执行;
3)每一个分支语句后一般都要加一条break语句,用来跳出switch语句块,最后一个分支可以不加;如将上面的例子改为:
这是因为分支后的常量表达式只会匹配一次,匹配成功后就会执行该分支后的所有语句,如果不加break,则会将后面所有分支的语句执行完!!
4)多个 case 分支可以共用一组执行语句,如下:
case 'A':
case 'B':
{
printf....
}
4.while循环
语法格式:
while (表达式)
{
语句
}
5.do...while循环
语法格式:
do
{
语句
}while(表达式);
与while不同的是,do..while的循环体至少会被执行一次
6.for循环
语法格式:
for ([表达式1];[表达式2];[表达式3])
语句
break和continue
break用于终止当前层次的循环,而continue用于结束本次循环,转入下一次循环
数组
一维数组
初始化
static int a[10];//会初始化为全零元素
int a[3] = {1, 2, 3};
元素引用
数组名
数组名是表示地址的常量,也是数组的起始位置。
#include
数组越界
练习
#include
#include
#include
二维数组
2.元素引用:数组名【行标】【列标】
int main() {
int a[M][N] = {1, 2, 3, 4, 5};//合法
int b[][N] = {1, 2, 3, 4, 5};//合法
int c[M][] = {1, 2, 3, 4, 5}; // 错误
for (int i = 0;i < M;i++) {
for (int j = 0;j < N;j++) {
//printf("%d ", *(a+i+j*));
printf("%p-->%d",&a[i][j],a[i]a[j]);
}
}
}
//数组没初始化,就是没往里面写值,原来每位的电平是啥就是啥
//a+1 看作: 归属为a的一维数组的基本元素的1个单位长度
//行指针
深入理解二维数组
a[0] = b[0]
a[1] = c[0]字符数组
定义,初始化,存储特点
IO
\t
, \n
,
)常用函数
#include
多维数组
指针
32位环境 指针类型占用4个字节变量与地址
指针 == 地址 变量名 == 抽象出来的某块空间的别名指针与指针变量
int i = 1;
int *p = &i;
int ** q = &p;
直接访问与间接访问
i = 1;
&i = 0x2000;
p = 0x2000;
&p = 0x3000;
*p = 1;
q = 0x3000;
&q = 0x4000;
*q = 0x2000;
**q = 1;
//要翻译回来的,类型不一致了就翻译不回来咯
//指针类型用来使用数据时正确的分割内存单元
//不管什么类型几级的指针,它在某一平台所占的内存大小是确定的
空指针与野指针
void func(){
int *p=NULL;
printf("%d\n",*p);
}
空类型
char *s = "hello";
void *i = s;//不确定什么类型就用void空类型
定义与初始化的写法
指针运算
指针与数组
指针与一维数组
#include
p++
!= p+1
#include
指针与二维数组
#include
#include
指针与字符指针
#include
const与指针
首先,来看看const的基本含义。在 C/C++ 语言中,const关键字是一种修饰符。所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码。就 const 修饰符而言,它用来告诉编译器,被修饰的这些东西,具有“只读”的特点。在编译的过程中,一旦我们的代码试图去改变这些东西,编译器就应该给出错误提示。
所以,const修饰符的作用主要是利用编译器帮助我们检查自己代码的正确性。我们使用const在源码中标示出“不应该改变”的地方,然后利用编译器,帮助我们检查这些地方是否真的没有被改变过。如果我们不小心去修改了这些地方,编译器就会报错,从而帮助我们纠正错误。使用const和不使用const,对于最终编译产生的代码并没有影响。
虽然const对于最终代码没有影响,但是尽可能使用const,将帮助我们避免很多错误,提高程序正确率。
const float pi = 3.14; // 常量化变量
const int* p;//常量指针
int const *p;
char *strcpy(char *restrict dest, const char *src); // src是源字符串 不应该被修改
int *const p;
const int *const p;
//const int *const p;常量指针常量
指针数组与数组指针
指针数组
//我的理解,无论是指针数组(数组),数组指针(指针)强调的都是后者
// 【存储类型】 数据类型 * 数组名 【长度】
//int *arr[3]--》type name;-->int *[3] arr;
int *arr[3]
#include
数组指针
// 【存储类型】 数据类型 (*指针名)【下标】 = 值
//int (*p)[3];--》type name;-->int[3] *p;
//这样指针移动一次的距离就是一个数组的大小;
int a[2][3] = {{1, 2, 3},{ 4, 5, 6}};
int (*p)[3] = a;
#include
多级指针
函数
函数的定义
#include
函数的传参
函数的调用
#include
#include
#include
函数与数组
#include
#include
函数的指针
// 类型 * 指针名 (形参);
//如: int * fun(int);
#include
类型 (*指针名)(形参)
类型 (*数组名[下标]) (形参)
int *(*funcp[N])(int);
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void *),
void *restrict arg);
构造类型
结构体
1 产生及意义
2 类型描述
struct node_st{
type1 name1;
type2 name2;
...
};
3 嵌套定义
struct day {
int H;
int M;
int S;
};
struct student_st{
char *name;
struct day day;
};
4 定义变量(变量,数组,指针) 初始化以及成员引用
//成员引用:变量名.成员名; 指针->成员名
// (*指针).成员名
struct A {
int i;
char c;
float f;
};
int main() {
// TYPE NAME = VALUE;
struct A a = {123, 'A', 2.22}; // 初始化
struct A a_ = { .c = 'A', .f = 2.22}; // 部分初始化
struct A *ap = &a_; // 部分初始化
//还可以定义结构体数组
printf("%d %c %.2f\n",a.i, a.c, a.f); // 成员引用
// 123 A 2.22
printf("%d %c %.2f\n",a_.i, a_.c, a_.f); // 成员引用
// 0 A 2.22
printf("%d %c %.2f\n",,(*ap).i, ap->c, ap->f); // 成员引用
// 0 A 2.22
}
占用内存空间大小
addr % sizeof(type)
不能整除的话就要继续往下偏移//结构体里的元素会对齐,不能整除的话就要继续往下偏移
#include
共用体
产生及意义
类型描述
union test_un{
int i;
float f;
double d;
char ch;
};
嵌套定义
定义变量 初始化以及成员引用
#include
#include
占用内存空间大小
函数传参(值,地址)
位域
union {
struct {
char a:1;
char b:2;//2位
char c:1;
}x;
char y;
}w;//该共用体一个char型一个字节大小
int main() {
w.y=6;
printf("%d\n", w.x.b);//-1
exit(0);
}
枚举
enum 标识符{
成员1,
...
};
enum dar {
MON = 1,//取了第一个值,后面的值会顺次增加
TUS, //2
WEB,
THR,
FRI =1,
SAT, //2
SUN,
};
int main() {
enum day a = FRI;
printf("%d\n", a);
}
enum status {
STATE_RUNNING = 1,
STATE_CANCELED,
STATE_OVER,
};
struct job {
int id;
int state;
time_t start, end;
};
int main() {
struct job_st job1;
switch(jobs.state) {
case STATE_RUNNING:
// TODO
break;
case STATE_CANCELED:
// TODO
break;
case STATE_OVER:
// TODO
break;
default:
abort();
}
}
动态内存管理
// void *malloc(size_t size);
// void free(void *ptr);
// void *calloc(size_t nmemb, size_t size);
// void *realloc(void *ptr, size_t size);
#include
#include
#include
free的理解
#include
typedef
typedef type typename
//typedef 已有的数据类型 新名字;
typedef int INT
int main() {
INT i = 9;
}
#define IP int *
type int *IP;
int main() {
// #define
IP p, q;
int *p, q; // 一个int * 一个int
// typedef
IP p, q;
int *p, *q; // 两个int *
}
typedef int ARR[6]; // int [6] 改名为 ARR
ARR a; // int a[6];
typedef struct {
int i;
float f;
}NODE, *NODEP;
//typedef int FUNC(int);--> int(int) FUNC;
//FUNC f; --> int f(int);
typedef int *FUNC(int);
FUNC p; -->int *p(int);
typedef int* (*FUNCP)(int);
//FUNCP p; --> int *(*p)(int);
Makefile
mytool:main.o tool1.o tool2.o
gcc main.o tool1.o tool2.o -o mytool
main.o:main.c
gcc main.c -c -Wall -g -o main.o
tool1.o:tool1.c
gcc tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
gcc tool2.c -c -Wall -g -o tool2.o
clean:
rm *.o mytool -rf
OBJS=main.o tool1.o tool2.o
CC=gcc //默认就是gcc
mytool:$(OBJS) //替换语法
$(CC) $(OBJS) -o mytool
main.o:main.c
$(CC) main.c -c -Wall -g -o main.o
tool1.o:tool1.c
$(CC) tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
$(CC) tool2.c -c -Wall -g -o tool2.o
clean:
$(RM) $(OBJS) mytool -r
//rm -f
$@ 表示在上一句依赖关系中依赖项的目标文件CFLAGS+=-Wall -g -c //GCC编译选项CFLAGS参数
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
main.o:main.c
$(CC) $^ $(CFLAGS) -o $@
tool1.o:tool1.c
$(CC) $^ $(CFLAGS) -o $@
tool2.o:tool2.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r
CFLAGS=-Wall -g -c
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
//通配符
%.o:%.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r
- **free代表着变量p不再拥有原来指向内存空间的引用权限**
- **free后最好马上将指针置NULL**
# typedef
`typedef type typename`
typedef(type define):为已有的数据类型改名
```c++
//typedef 已有的数据类型 新名字;
typedef int INT
int main() {
INT i = 9;
}
#define IP int *
type int *IP;
int main() {
// #define
IP p, q;
int *p, q; // 一个int * 一个int
// typedef
IP p, q;
int *p, *q; // 两个int *
}
typedef int ARR[6]; // int [6] 改名为 ARR
ARR a; // int a[6];
typedef struct {
int i;
float f;
}NODE, *NODEP;
//typedef int FUNC(int);--> int(int) FUNC;
//FUNC f; --> int f(int);
typedef int *FUNC(int);
FUNC p; -->int *p(int);
typedef int* (*FUNCP)(int);
//FUNCP p; --> int *(*p)(int);
Makefile
mytool:main.o tool1.o tool2.o
gcc main.o tool1.o tool2.o -o mytool
main.o:main.c
gcc main.c -c -Wall -g -o main.o
tool1.o:tool1.c
gcc tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
gcc tool2.c -c -Wall -g -o tool2.o
clean:
rm *.o mytool -rf
OBJS=main.o tool1.o tool2.o
CC=gcc //默认就是gcc
mytool:$(OBJS) //替换语法
$(CC) $(OBJS) -o mytool
main.o:main.c
$(CC) main.c -c -Wall -g -o main.o
tool1.o:tool1.c
$(CC) tool1.c -c -Wall -g -o tool1.o
tool2.o:tool2.c
$(CC) tool2.c -c -Wall -g -o tool2.o
clean:
$(RM) $(OBJS) mytool -r
//rm -f
$@ 表示在上一句依赖关系中依赖项的目标文件CFLAGS+=-Wall -g -c //GCC编译选项CFLAGS参数
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
main.o:main.c
$(CC) $^ $(CFLAGS) -o $@
tool1.o:tool1.c
$(CC) $^ $(CFLAGS) -o $@
tool2.o:tool2.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r
CFLAGS=-Wall -g -c
OBJS=main.o tool1.o tool2.o
CC=gcc
mytool:$(OBJS)
$(CC) $^ -o $@
//通配符
%.o:%.c
$(CC) $^ $(CFLAGS) -o $@
clean:
$(RM) $(OBJS) mytool -r