1.1 二进制指令—>汇编语言(一些助记符,例如英文字母)—>高级语言
1.2 编译器,编辑和翻译。编辑,即对代码进行剪切、复制一些文本操作;翻译,将代码翻译(变成计算机能够识别的语言,还需要链接器)
2.第一个C语言程序2.1 函数分为两部分,函数头和函数体。函数头又由声明、函数名和输入参数组成。int 声明函数返回类型,同时申请int类型数据所占空间大小(int,4个字节);函数名,整个项目只能有一个main函数,而且整个项目的代码都是从main函数开始;输入参数,一开始也是要先声明。
2.2 main()里面无参数(或者由viod),这表示不用输入参数。如果有的函数名前面有viod,表示可以不用有输出
2.3 stdio.h 为标准输入输出库文件。std:standard;i:input;o:output. 使用scanf(输入函数)也需要引此文件
#include3.数据类型int main() { printf("hello") return 0; }
3.1 C语言中没有字符串类型。字符串,也就是由单个字符组成。这matlab不一样,matlab中字符串是作为一个整体存在,而字符组成的叫做字符数组
3.2 计算机存储字符是以ASCiLL码存储的
4.变量和常量4.1 定义变量。定义变量的第一步就是先定义变量,即申请空间,而这个空间的名字就是变量名。“=”后面是常量,即把常量存储在名叫变量名的空间中。在C语言中,使用变量的第一步就是先声明变量(也是说先申请空间)。定义变量的同时也初始化了变量,如果指定一个值,那就是把指定的值存储进去,如果定义时不指定,系统会随机指定一个值放进去。
int a=0;
4.2 在同一个{}中,同一个变量不能重定义,即变量名不能被定义两次,即使是被不同数据类型所定义。
// 这不算在同一{}中
{
int a=0;
{int a=1;} //这有点类似全局变量和局部变量的关系
}
// 重定义
{
int a=0;
char a='e'; //这也算重定义
}
4.3
- 局部变量:{}内部所定义。
- 全局变量:所有的{}外部所定义。全局变量,一个源文件定义后,可以在同一项目的其他的源文件使用,但需要先声明
test1.c
int a=0;
{
}
test2.c
extern int a //后面的数据类型和变量必须和全部变量被声明保持一致
4.4 变量名是个标识符,但有时可以表示地址。scanf和printf函数,会在缓存区读取数据。
- int a 变量a就是个标识符。
- char a[] 变量a可以表示地址。
4.5
- 全局变量的作用域是整个项目,而生命周期是整个项目
- 局部变量的作用域是变量所在的局部范围。而生命周期可能大于作用域,即不是从作用域出来后就被销毁了(用static修饰的变量)。
4.6 常量
- #define定义的标识符常量
#define max 10; #define max “scaklhj”5.字符串、转义字符和注释
5.1 字符串,自动以 结尾,而这个 是我们敲完字符串时,系统自动帮我们加的
char a='asdf';//系统自动输入 sizeof(a); //我们会得到a所占空间大小是5个字节,因为 算一个字节。 strlen(a); //结果为4,strlen和printf都是遇到 就停,只看表面,而sizeof是计算所占空间大小的
5.2
- ddd 表示八进制的数字,d的个数不限,但不能超过8(8进制最大是7)
- xdd表示十六进制的数字
- 空格也算字符
5.3
- %f float
- %lf double
- %zu 打印sizeof()返回的值,也可以用%d
6.1 数组:一组相同类型元素的组合
int arr1[]={0} // []没有数(不分配空间),当后面赋值后,会自动分配空间,这里就自动分配4个字节的空间
int arr2[2]={0} // [2]代表2个元素,但后面只有一个数,则系统会自动补充0到数组里面
char arr3[]={'0'}
char arr4[2]={'0'} // 系统会自动补充
double arr5[]={0}
10 操作符
11 关键字
- 除号的两端都是整数时,执行的是整数除法,如果两端只要有一个浮点数就执行浮点数的除法
float a=10.876; printf("%10.1f",a); //"10.1f"是指宽度为10,且保留小数点后1位(四舍五入),如果变量宽度不够,则前面补空格 //如果给的宽度小于变量的宽度则会自动增加宽度,能够正好符合变量的宽度。 //".1f"会根据变量的宽度自动调整
取模操作符两个操作符只能是整数
初始化:创建变量的同时给变量一个值
int a=10;//初始化 a=20; //赋值单目操作符:只有一个操作数的操作符
int a=10; printf("%d",sizeof(a)); //sizeof是个单目操作符,后面可以跟变量也可以跟变量类型 printf("%d",sizeof(int)); printf("%d",sizeof a); //因为sizeof是单目操作符,所以后面可以不加括号直接跟变 printf("%d",sizeof int); //量名,但不可以直接跟数据类型
(数据类型):强制类型转换
int a=3.14; //3.14 这种字面浮点数,编译器默认理解为double类型 int a=(int) 3.14; //3.14强制转换成整形逗号表达式:逗号隔开的一串表达式
- 特点:从左到右依次计算,整个表达式的结果是最后一个表达式的结果
int a=20; int b=3; int c=5; inr d=(c=a-2,a=b+c,c-3);
下标引用操作符
int arr[10]={3}; arr[3]; //[]就是下标操作符,arr和3就是[]的操作符 int n=3; arr[n]=10; //[]是操作符,里面可以放变量,当定义arr时,[]是定义语法的一种 //形式,所以里面需要放常量
-
typedef
类型定义。即类型重命名
typedef unsigned int unite_32 // 给unsigned int(无符号整形)重新起了个名字,叫做unite_32
-
static
修饰局部变量。该变量被修饰后,叫做静态局部变量。
- 改变变量的生命周期,让静态局部变量除了作用域依然存在,直到程序结束,生命周期才结束
- 将原本存在栈区的局部变量,存到静态区。(静态区一般存储全局变量和静态变量)
修饰全局变量
- 被修饰后,使得这个全局变量只能在本源文件被使用
- 全局变量具有外部链接属性和内部链接,一旦被static是修饰后,外部链接属性就被消除了,只剩下内部链接属性
修饰函数
- 被修饰后,使得这个函数只能在本源文件使用,不能在其他源文件内使用
- 函数具有外部链接属性和内部链接,一旦被static是修饰后,外部链接属性就被消除了,只剩下内部链接属性
-
const:常属性
一个变量一旦被const修饰后,后面就不能该变,但可以在初始化的时候改变.使得这个变量具有了常属性,本质还是变量
const int a=1; //如果想改变,可以从在初始化的地方改变 a=2; // a的值不会被改变
-
extern:声明外部符号的.即在其他源文件定义的
如果一个在其他源文件定义的函数,或者全局变量,如果想被目标源文件使用,必须先声明
test1.c int add(int x,int y) int a;//a是全局变量 test2.c extern int a; extern int add(int x,inty);
#define max 100 //定义常量 #define add(x,y) ((x)+(y)) //定义宏。add:宏名;x,y:参数;((x)+(y)):宏体 //参数可以是任意类型13 指针
// 用指针和不用指针加一的区别(针对数组)
int arr[2] = {0};
int* p1 = arr;
int* p2 = &arr;
printf("%pn", p1; //指针的类型决定了指针向前或向后走一步有多大(字节)
printf("%pn", p1+1); //int型指针,+1就是向前走四个字节,所以第二个和第四
printf("%pn", p2); //个输出相等
printf("%pn", p2+1);
printf("%pn", arr); //这里没有把运用指针就直接打印,而且加1,这里向前或向后加
printf("%pn", arr+1); //加一,取决于数组名前面是否有&,有&代表&arr是整个数组的
printf("%pn", &arr); //地址,加一,要前进整个数组大小的字节;没有&则是数组首元
printf("%pn", &arr+1); //素的地址,加一,取决于这个数组的类型,整型数组则前进4
控制语句
- C语言的三种基本结构
顺序结构
选择结构
循环结构
-
if 后面如果想跟多条语句,后面必须加{}。;代表一条语句语句的结束。{}里面也会有许多以;结尾的语句,但对于整个程序来说,{}是if的一条语句,if{}else{}又是整个程序的一条语句
-
1010&&age<20 这是如果age=5因为先判断5>10为逻辑假0,0<20,为逻辑真,所以10
-
控制语句整体,算一条语句 if {}else{} 是一条语句
-
else与离它最近的if匹配
-
程序到return后,就代表结束该部分程序,不是结束整个程序,有返回值,这块程序就结束了
-
当拿一个变量(单纯的变量)判断是否等于一个常量,可以让常量放在前面,3==a
-
表达式不能赋值 变量就只是个变量 不要变形
num%2==2 //num%2是个表达式,不能被赋值,不用写成2=num%2
-
code
//判断一个数是否为奇数
int num= 0;
scanf("%d",&num);
if ( num % 2==1) {
printf("奇数");
}
else {
printf("不是奇数");
}
//输出1—100之间的奇数
int i = 0;
for (i = 0; i <= 100;i++) {
if (i % 2 == 1) {
printf("%d",i) }
}
// switch语句
//switch (整型表达式){
//语句项;
//}
//语句项:是一些case语句
//case 整型常量表达式(字符也可以,字符也属于整型)
//语句;
//这个语句有两种形式
//1:表达式;
//2:控制语句(控制语句整体算是一个语句相对于整个程序)。控制语句有两种形式,有时用{},有时不
//用,7但要当成一个整体 !
- 在循环中,continue会跳过本次循环,也会跳过continue后面的语句
int ch=getchar(); //获取字符 putchar(ch) //打印字符
-
敲入回车键就是输入n 敲入回车键 才把字符输入缓存区 而scanf是只要缓存区有字符,就会读取
-
输入n(就是回车键) 默认输入完毕
-
内存缓存区,在程序执行完后,即出int main{}后就被清空,在程序没结束之前内存区有多少字符,scanf函数和getchar函数就得按顺序读取字符
-
当用scanf和getchar函数获得输入时,最后需要敲一下回车键,这是回车键有三个作用
-
1 换行输出
-
2 将键盘输入的字符传到内存缓存区
-
3 将换行字符一同传到缓存区。scanf会把换行符当成空白字符,而getchar会把换行符存到变量
-
一旦敲回车键,scanf会立马读取
-
scanf函数遇到空白字符,就会停止读取(读取数字时,读取字符不会)
scanf("%4d %d %d",&a,&b,&c); // scanf会忽略空白字符 //输入:123 空格 12 回车 123 //当敲回车时,就把123 空格输入进了缓冲区,这时scanf就开始读取了,当读到3时,虽然还没读满4个数,但还是会停止,(scanf遇到空白字符就停止),然后接着从非空白字符读取下一个数字,赋值给b,而不是把空白字符拿走。对于字符串,拿走后,如果还有空间,自动补
-
-
getchar和scanf读到非打印字符时,会把相应的效果输入在窗口,比如ASCILL值 9 用putchar和printf显示时,会空4个格;ASCILL值 32
-
if 后面默认跟一条语句,如果想跟多条语句,可以加{}
-
for(i=0;i<10;i++)可以表示循环10次,如果i从0开始,建议i<10这样写
-
for(; ;)判断部分省略,判断部分恒为真
-
初始化部分最好不要省略
-
=是赋值,==是判断
-
if 中的continue满足条件 会跳过的代码
do { if (i==5) continue; // 当i=5时,continue会跳过后面的代码 i++; // 所以,到4之后就会死循环 }while(i<10);- 在定义浮点数时,float通不过,可以尝试double
- int a=5/4 a会取整数部分,不是先得出小数部分,在取余,这是整数的除法,浮点数的除法是要先求出小数的 (这里将被除数或者除数变成浮点数,执行的就是浮点数的除法,即将5或者4变成5.0 4.0)
- for循环 里面只要有一个判断条件不满足,就结束循环
for (;L<=mid+3,R>=mid;L++,R--)
- 写程序最好写一部分,测一部分
- scanf(”%dn“)scanf在读取时会读完所有对应字符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-33iWmHrr-1652186920778)(C:Users20961AppDataRoamingTyporatypora-user-imagesimage-20220417220403133.png)]
4.19-
当不调用函数的时候,形参就不开辟空间
-
int arr[10]={0}; int p=arr; arr[2]=*(arr+2); *P=arr[0]=*(arr+0)// p代表的就是首元素的地址,不要把他看成变量名 // 一个变量名只有在定义的时候(即int p),表示是个名字,但在后面使用时,要把他看成p所代表的数据 -
void func(int* arr) { int b=sizeof(arr)/sizeof(arr[0]); // 在这里sizeof(arr)是首元素的地址,因为传进来的就是首元素的地址,则算的的首元素地址所占内存的大小 } int main() { int arr[10]={12}; int a=sizeof(arr)/sizeof(arr[0]); // 这里sizeof(arr),arr代表的是整个数组,计算的是数组所占空间空间的大小 } -
思考问题时,想的应该是内存里的数据,而不是谁代表数据,写的时候要把代表数据的变量名写出来,因为你不可能
把数据直接写出来,就像不可能把地址写出来,找个东西代表他,但简单的数据10,直接写出来就行,没必要
在找个变量来代表他
- 链式访问:把一个函数的返回值方程另一个函数的参数
- printf返回的是在屏幕打印字符的个数。23这是两个字符(’2‘和‘3’)
-
自己定义的函数文件使用时,就是用双引号,标准库文件就是尖括号
#include
// 标准 #include"add.c" // 自定义 -
模块化的意思就是把源文件分开写
包含头文件,相当于把头文件的内容拷贝过来
-
%d:打印有符号整数(会有正负数)
%u:打印无符号整数
-
每一个函数的调用,都要在栈区创建一个空间
-
压栈(push):给栈顶放一个元素
出栈(pop):从栈顶删除一个元素
栈顶指针:esp用来记录栈底的地址
栈底指针:edp
call:调用
寄存器是独立于内存的,集成到cpu的
十六进制后面要加h,在反汇编时
-
在调用函数之前先将实参压栈(临时拷贝,在main创建的栈帧外 ),再调用函数。在调用函数会马上创建栈帧而且不会再为形参申请空间是main函数增加栈帧
-
返回值时,是将值放在eax寄存器中 返回值时通过寄存器带回来的,没有在在栈区开辟空间
-
在变量创建创建空间,两个变量的空间位置一定紧紧挨着
-
正数的原码、反码和补码一样
负数的反码是符号位不变,其他位加取反,而反码加一就是补码
-
画红框中的意思如下,对a进行左移,并不会改变a的值
-
- 移位操作符只针对整数,不支持浮点数
- 无符号整数,可以看成正数
-
正数的原码、反码和补码是相同的,所以看到补码的符号位,可直接写出它的原码
-
int a=10; printf("%d",a--); // 打印10 int a=10; test(a--); //传进去也还是10 -
sizeof 是操作符,不是函数。如果是函数,sizeof a后面应该是(a)
-
"abc"=="abcsf";//这是在比较地址 //应该用strcmp();比较字符串
-
b=(a>b?a:b);将条件表达式用括号标起来
-
[]
// []是个双目操作符,左值和右值在某些情况下可以交换 // arr[7]和7[arr]是等同的,sizeof也是个操作符,可以看作和+ -一样的乘除,满足交换律 // 在定义数组时即,int arr[10]不能写成int 10[arr] //arr[7]-->*(arr+7)--->*(7+arr)--->7[arr] // arr就是首元素的地址 // arr+7就是跳过7个元素,指向第八个元素 // *(arr+7)就是8个元素
-
结构体传参,传值和传址
struct stu { char name[20]; int age; double score; }; void set_stu(struct stu ss) // 传值进去,编译器会在程序运行时,建立一个新的 { // struct stu ss 最后改变的是ss不是s // ss.name="sgj"; // ss.name是地址,不能以这样给数组赋值 //ss.name[20]="sgj";// 正确赋值,按照正常的赋值方法赋值就行 strcopy(ss.name,"sgj");// 正确赋值 ss.age=20; ss.score=100.0; } int main() { struct stu ={0}; set_stu(s); // 传值 print_stu(s); //传值 return 0; } // 传址 struct stu { char name[20]; int age; double score; }; void set_stu(struct stu* ss) // 传址进去,编译器会在程序运行时,改变的是s { // ss.name="sgj"; // ss.name是地址,不能以这样给数组赋值 strcopy(ss->name,"sgj");// 正确赋值 ss->age=20; // 传址进去,用->形式调用参数 ss->score=100.0; } void printf_stu(struct stu* ps) { printf("%s %d %lfn",ps->name,ps->age,ps->score); } int main() { struct stu s={0}; set_stu(&s); // 传值 print_stu(&s); //传值 return 0; } -
位操作符(只适用于整数)
-
&(按位与):只要有一个为零,对应位就为0
-
正数和负数的按位与,运算出来的数,在不溢出的情况下,结果是正数
-
|(按位或):只要有一个为1,对应位就为1
-
正数和负数的按位与,运算出来的数,在不溢出的情况下,结果是负数
-
^(按位异或):相同为0,相异为1
-
正数和负数的按位与,运算出来的数,在不溢出的情况下,结果是负数
-
(ab)a=b (ab)b=a 0^a=a a^a=0
异或支持交换律即353=335
-
-
sizeof :操作符
- 计算的是变量所占内存空间的大小
- 计算的是类型所创建的变量占据内存空间的大小,单位是字节
sizeof(int); sizeof(a); sizeof a;// 没有sizeof int
-
0可以看成正数,其反码为0000000000000000000(原反补一致)。~0为-1
-
~的应用:将二进制位的某一位进行修改
int a=13; // 补码:00000000 00000000 00000000 00001101 // 将1101前面的一位变成1 // 00000000 00000000 00000000 00001101 // |(按位或) // 00000000 00000000 00000000 00010000 1<<4 // = // 00000000 00000000 00000000 00011101 // 即a|=(1<<4) // 上面是将某一位变成1 // ----------------------------------------------------- // 将上面变成的位变回0 // 00000000 00000000 00000000 00011101 // &(按位与) // 11111111 11111111 11111111 11101111 // = // 00000000 00000000 00000000 00001101 // 11111111 11111111 11111111 11101111 // ^ // | //~(00000000 00000000 00000000 00010000) // ^ // | // 1<<4 // 即 a&=~(1<<4) // 这是将某位变成0
-
无符号整型提升,提升了精度,一般不会改变大小
-
char 类型所存储的数的范围:-128~127
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UiL5MDGD-1652186920780)(C:/Users/20961/AppData/Roaming/Typora/typora-user-images/image-20220510193303416.png)]
-
截断是从低位到高位截,即从右到左截
-
优先级是指相邻操作符
-
尽量写出唯一路径,或者加括号
-
算术运算符 + - * / %
赋值运算符 =
long a=4可能会整型提升,因为4是int型,存到long中,整型提升。但算术运算(上面的算术运算符),是以缺省值运行的
-
-
整型提升是按照变量的数据类型的符号位来进行提升的
-
操作数都要转成排名最高的数据类型
-
这告诉我们以后,尽量不去碰复杂表达式,宁愿多写点步骤,也不可为了方便写在一起
对于表达式,先从整体上来看,找出优先级最大的操作符,如果有若干个相同的操作符,系统并不能指定将这几个优先级相同的操作符,全部计算完,再计算次一级的操作符
不同的编译器有不同的规定,有的是全部算完,有的是先算一部分
// 例: // Vs2019 int a=1; int b=(++a)+(++a)+(++a); // 结果就是b=12 // 这里就是先将括号先计算完。值得注意的是,+操作符的的左操作数的获取 // 是在获取右操作数之后求值的 // Linux // 结果b=10 // 那这里就是先将前两个括号计算出来。值得注意的是,和Vs一样,+操作符的的左操作数的获取是在获取右操作数之后求值的
-
-
0xb6的二进制数是10110110,如果是写成32位就是00000000000000000000000010110110,因为a是char类型只能放八位,所以从左到右截断就是11111111,放到char类型的空间(也即1个字节),又因为char是有符号,所以存进去的最高位成了符号位,下面进行==操作时,会进行整型提升,因为最高位时是1,所以提升后的结果是11111111111111111111111111111111,所以成了负数。
-
启发:内存空间存的只是一串二进制序列,当程序有不同的要求,会将这些二进制序列转换成对应的符号,例如,printf(“%c”,a),系统就会把存在a中的二进制序列先进行整型提升,然后找对应的字符
-
short是2个字节
-
整型提升就是将存储的二进制序列进行精度提升
-



