目录 
C语言笔记 
视频 
https://www.bilibili.com/video/BV1vs411n7TH
编译全过程 
主要是分4步
1.预处理
宏定义展开,头文件展开,去掉注释,条件编译
bash
gcc -E main.c -o main.imain1.c 文件内中就是包含我们所有导入的库的代码 
2.编译,
检查语法,把语言编译成汇编语言
bash
gcc -S  main.i -o main.s3.汇编
这一步是把main2.s 汇编代码转换成二进制文件
bash
gcc -c main.s -o main.o4.链接
bash
gcc main.o -o main会生成一个main.exe 文件
一次编译
bash
gcc -o main.exe main.c main .c基本语法 
c
// 常量 第一种
const int i  = 10; 
// 注意,在c语言中,const 不安全
// 常量第二种
// 定义宏变量
//在主函数外面定义
#include <stdio.h>
#define PI 3.12323
// 不需要加等号,和分号
void main(){
    // f 会保留6位小数.并且四舍五入
    printf("%f",PI);
}输入 
c
#include <stdio.h>
void main(){
    int a;
    scanf("%d",&a);
    printf("%d",a);
}易错点 
c
float a = 4.5e0;
double c = .288;
 
double c = 288.;科学表示法 
分为三部分
() e ()
📌第一部分
()为一个浮点型, 第二个部分是e ,第三部分()为一个十进制的整数,可以是正数和负数,并且如果是正数,+号可以省略
格式化输出 
%3.2f 标识保留2位小数,并且会四舍五入 ,3表示整体的宽度,不足3个宽度空格填充,小数点也算一个宽度
%s 输出字符串
注意字符串末尾自带一个\0 而 %s 会一直输出字符串的字符,直到找到\0为止
%6f 代表小数整体宽度为6个,包含小数点,不足6位,在最后填0
%6.3f 代表整体宽度为6,包含小数点,如不足6位,在开头填充空格,为啥填充0,是因为小数点后的位数被锁定了
字符串 
字符串输入 
c
void main(){
    //gets 可以接收空格
    char buff[100];
    gets(buff);
    printf("%s\n",buff);
    // scanf 的%s 默认是不能接收空格  但是可以使用正则表达式达到接收空格的效果
    scanf("%s",&buff);
    printf("%s\n",buff);
    
    // fgets 是安全的 不会出现溢出错误,如果超出数组长度,则只接收数组长度-1的字符串
     fgets(buff,sizeof(buff),stdin);
    printf("%s",buff);
}字符串输出 
c
void main(){
    // puts 自带一个\n 并且也是读取到\0 后停止
    char string[] = {"dsadsa"};
    puts(string);
    printf("%s\n",string);
    
    fputs(string,stdout);
}字符串长度 
c
#include <string.h> 
char string[] = "hello";
char string1[100] = "hello";
int size = sizeof(string);
int size1 = sizeof(string1);
unsigned int len = strlen(string);//注意要导包 <string.h> 
printf("%d\n",size);// 6 因为如果是没有声明长度的就是字符串数组,默认末尾有一个\0  所以长度是6
printf("%d\n",size1); //100   因为声明的长度是100 所以就是100
printf("%d\n",len); // 计算的是字符串的长度关于布尔型 
只有0才是false 其他都是true
指针 
指针类似于Java的对象内存地址
声明指针 
c
int *num = 10;
printf("%d",*num);通过使用*变量名 可以获取指针所指向的值
c
int i = 10;
int *num = &i;
// & 表示取地址值,把i变量的地址值赋予给num 指针,这样,num指针 指向得就是10
printf("%s",*num); //10数组 
c
int array[3] = {12,23,45};
int *num = array;  // 此时num 为指向数组的一个数组指针  默认指向第一个值
printf("%d",*num);// 输出 12  第一个值
printf("%d",*array);// 输出12 数组默认就是一种指针类型 默认指向第一个
printf("%d",*(num+1)); // 指针计算  单独的没有加* 号的数组指针 表示的是数组的第一个值得地址,也就是索引值,加1 并不是地址加1,而是内存地址+所占用字节数,int 为4个字节,所以会加4  最后输出得值为 23指针可以为任意内容,
下标越界可能不会报错 但是可能会读取到其他内存上的值
指针数组 
指数组里全是指针
c
int a = 16, b = 932, c = 100;
//定义一个指针数组
int *arr[3] = {&a, &b, &c};
int **p = arr; // 2个* 代表二级指针,
printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2)); // 16, 932, 100补充 指针数组的scan赋值操作
c
int ids[10];
char *names[10]={"","","","","","","","","",""};
for (int i = 0; i < 10; ++i){
    scanf("%d,%s",&ids[i],(names+i));//names+i 就是数组里的每一个指针
}
for (int i = 0; i < 10; ++i){
    printf("%d,%s\n" ,ids[i],(names+i));
}二维指针 
指向二维数组的指针
c
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };函数指针 
就是讲函数以指针的类型保存起来,方便后续调用 实用场景就是 回调函数
c
int max(int a,int b){
    return a>b?1:0;;
}
void main(){
 //返回值类型 指针名称  参数类型  
    int (*pmax)(int, int) = max;
  // 括号不能省略
}返回值为指针类型 
c
char *strlong(char *str1, char *str2){
    if(strlen(str1) >= strlen(str2)){
        return str1;
    }else{
        return str2;
    }
}结构体 
类似于对象的操作
c
typedef struct user{
    int id;//4
    char name[1];//10
    int age;//4
} User; // User 相当于取一个别名
void main(){
    // 赋值操作,相当于new 了一个新的user 
    User user = {1,{},1};
    // 调用属性
    int id = user.id;
}使用关键字 typedef 可以为类型起一个新的别名。typedef 的用法一般为:
c
typedef  oldName  newName;
typedef int INTEGER;
INTEGER a, b;
a = 1;
b = 2;📌 如果想要在方法中去改变结构体的值,需要使用 结构体指针的操作
例如
c
int delete(Array *array,int index){
  // 获取结构体指针中的值
  array->next;  // 类似于array.next
}
void main(){
  ....
  // 需要传递地址过去
  delete(&array,1);
  
}文件 
| "r" | 以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。 | 
|---|---|
| "w" | 以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 | 
| "a" | 以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 | 
| "r+" | 以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。 | 
| "w+" | 以“写入/更新”方式打开文件,相当于 w和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 | 
| "a+" | 以“追加/更新”方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 | 
运算顺序 
| 优先级 | 运算符 | 结合律 | |
|---|---|---|---|
| 1 | 后缀运算符:[] () · -> ++ --(类型名称) | 从左到右 | |
| 2 | 一元运算符:++ -- ! ~ -(负号运算符) * & sizeof_Alignof | 从右到左 | |
| 3 | 类型转换运算符:(类型名称) | 从右到左 | |
| 4 | 乘除法运算符:* / % | 从左到右 | |
| 5 | 加减法运算符:+ - | 从左到右 | |
| 6 | 移位运算符:<< >> | 从左到右 | |
| 7 | 关系运算符:<<= >>= | 从左到右 | |
| 8 | 相等运算符:== != | 从左到右 | |
| 9 | 位运算符 AND:& | 从左到右 | |
| 10 | 位运算符 XOR:^ | 从左到右 | |
| 11 | 位运算符 OR: | 从左到右 | |
| 12 | 逻辑运算符 AND:&& | 从左到右 | |
| 13 | 逻辑运算符 OR: | 从左到右 | |
| 14 | 条件运算符:?: | 从右到左 | |
| 15 | 赋值运算符: | ||
| = += -= *= /= %= &= ^= | = | ||
| <<= >>= | 从右到左 | ||
| 16 | 逗号运算符:, | 从左到右 | 
格式化输出 
| 格式控制符 | 说明 | 
|---|---|
| %c | 输出一个单一的字符 | 
| %hd、%d、%ld | 以十进制、有符号的形式输出 short、int、long 类型的整数 | 
| %hu、%u、%lu | 以十进制、无符号的形式输出 short、int、long 类型的整数 | 
| %ho、%o、%lo | 以八进制、不带前缀、无符号的形式输出 short、int、long 类型的整数 | 
| %#ho、%#o、%#lo | 以八进制、带前缀、无符号的形式输出 short、int、long 类型的整数 | 
| %hx、%x、%lx | |
| %hX、%X、%lX | 以十六进制、不带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字也小写;如果 X 大写,那么输出的十六进制数字也大写。 | 
| %#hx、%#x、%#lx | |
| %#hX、%#X、%#lX | 以十六进制、带前缀、无符号的形式输出 short、int、long 类型的整数。如果 x 小写,那么输出的十六进制数字和前缀都小写;如果 X 大写,那么输出的十六进制数字和前缀都大写。 | 
| %f、%lf | 以十进制的形式输出 float、double 类型的小数 | 
| %e、%le | |
| %E、%lE | 以指数的形式输出 float、double 类型的小数。如果 e 小写,那么输出结果中的 e 也小写;如果 E 大写,那么输出结果中的 E 也大写。 | 
| %g、%lg | |
| %G、%lG | 以十进制和指数中较短的形式输出 float、double 类型的小数,并且小数部分的最后不会添加多余的 0。如果 g 小写,那么当以指数形式输出时 e 也小写;如果 G 大写,那么当以指数形式输出时 E 也大写。 | 
| %s | 输出一个字符串 | 
取值范围 
| 类型名称 | 字节数 | 取值范围 | 
|---|---|---|
| char | 1 | -128~127 | 
| short int 或 short | 2 | -32768~32767 | 
| int | 4 | -2147483648~2147483647 | 
| long int 或 long | 4 | -2147483648~2147483647 | 
