break语句
关于break和continue,众所周知,break是跳出当前循环,continue是跳出本次循环。
但是在多重循环中,我们可能会模糊概念:break是跳出全部循环还是只是某层循环?–>跳出的是break所在层的循环即当前循环。
结论:只要记住,break和continue只对当层循环有用,对外层循环没有影响。
int main()
{
int i;
for(i=0;i<1;i++)
{
if(i==0)
break;
i++;
printf("在循环中%d",i);
}
printf("退出循环%d",i);
}
结果是退出循环
int main()
{
int i,j;
for(j=0;j<1;j++)
{
for(i=0;i<1;i++)
{
if(i==0)
break;
i++;
printf("在循环中%d",i);
}
printf("退出内层循环循环%d",i);
}
}
结果是退出内层循环
得出结论:break 结束一层循环
#include<stdio.h>
int main()
{
int a =1,b=2;
for(int i=0;i<3;i++)
if(a<b)
{
a++;
if(a==b)
break;
printf("1111");
}
printf("退出循环");
}
结果是退出循环
switch中的break
int main()
{
int b = 1;
int i;
for(i=0;i<1;i++)
{
switch(b)
{
case 1:
printf("nihao\n");
break;
}
printf("结束break\n");
}
printf("结束循环");
}
结果是nihao 结束break 结束循环
得出结论:break在循环中的Switch中只能结束Switch,不能结束循环
break只能用在循环和switch语句体内
goto语句可以用来退出多层循环,也可以用标签跳出
continue语句
#include<stdio.h>
int main()
{
int i,j;
for(j=0;j<1;j++)
{
for(i=0;i<5;i++)
{
if(i==0)
continue;
}
}
printf(" i是%d,j是%d",i,j);//i是5,j是1
}
结论continue跳过本次循环,接着下一次循环,i==0时continue 继续在执行内层循环,直到i==5结束内存循环,在执行外层循环
switch
概念:switch后面的括号只能是整形,字符型,枚举型,后面的括号只能有一个变量值,可以a+b
switch后面的case只能是常量或常量表达式
break
break语句应出现在switch语句和循环语句中。
break语句可以单独出现在循环中
只能在循环体内和switch语句体内使用break语句
continue
c语言中的continue语句可以通过改变程序的结构而忽略
逻辑运算
逻辑运算符的优先级 !&& ||
&&,||优先级低于关系运算符, !高于算术运算符
逻辑运算的短路现象
逻辑表示式是从左往右计算!!,一旦能过确定表达式的值就结束运算
1.4【C语言】运算符和表达式-逻辑短路性质(逻辑运算符)_哔哩哔哩_bilibili
逻辑与
int main()
{
int a = 15;
int b = 16;
printf("%d",a==16&&b==16);
}
结果为0 计算过程为 因为==的优先级大于逻辑运算符,所以先算a==16,结果为0,又因为&&要求全1为1,所以左边为0右边短路,不执行右边了,整个逻辑表达式结果为0。
逻辑或
int main()
{
int a = 15;
int b = 16;
printf("%d",a==16||b==16);
}
结果为1,逻辑或要求有1为1,所以即便左边为0,仍要计算右边,右边为1,整个逻辑表达式结果为1.
各种混合
int main() /*main函数*/
{
int a = 15;
int b = 16;
printf("%d",a<b&&a==16||b==16);
}
结果为1,逻辑与的优先级比或要高,又因为逻辑运算符自左向右的特性,所以(a<b&&a==16 ) ,注意这里加个括号不是因为逻辑与的优先级高一点所以我们要先算他!而是把这个表达式变为A||B或者A&&B的这种形式根据逻辑运算符自左向右的特性先算(a<b&&a==16 )得出0,因为是逻辑或,再往下算b==16
int main() /*main函数*/
{
int a = 15;
int b = 16;
printf("%d",a<b||a==16&&b==16);
}
逻辑与的优先级比或要高,又因为逻辑运算符自左向右的特性,所以(a==16&&b==16) ,注意这里加个括号不是因为逻辑与的优先级高一点所以我们要先算他!而是把这个表达式变为A||B或者A&&B的这种形式先算a<b得出1,因为是逻辑或,大短路,所以结果为1
大短路
int main()
{
int a=0,b=0,c=0;
if(++a||++b&&++c)
printf("%d,%d,%d\n",a,b,c);
}
结果是1 0 0
逻辑运算符自左向右的特性,把++b&&++c加上一个括号变成++a||(++b&&++c),就变成了A||B的形式,又因为自左向右的特性,先执行++a,得到结果为1,满足逻辑或的条件,后面的++b,逻辑与++c都不运行
例子
a=1,b=-1,c=0
a--+b==b<c&&++c
看作(a--+b==b<c)&&++c
因为有逻辑与运算符所以这是一个逻辑表达式,从左往右
先算a+b=1+-1=0,再算b<c为1,0==1 为0
这个表示变为了0&&++c,因为前面为0了,所以短路了。
关系运算符
1<x<2
上述是合法的表达式,但关系运算符是从左到右算,1<x得到0的话,0<2会造成死循环,所以经常会得不到想要的效果,一般都是x>1&&x<2
赋值运算符
x+=9+8//先算9+8,之后x = x+17
x-=9+8//先算9+8,之后x = x-17
x/=9+8//先算9+8,之后x = x/17
x%=9+8//先算9+8,之后x = x%17
自增自减运算符
a++;后置加加,先用a的值,表达式结束之后,在进行自增运算
#include<stdio.h>
int main()
{
int x = 6;
printf("%d", x +=(x++),++x);
}
先用x+x = 12,之后表达式结束,自增1,此时x是13,之后再进行++x运算,结果为14
tip:不要以为(x++)有括号就要把x算完!这是自增自减运算符
int i =1; ++(i+1);//这种是错误的,i+1就是2 就变成了++2
自增自减运算符要求操作数是变量
域宽
#include<stdio.h>
int main()
{
int a = 1234;
float b = 123.456;
float c = 12345.54321;
printf("%2d\n",a); //1234
printf("%2.1f\n",b);//123.5
printf("%2.1f\n",c);//12345.5
printf("%7.2lf",2.666);
//输出: 2.67(前有两空格记得要数小数点)
}
以%mf或%mlf 格式输出浮点数时,如果指定宽度大于实际数据宽度,则按指定宽度输出,且多余数补以空格;如果指定宽度小于实际数据宽度,浮点数的整数部分将以实际位数输出,小数部分按指定位数输出,且对数据做四舍五入处理。而输出整型数时,没有宽度限制的整数按原数输出;在宽度限制小于数的实际位数时,宽度说明无效,按数的实际位数输出。
默认右对齐,因为域宽2 所以在前面补空格
不数'\0'
printf("%3s","ab"); 空格ab
#include<stdio.h>
int main()
{
int i;
for(i=1;i<5;i++)
printf("%2d",i); // 1 2 3 4
}
负号左对齐,因为域宽2 所以在后面补空格
#include<stdio.h>
int main()
{
int i;
for(i=1;i<5;i++)
printf("%-2d",i);//1 2 3 4
}
long y = 423;
printf("%+5d",y);//空格+423printf("%-5d",y);//423空格空格
printf("%05d",y);//00423
+代表输出符号位
--
常量
分为直接常量和符号常量两种。
直接常量
直接常量又分为整型常量,实型常量,字符型常量和字符串常量。
整形常量
包括正整数、负整数和零。C语言中,整型常量可以用十进制、八进制和十六进制表示
八进制前缀是0,十六进制前缀是0x
注意不要和转移字符的前缀弄混
十六进制转义字符是\x,不是\0x
实型常量
实型常量即实数,又称为浮点数。C语言中,实数只能用十进制数表示,实数的表示方法有两种:小数形式和指数形式。
易错点
小数点前或后缺少数字的,也是合法浮点数. 比如: 0.0、.0、0.
但是前后都缺了,只有一个. , 不是合法的浮点数.
指数形式写作小写e与大写E都合法.不区分大小写.
e之前和之后必须有数字(不限制正负), 比如 12e,e12 不合法.,但是12e0合法.
且e之后的数字必须为整数. 比如: 12e3.14 不合法
1000.0与1e3 都是合法的浮点数 .
3.e-0 , .3e0 都是合法的
但是2e.4 , 2e-4. 不合法
口诀:e前后都要数字,后面的数必须为整数 .前或后必须要有数字
字符常量
字符常量指单个字符,单引号括起来
转移字符也属于字符常量
八进制转义字符的格式就是\ddd,d的范围是0~7
十六进制转义字符的格式为\xhh,h的范围为0~9,A—F(a—f字母不区分大小写)
必须必须带有转义符反斜杠\
只有一个反斜杠的\不合法
在\1011 中1011是八进制形式, 不是二进制,不是十进制,换算后十进制为 521 , 已超出ASCLL码最大值128 , 不合法
在\xf , 以x开头表示以十六进制表示的,转换为十进制为 15. 合法 .
注意: \f与 \xf 都合法.
但是 \n 合法, \xn 不合法,因为十六进制最大值为f,即15
字符串常量:双引号括起来,可以是中文
scanf
scanf 中 %d 只识别“十进制整数”。对 %d 而言,空格、回车、Tab 键都是区分数据与数据的分隔符。
当 scanf 进入缓冲区中取数据的时候,如果 %d 遇到空格、回车、Tab 键,那么它并不取用,而是跳过继续往后取后面的数据,直到取到“十进制整数”为止。
如果 %d 遇到字母,那么它不会跳过也不会取用,而是直接从缓冲区跳出
#include<stdio.h>
int main()
{
int i=0,m=9,n=7;
//输入7 q 4
scanf("%d%d%d", &i,&m,&n);
printf("i=%d\n", i); 7
printf("m=%d\n", m); 9
printf("n=%d",n); 7
return 0;
}
%d遇到 字母直接结束scanf
scanf(“%d %d”,&a,&b);//在输入的时候需输入空格,程序才可正常运行
而空格只需 输入,不必个数相同。
scanf(%s)的时候读到空格或者是\n 都会停下
scanf没有小数点的精度控制!
scanf(“%d%d”,&a,&b);//如果输入逗号,会出现不确定的值。
scanf("%d,%f");逗号只能输入逗号,不能输入其他字符
gets它读取整行输入,直至遇到换行符(回车)结束,遇到空格不会停止。
scanf("%d,%d,%f",&a,&b);
%f是起作用的,键盘读取前两个数据之后,读入第三个数据后,将其存放入缓冲区,然后找到应存放的地址,因为没有找到,程序会发生错误而终止
char a[10],char b[10];
scanf("%s%s",a,c);输入abcd空格defg
a读入abcd之后遇到空格结束abcd的输入,defg读入到b中 注意:不要以为scanf读入空格就结束,这个结束是结束输入的字符串,不是整个scanf
int main()
{
int i;
scanf("%d",&i); //输入c95
printf("%d\n",i); //输出-858993406
}int main()
{
int i;
scanf("%d",&i); //输入95c
printf("%d\n",i); //输出95
}
'\0'和数字0和'0'和null
'\0'字符串的末尾的结束标志,占1字节
'\0' 数字0 Null 都是一个意思,‘\0’的ASCII码是0
Null就是0,Null通常用作空指针
数字0用作变量值
而字符0 ASCII码是48。
*三个概念
作单目运算符表示间接访问运算符。
作双目运算符表示乘法运算。
作为标记时表示定义变量是指针变量
死性概念
文件
c语言文件存取方式可以是顺序文件,也可以是随机文件
feof函数是判断指针是否到达文件末尾。如果是返回非零值,否则返回0
文件由数据序列组成,可以构成二进制文件或文本文件
执行fclose函数时,关闭文件成功,则函数返回值时0
函数
如果函数的类型和返回值类型不一致,以函数为标准
数据只能从实参单向传递给形参(在实参传递时,传递数组名或指针,传递的是地址,形参接受地址,此时实参和形参指向同一内存单元)
函数由两个部分组成,函数声明和函数体
函数不写返回值,默认int
函数的返回值不能是数组
函数名也是指针,是函数入口地址,指针直接指向函数名即可,和数组名一样
int fun(int x,int y)//函数fun
int (*p)(int x,int y) =fun;//fun是函数名,函数入口地址
int (*p)(int x,int y) =&fun;//也是对的
函数体内的局部变量无论是否声明为static,外部编译单位都不能引用
void 类型的函数也可以有return语句
形参在没有被调用时,不会分配内存空间
一个函数没有return语句(题目不告诉你是不是void返回值类型),会造成2种情况,1.编译不通过 2.编译器默认加一个return 0(返回不确定的值)
全局变量不能定义在函数内部,可以在文件外面
用户定义的函数中若没有return语句,可以不用定义为void语句
形参和实参分别占用不同的内存空间
形参必须是变量,实参可以是常量,变量或表达式
有些递归程序是可以用非递归算法实现的
数组
一维数组定义方式:类型说明符 数组名 [整形表达式或整形常量]
引用数组元素时,其数组下标的数据类型允许是 整形常量或整形表达式,整形变量(定义的时候不能用变量)
数组作形参可以退化成指针
数组名不能进行自增自减运算
若数组a有m列,则在a[i][j]前的元素个数为i*m+j
数组不能用变量来定义大小但是可以用常量
二维数组元素的内存中存放顺序是按行顺序存放
数组的地址计算公式为首元素地址+(行索引*每行元素个数+列索引)*元素大小
二维数组定义:行可省,列不可省,其中行省略,要初始化!否则不知道分配多少内存空间给他
int arr[][5];//错误的初始化
int arr[][5] = {0};//正确的初始化
int arr[][5] ={3*5};//正确的,相当于arr[1][5] ={6};其中arr[0][0] = {6};
数组是一组相同类型元素的集合,它们在内存中是连续存储的。数组的大小是在声明时确定的。一旦确定就不能改变,即数组的大小是固定的。此外,数组中所有元素的类型必须相同,即数组元素的类型是固定的。
指针
- ( )>[ ]>*
- int *p[3]是一个指针数组,该数组包含三个元素,每个元素都有基类型为int型的指针
- int (*p)[3]是一个数组指针,指向数组的指针,该数组包含三个元素,每个元素都是整形变量,不是指针
- 二级指针是指向一级指针变量的指针
- 两个指针指向同一个数组,a指针指向数组末尾,b指针指向数组开头,(a-b)指针相减,结果是元素之间的个数
- 指针变量所占字节数均为4字节
- &*这两个运算符优先级相同,从右往左算,*不能用在变量上,*作用是取地址
- 表达式 *&x就等于x。相反地,在形如 &*ptr的表达式中,这些运算符会互相抵消,表达式的类型与值等效于ptr。
-
int a = 1; int *p = &a; float *p1 = (float*)p;
指针变量是可以强制类型转换的,但是p是将&a地址中的值按照int型变量进行解释,而p1则是将&a地址中的值按照float型变量进行解释的
-
通过类型转换可以将一种类型的指针赋值给另一种类型的指针变量
-
char *a[2] = {"abcd","ABCD"};
数组a的两个元素分别存放了字符'a'和 'A'的地址
宏
- 宏替换不占用运行时间,只占用编译时间
- 宏替换过程,在编译时间就完成了,因此不会占用程序运行时间
- #definde s(n)空格空格n+1是对的表达形式
- 宏定义宏调用是允许嵌套的
- 宏名不能是关键字,可以小写也可以大写
- 宏名无类型
- 预处理命令行在其他语句编译前进行
- 预处理命令行无需再程序开头可以在程序的任何地方
- #include是文件包含的宏定义,不属于c语言的语句
- 一个#include只能包含一个文件,如果需要包含多个文件,必须使用多个#include命令行
- #include命令如果太长,可以使用符号'\'将命令写成多行
- 用户可以重新定义库函数,若如此,函数将会失去原有含义
- 凡是以#开头的均为预处理命令
- 宏替换是由预处理程序自动完成的
- 宏替换没有数据类型限制
- #define F 37.5f F是宏名,在程序中出现的宏名都是用字符串去替换,所以F是字符串
- 在程序中一行只能有一个预处理命令行
- 使用带参宏时,参数的类型和宏定义可以不一致
- #include"stdio.h "搜索源程序所在目录,再按照系统设定的标准方式搜索
- #include<stdio.h> 直接按照系统设定的标准方式搜索目录
-
#define SUM(x) 3*x*x+1 int main() { int i=5, j=8; printf("%d\n", SUM(i+j)); return 0; }
直接把表达式中的x替换为i+j 即3*i+j*i+j+1=3*5+8*5+8+1=64 ,宏只是进行简单宏替换,不要计算i+j
-
#include<stdio.h> #include<math.h> #include<string.h> #define f(x,y) y = x*x int main() { int a=2, b=0; f(a, b); printf("%d",b);//4 }
-
...
结构体
- 结构体类型的大小为所有成员所占内存空间之和
- 结构体变量的成员可以是变量,数组,指针变量。
- 结构体定义时,成员数据类型不能是本结构体类型
- typedef说明的新类型名可以是小写也可以是大写
- typedef定义新的类型名后,原有类型名仍有效
- typedef只是对已存在的类型增加一个类型名,不能创造新的类型
- 结构体变量再程序执行期间,所有成员一直驻留在内存中。
- 链表是以结构类型表示链中元素,以指针表示链的一种线性数据结构
共用体
- 1.一个共用体变量不能同时存放其他所有成员。
- 共用体内存长度是按成员中最大的分配,而结构体是所有成员之和
基本概念
- 允许有多个return语句,但每次调用只能有一个return语句被执行
- 不加{}默认执行一条语句
- 预处理命令一般以#开头
- 字符以ASCII形式存储在内存中
- c语言中,char型数据在内存中的存储形式是ASCII码。因为字符型数据是将一个字符常量放在一个字符变量中,并不是把字符本身放在一个单元去,而是将字符相对应的ASCII码放到存储单元中。
- sizeof是运算符,不是函数,siezof(int);是一个整形表达式。
- %*用于跳过输入的数字 %#用于显示出所有数值位数
- %%d 输出的是%d
- c语言从main函数开始,但不一定从main函数结束
- main函数的位置可以任意
- c语言主要是借助定义函数功能来实现程序模块化的
- c语言基本组成单位是函数
- 一个c函数可以单独作为一个c程序文件存在
- c语言没有子程序
- c语言模块化通过函数来体现
- c语言中数据可以使用二进制和ASCII码两种代码存放
- c语言编写的函数都可以作为一个独立的源程序文件,但不能编译并执行。
- c语言执行步骤:预处理、编译(编译程序)、链接、运行。
- .c源文件通过编译程序生成.obj的目标文件,在经过链接成.exe可执行文件(.exe可以反复调用)
- c语言使用编译程序,不使用解释程序,解释程序是一条语句一条语句的执行,效率远远比不上编译程序
- c语言允许两种注释:一种是以"//"开头的行注释,另一种是以"/*"开始,"*/"结束的块注释
- 每个后缀为.c的c语言源程序都可以单独进行编译
- c语言程序不一定要保存在同一源文件中,外部函数可以在同程序中其他源文件中调用。
- c语言标识符可以分为关键字,预定义标识符和用户标识符三类。用户标识符由数字字母下划线组成,数字不能开头。其中关键字不能作为用户标识符,预定义标识符可以作为用户标识符,只不过会失去原有的作用。
- 每个模块不能单独进行编译
- 允许函数进行单独编译,实现模块化
- 程序模块化是为降低程序的复杂度,是程序设计维护等操作简单化
- 程序的运行效率与程序的算法,实现有关,与程序模块化无关
- 可以通过强制类型转换把char型指针指向double型变量(通过强制类型转换把一种类型指针指向另外一种类型指针)
- gets读入数据从数据起始的地方开始覆盖,并且带'\0'
- 常量可以用符号名代表
- 注释符号"/*"和"*/",/和*之间不能有空格,/*和*/必须成对出现并且不能嵌套
- 注释可以出现在程序中任何位置,但是不能写在变量名或关键字中间,一旦写中间,将会失去变量名或关键字的意义
- 编译预处理中,不能使用关键字
- double a=10是可以的,但是实型变量不可以存放整形,存放整形数据其实是把整形转为实型存放
- int a =7.56 可以的 单输出因为是int型要用%d
- 返回符EOF是在头文件stdio.h中定义的宏,一般值为-1,作为文件结束标志
- 函数体必须由‘’{‘’开始,c语言函数必须由main函数开始,不是mian语句
- 应该避免滥用goto语句
- 复杂任务可以分解成简单子任务
- 全局变量可以在函数以外的任何部位进行定义
- 全局变量的作用域是从定义位置开始到源文件结束
- 全局变量的生存期贯穿于整个程序的运行期间
- 常量名也要遵守标识命名规则
- 单目运算符的运算对象可以在其左侧或者右侧,如i++或++i
- 变量,常量占用内存单元
- 冒泡排序与快速排序比较次数相同(在最坏的情况下)
- 文件是由数据序列组成,可以构成二进制文件或文本文件
- a=(b=3)=1是错误的,(b=3)这个表达式的值为3,a=3=1,这种表达方式是错误的
- 格式控制字符+默认右对齐,-左对齐
- 在有限范围内,变量可以在任意位置定义
- 空字符串不包含字符,但包含字符结束符'\0',其占用内存大小是1字节
- " ";空格占1字节,加上'\0',一共占2字节
- 两个连续的单引号''不占空间,不是合法字符常量,因为合法的字符常量占用1字节空间
- 两个连续的双引号""是合法的字符串常量,两个连续的双引号是空字符串,包含字符串结束符'\0'
- 在没有安装c语言集成开发环境的机器上不能运行c源程序生成的exe文件。
- main(int argc,char*argv[ ])argc的个数与argv的个数有关。如命令行为:file 1 2 3<回车> argc的个数就为4 argv[0]的值为file,argv[1]的值为1 。
- 花括号括起来的的语句序列称为复合语句。
- 带符号普通整形的数据范围是-32768~~+32767(2的15次方)
- 实型变量可以输入实型数据或整形数据
- 静态变量和外部变量的初始化是在编译阶段完成的,而自动变量的赋值是在函数调用阶段完成的
strcpy
复制过来要注意'\0'
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
char s[]="beijing";
strcpy(s,"china");
printf("%d",strlen(s));//5
printf("%s",s);//china
}
static auto resign extern
static变量又称静态变量,编译时为其分配的内存在静态存储区内,如果static变量没有赋初值默认初值为0作用域是从定义开始的地方到本文件结束。
resign变量又称寄存器变量,变量值保留在CPU寄存器中,而不是像变量一样占用内存单元。
extern又称外部函数,外部函数在整个源程序内都有效,可以将扩大全局变量的作用域。
全局变量没有赋初值,默认为0
auto又称自动变量,函数定义变量时,如果没有存储类型,系统就认为所定义的变量具有自动类型,自动变量未赋初值,为随机值。
auto和resign只有在使用时在占用内存单元
如果要定义一个只允许本源程序文件中所有函数使用的全局变量则该变量的存储类型为static
外部函数的隐含类型是static
全局变量在静态区,局部变量在动态区,static定义的变量在静态区
常见题
语句while(!E);中的!E等价于 E==0
因为:当E为真,!E为假。当E为假,!E为真。当E为真 E==0为假。当E为假 E==0为真
与while(E)中的(E)不等价的表达式是 E==0
(exp)?a++:b--,exp等价于 exp != 0
表达式(w)?(--x):(++y),其中w等价的表达式是 w!=0
若数组a有m列,则在a[i][j]前的元素个数为i*m+j,任意一元素的在数组中位置是i*m+j+1
已知long i=65539; 执行语句 printf("%d",i);屏幕显示3
(在tc编译器上) long定义的变量是4个字节,即32位;int定义的变量是2个字节,即16位
65539 在内存中占32个二进制位即0000 0000 0000 0001 0000 0000 0000 0011
它要以整形输出(%d)那么就需要从低位截取16位转换成十进制输出,即0000 0000 0000 0011
int k = 32767;执行k = k + 1;k的值为
k是一个带符号整数变量,其范围是-32768~~32767 当超出范围时,结果会产生溢出,根据溢出规则,结果绕回范围的另一端。所以为-32768
以下程序中,程序没有任何错误,可以正常运行
int sub(char x,char y)
{
int z; z = x%y; return z;
}int main()
{
int a = 5,c = 3,k; k = sub(a,c); printf("%d",k); // 2}
long i = 65539; printf("%d",i); //3
合法的常量是 D
A.整数:1,200 //不是合法的整形常量,不能有逗号,否则编译会出错
B.实数:1.5E2.0 //e后面不能有小数
C.字符斜杠:’\‘ //转义字符’
D.字符串:"\007"
字符’97‘是错的,字符是单个字符
void fun(int a,char c);
调用
fun(99,'9');//对的
fun(99,'99');//错误的
fun(99,99);//正确的