C语言学习概览
Posted 胖仙人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言学习概览相关的知识,希望对你有一定的参考价值。
为了更好的阅读体验,建议访问博主的语雀知识库进行阅读
Part 1 第一个C语言程序
一、创建工程(编译环境VS2019)
①运行VS2019,点击右下方创建新项目,选择C++空项目
②配置项目内容,选择好项目创建的位置
③右击名为源文件的文件夹,选择添加新建项,新建C++文件,文件后缀名更改为.c
④编写源文件
二、代码内容
>Code Ⅰ:
#include<stdio.h>
int main(void) -- void可以省略,意为main函数不需要参数
{
printf("Hello World");
return 0;
}
①库函数
代码中printf()函数为一个库函数,使用库函数时,要在代码头部引入对应的头文件
②头文件 stdio.h
C语言提供的头文件有很多,stdio代表的是和标准输入输出有关的头文件,.h为头文件的后缀名
③主函数
main - 函数名,固定写法,不可改变
( ) - 函数参数
{ } - 代码块,在代码块内编写代码
int - 整型,表示函数调用完之后会返回一个整数
所有的程序都是从main函数的第一行开始运行,即main函数是程序的入口,且一个项目中的所有.c文件中只能有一个main函
④*main函数带参数的写法
int main(int argc,char * argv[]){}
三、*快捷键
Crtl+F5 --> 执行(运行)代码
F10 --> 逐行运行代码
Part 2 数据类型
一、数据类型引入的意义
程序是服务于现实生活中的方方面面的,而生活中的方方面面往往离不开数据,不同的领域对数据的精确度要求也各不相同,如日常购物计算和银行的计算要求的数据精确度是不相同的,所以在C语言中,我们需要引入不同的数据类型,来满足现实生活中不同的需求。
二、计算机中的单位
bit | |
byte | =8bit |
kb | =1024 byte |
mb | =1024 kb |
gb | =1024 mb |
tb | =1024 gb |
pb | =1024 pb |
三、数据类型及大小
int main()
{
//如何计算一个类型创建的变量的所占空间的大小
//sizeof();
//%d - 指定打印格式为整数
printf("%d\\n", 100); //以整数形式打印100
printf("%c\\n", 100); //以字符形式打印100
printf("%d\\n", sizeof(char));
printf("%d\\n", sizeof(short));
printf("%d\\n", sizeof(int));
printf("%d\\n", sizeof(long));
printf("%d\\n", sizeof(long long));
printf("%d\\n", sizeof(float));
printf("%d\\n", sizeof(double));
return 0;
}
名称 | 关键字名 | 长度(byte) |
字符数据类型 | char | 1 |
短整型 | short | 2 |
整型 | int | 4 |
长整型 | long | 4 |
更长的整型 | long long | 8 |
单精度浮点型 | float | 4 |
双精度浮点型 | double | 8 |
有了丰富的数据类型,我们就要考虑使用类型的合理性,比如:
定义一个age变量,用来表示人的年龄,而普遍情况下,人的年龄不会超过三位数
int 能表示的有符号数字的范围:-231+1~ 231
short能表示的有符号数字的范围:-215+1~ 215
为了避免浪费空间,选择用short类型创建该变量更为合适
四、ASCll码
数据在计算机中是以二进制形式存储的,但在编码过程中,我们敲在键盘上的都是字符,为了方便存储,我们给每个能在键盘上敲出来的字符都对应唯一的整数值,方便字符存储在计算机中。
我们将这些对应关系汇制成ASCll码表
Part 3 变量
一、定义变量的方法
//变量的定义:
[数据类型] [变量名];
short age;
float weight;
//变量的初始化:
[数据类型] [变量名] = [值];
short age = 18;
//变量的赋值
age = 20;
二、 局部变量和全局变量
①定义:
在代码块内部定义的变量称为局部变量
在代码块外部定义的变量称为全局变量
int g = 10; //全局变量
int main()
{
int a = 0; //局部变量
}
②局部变量和全局变量的优先度
>Code Ⅰ:定义一个和全局变量重名的局部变量
int g = 10; //全局变量
int main()
{
int g = 5; //局部变量
printf("%d",g);
}
此时打印结果为5,即局部变量和全局变量的名字可以相同(不建议),且局部变量优先使用。修改局部变量时不影响全局变量的值。
三、变量的使用
>Code Ⅰ:变量相加案例
int main()
{
//两个整数相加
int num1 = 0;
int num2 = 0;
//给两个变量输入值
scanf("%d %d", &num1, &num2);
//相加
int sum = num1 + num2;
//打印求和结果
printf("%d", sum);
return 0;
}
四、变量的作用域
①作用域的定义:通俗的说,变量能被使用的范围称为变量的作用域
②局部变量的作用域:
>Code Ⅰ:
int main()
{
{
int a = 10;
}
printf("%d",a);
}
运行报错:
上述代码中,变量a是定义在3-5行中的代码块中的,所以变量a只能在3-5行的代码块中使用,3-5行的代码块则称为变量a的作用域。
>Code Ⅱ:将printf函数放到代码块中
int main()
{
{
int a = 10;
printf("%d",a);
}
}
运行结果
>Code Ⅲ:在main函数内部,把变量的定义放到代码块的外部
int main()
{
int a = 10;
{
printf("%d",a);
}
}
运行程序,能够正常打印
简单的说,全局变量的作用域即为变量定义时所在的代码块
③全局变量的作用域
>Code Ⅰ:
int a = 100; //定义全局变量
void test()
{
printf("函数打印:%d\\n", a);
}
int main()
{
test(); //调用函数
printf("main函数打印:%d\\n", a);
return 0;
}
运行结果:
>Code Ⅱ:在外部文件中定义的全局变量的使用
(1)我们在项目的源文件夹中添加一个 “外部文件.c
”文件:
int g_val = 100;
(2)在文件“全局变量.c
”文件中编写代码:
//声明外部变量
extern int g_val;
int main()
{
printf("%d\\n", g_val);
return 0;
}
运行结果:
由上述两个案例,全局变量定义后在整个项目内都可以使用;跨文件使用时全局变量时,需要先声明外部变量再使用。
五、变量的生命周期
①局部变量的生命周期
进入局部变量所在的代码块,生命周期开始;出代码块,生命周期结束
②全局变量的生命周期
全局变量的生命周期=程序的生命周期=main函数的生命周期
*补充说明:
一个int型的变量被定义后,计算机会在内存中申请了4byte的空间用于存放变量的值;该变量的生命周期未结束时,程序拥有这块空间的使用权限;变量的生命周期结束时,这块空间即被回收,用于计算机的其他工作。
Part 4 常量
一、常量的分类
①字面常量
平时看到的数值即为字面常量,如3.14,100等;
int a = 10,即变量a被定义时,将字面常量10这个值存入变量a中。
②const修饰的常变量
一个变量被初始化之后,可以在后面的代码中改变其值,而如果用const修饰该变量,这该变量具有常属性,其初始化的值不能被更改
>Code Ⅰ:
int main()
{
const int a = 100;
a = 200;
printf("%d\\n",a);
}
运行报错:
注意:变量a被const修饰之后只是具有了常属性,其本质还是一个变量,并不是变成了一个常量。
③#define定义的标识符常量
>Code Ⅰ:
#define Max 200
int main()
{
int a = MAX;
printf("%d\\n",a);
}
运行结果:
④枚举常量
生活中一些属性的值可以逐一列举出来,C语言中即可以创建枚举类型来描述这些属性
如:
性别可分为:男 女 保密
>Code Ⅰ:
enum Sex //枚举类型
{
//枚举的可能取值 - 枚举常量
MALE,
FEMALE,
SECRET
};
int main()
{
enum Sex s = SECRET;
printf("%d\\n",s);
printf("%d\\n",MALE);
return 0;
}
运行结果:
我们定义了一个枚举类型,用来描述性别这个属性,其可能取值有三个,此时我们定义枚举类型的变量时,变量的类型即为enum Sex;
且从运行结果可以看到,当我们打印枚举类型中的值时,可以得到结果为一个常量,
即每个枚举常量都对应一个值,且第一个默认为0,往下依次增加;
因为枚举常量属于常量,所以定义之后也不可在主函数中修改其对应的值(如在主函数写MALE = 3; )
如果我们需要枚举常量对应我们想指定的值,需要在初始化过程中完成
>Code Ⅱ:
enum Sex //枚举类型的初始化过程
{
MALE = 1, //为枚举常量赋初值
FEMALE = 3,
SECRET = 5
};
int main()
{
printf("%d\\n%d\\n%d\\n",MALE,FEMALE,SECRET);
return 0;
}
运行结果:
Part 5 字符串
一、字符与字符串
C语言数据类型分类中,有字符类型,关键字为char,大小为1byte。在编译器中,我们用单引号引出一个字符,如:'a'
但C语言中没有字符串类型的,但我们可以用双引号引出一串字符,称之为字符串,如 "abcd"
二、字符串的使用&字符串的结束标志
①一般情况下,我们在使用字符串之前,会先将其存入一个字符数组中
CodeⅠ中创建一个能存放10个字符的字符数组,将字符串"abcdef"存入数组中,字符串中的每一个字母视为一个字符,且当字符串存入数组之后,字符串的末尾会默认带上一个结束标志 '\\0';
所以此时,字符串存入数组之后,需要占用7个字符空间,而未被占用的空间会默认存放空字符 '\\0'
>Code Ⅰ:
int main()
{
char ch[10] = "abcdef";
return 0;
}
调试环节:
①F10逐行运行代码,使代码运行至数组初始化的下一行
②选择菜单栏的调试-->窗口-->监视-->监视1,点击添加要监视的项,输入数组名ch,得到数组中存放值的具体详情
★要重点注意的是,当字符串存入字符数组中时,会自带一个隐藏的结束标志'\\0',需要和数组默认存放的'\\0'区分开。
②为了更直观的观察字符串自带的结束标志,Code Ⅱ中创建字符数组时不定义数组的长度,使数组可以随着字符串长度扩充,这种做法的好处是不会造成空间浪费。
>Code Ⅱ:
int main()
{
char ch1[] = "abcdef";
return 0 ;
}
调试监视结果:
可以看到,除了我们想要存放的字符串,还多了一个'\\0'
③字符串的输出
在之前的学习中,%d表示以整型输出;%c表示以字符形式输出;
打印字符串时,%s表示以字符串形式输出。
>Code Ⅲ:
int main()
{
char ch[10] = "abcdef";
printf("%s\\n",ch);
return 0;
}
运行结果:
三、结束标志'\\0'的影响
①以单个字符形式往字符中存入字符串
>Code Ⅰ:
int main()
{
char ch1[] = {'a','b','c','d','e','f'};
return 0;
}
监视结果:
可以发现,以单个字符形式将字符串存入数组时,结尾并没有结束标志'\\0'
②两种形式存放字符串的打印结果比较
>Code Ⅱ:
int main()
{
char ch1[] = "abcdef";
char ch2[] = {'a','b','c','d','e','f'};
printf("单字符形式存入数组:%s\\n",ch1);
printf("字符串性质存入数组:%s\\n",ch2);
return 0;
}
运行结果:
从结果可以看出,当我们以单字符形式将字符串存入数组后,打印该数组会输出我们预期之外的内容
出现上述结果的原因:
使用printf函数打印字符数组中的字符时,会先读取数组中的内容,读取到第一个'\\0'之后,将其视作为一个结束标志,不再往后读取,并将之前所读取的内容以一串字符的形式打印输出。
而以单字符形式存入时,printf函数在读取完abcdef这6个字母之后,由于没有读取到结束标志'\\0',所以会继续读取数组空间之外的其他内容,直到读取到结束标志'\\0'时停止读取,输出内容。所以得到的结果中,会多出预期之外的随机值
③从求字符串长度来体会结束标志的影响
字符串存入数组之后,想求其长度(即在内存中所占的大小),需要用到strlen()函数;因为strlen是库函数,使用前需要引入对应的头文件;代码如下:
>Code Ⅲ:
#include<string.h>
int main()
{
char ch1[] = "abcdef";
char ch2[] = {'a','b','c','d','e','f'};
printf("ch1的字符串长度:%d\\n",strlen(ch1));
printf("ch2的字符串长度:%d\\n",strlen(ch2));
return 0;
}
输出结果:
在数据类型里学过,一个字符的长度为1byte;计算字符串长度,只会将结束标志'\\0'前的字符计入长度,结束标志本身不计入字符串长度;所以代码中字符串正确的长度应为6byte。
而以单字符形式存入字符串时,由于会一直读取到结束标志为止,所以计算长度时,也将多出来的随机值计入了长度。
Part 6 转义字符
一、案例
写一个程序,期望它能打印一串文件路径,而文件路径中是有'\\'来划分层级的,代码如下:
>Code Ⅰ:
int main()
{
printf("C:\\test\\test.c");
return 0;
}
打印结果:
可以看到,打印结果和预期结果并不一样,路径中的'\\t'并没有成功打印。这是因为,'\\t'在C语言中,是一个转义字符
二、转义字符的使用
顾名思义,转变一个字符原本的含义,通过一下代码,进一步了解转义字符:
①printf函数的打印规则:printf()函数会将括号内双引号引起的内容打印输出;
>Code Ⅰ:
int main()
{
printf("第一行:%dn",100);
return 0;
}
运行结果:
上述代码中,期望以整数的形式打印100;打印时,100会以整数形式替换%d的位置,其他内容按照printf函数打印规则,双引号内的内容会被打印,打印结果应为图片所示结果
②当我们在字符 'n' 前加上字符 '\\' 后:
int main()
{
printf("第一行:%d\\n",100);
return 0;
}
运行结果:
打印结果中,并没有 '\\n' 的出现
此时,'\\n' 这个整体已经是一个转义字符了,在打印时实现其对应的功能;
转义即转变了字符n本身的含义,使其变成了一个具有功能性的字符,所以被称之为转义字符;
而 '\\n' 在C语言中为具有换行功能的转义字符转义字符的
③转义的核心
不难看出,转义字符中起到“转义”作用的其实是转义字符之前的反斜杠 '\\' ;即在一个字符前加上反斜杠会转变该字符原有的含义。
比如 '\\n' 表示换行符;'\\t' 表示水平制表符等;
需要额外说明的是C语言中的单引号和双引号:
写一个程序预期输出双引号引起的HelloWorld;即"HelloWorld"
;按照printf函数的打印规则,写出如下代码。
>Code Ⅰ:
int main()
{
printf(""HelloWorld"");
return 0;
}
程序报错:
程序不能正常运行,其原因在于C语言中双引号和单引号都是用来引起一段内容的,它门会自动寻找配对;
如上述代码中,我们期望中间的两个双引号以及引起的字符串HelloWorld能被输出,但实际上第一个双引号和第二个双引号会自动配对,作为一对双引号,行使其作为双引号引起内容的职责;第三个双引号和第四个双引号亦是同理。
所以夹在中间的字符串HelloWorld实际上和它两侧的双引号并不是一个整体,这样的写法是不符合C语言语法的。
为了解决这个问题,我们在双引号前加上反斜杠'\\',构成转义字符 \\" ,使其不再具自动配对并引起内容的特性,而是单纯的作为一个字符。
>Code Ⅱ:
int main()
{
printf("\\"HelloWorld\\"");
return 0;
}
输出结果:
单引号同理。
④反转义
既然反斜杠是转义的核心所在,可以转变字符原本的含义,同理,在反斜杠之前加上反斜杠,亦可使其失去转义的功能;在转义字符前加上反斜杠,使其变为纯字符,失去转义字符的功能;
回到开头打印路径的案例,我们在转义字符\\t前加上反斜杠\\\\t,此时\\t就不再是水平制表符了,而是作为纯文本字符:
>Code Ⅰ:
int main()
{
printf("C:\\\\test\\\\test.c");
return 0;
}
输出结果:
三、转义字符\\ddd和\\xdd
①转义字符\\ddd,表示1~3位八进制数所代表的字符
如/065,表示八进制数065代表的代表的字符
计算过程:
065 --转换成10进制--> 53 --做为ASCAll码值对应的字符--> 字符5
>Code Ⅰ:
int main()
{
printf("%c\\n",'\\65');
return 0;
}
运行结果:
②\\xdd,表示1-2为十六进制数所代表的字符
用法和\\ddd同理
四、计算字符串长度案例(转义字符的判断)
转义字符在计算长度时,只作为一个字符来处理,其大小为1byte
>Code Ⅰ:求字符串长度
int main()
{
printf("%d\\n",strlen("C:\\test\\328\\test.c"));
}
输出结果:
字符拆解:
'C' , ':' , '\\t' , 'e' , 's' , 't' , '\\32' , '8' , '\\t' , 'e' , 's' , 't' , '.' , 'c'
易错点:\\ddd后面跟的数字必须是8进制数字(<8),所以\\328是两个字符。
Part 7 注释
一、注释的作用
注释的文本是不会被编译器识别编译的,在编译器中呈绿色字体;一般用于为某段注释信息添加解释说明;或者用于屏蔽程序中暂时不需要的代码
二、注释语法
①单行注释(C++注释风格):双斜杠后跟注释内容//
int main()
{
int a = 0; //(单行注释)定义变量a
return 0;
}
②多行注释(C语言注释风格):/*注释内容*/
int mian()
{
/*程序的功能
1:……
2:……
*/
int a = 0;
return 0;
}
三、VS2019中相关快捷键
①选中需要注释的代码:Crtl+K+C 快捷注释
②选中已被注释的代码:Crtl+E+U 取消注释
Part 8 选择语句
一、初见分支
生活中最常见的例子就是使用支付软件时选择是否支付,简单实现一下这个过程:
>Code Ⅰ:
int main()
{
int input = 0;
printf("确认支付?(1/0):");
scanf("%d",&input);
if(input == 1)
{
printf("支付成功\\n");
}
else if(input == 0)
{
printf("支付失败\\n");
}
return 0 ;
}
运行结果:
ps:深入学习将放在正式章节中介绍
Part 9 循环语句
一、初见循环
利用循环实现一个简单的计数,当数字加到100时,就停止程序:
>Code Ⅰ:
int main()
{
int a = 0;
while(a<100)
{
a ++;
printf("计数:%d\\n",a);
}
return 0;
}
运行结果:
ps:循环有多种形式,深入学习将放在正式章节中介绍
Part 10 函数
一、初见函数
函数可以封装某个功能,比如之前学习的两数求和案例,改写成用函数实现:
>Code Ⅰ:
int Add(int x, int y)
{
return x+y;
}
int main()
{
int x = 0;
int y = 0;
int sum = 0;
scanf("%d %d",&x,&y);
sum = Add(x,y);
printf("两数和为:%d",sum);
return 0;
}
运行结果:
我门将求和这个功能封装进了add这个函数中,这时候我们只要给这个函数提供我们要求和的数,函数就会计算得出结果,并将结果返回到主函数中。
Part 11 数组
一、数组的定义
数组中存放了一组相同类型元素的集合。当我们编码时需要用到多个相同类型的数据时,我们可以考虑用数组来存放这些数据
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};//
return 0;
}
数组的定义方法:
数据类型 数组名[n] = { };
数组定义时:
①需要定义该数组存放的是什么类型的数据。上述代码中,创建的数组只能存放int类型的数据;
②需要定义数组名。上数代码中,arr即为数组名
③数组名后要接中括号,且中括号内要填入整型常量,表示数组空间的大小。上述代码中,该数组能存放10个int型数据
④赋予初值是,在‘{ }’中写要存入数据的数据。上述代码总,数组中存放了1~10的整数
二、数组的使用
①数组的下标:
数组被创建时,数组的每个空间都有一个编号,该编号默认从0开始递增。如上述代码中,数组中元素3对应的数组下标为2;
知道下标后,我们可以使用数组名[下标]的形式来访问数组中的每个元素
>Code Ⅰ:
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
printf("%d %d",arr[1],arr[9]);
return 0;
}
运行结果:
因为数组的下标时默认从0开始增长的,所以该代码中,arr[1]访问的是数组中第二个元素,arr[9]访问的是第10个元素
即数组的最大下标 = 数组长度 - 1
②利用循环遍历数组
int main()
{
int i = 0;
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
while(i<10)
{
printf("%d",arr[i]);
i++;
}
return 0;
}
运行结果:
当我们想要访问数组中元素时,下标部分是可以为变量的,如上述代码中下标为 i ,其值是一直在变的;但要注意的是,定义数组时,数组名后括号内的数字必须为整型的常量,不可为变量。
Part 12 操作符
一、操作符的分类
①算数操作符
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
% | 取余数 |
加减乘操作符的用法比较简单,这里对除法做一些说明:
当除法的两边都为整数时,其运算结果只会取结果的整数。
>Code Ⅰ:
int main()
{
int a = 5 / 2;
float b = 5 / 2;
printf("%d\\n%f\\n",a,b);
return 0;
}
运行结果:
可以看到,不管存放结果的变量是什么类型,其结果只会取5除以2结果的整数部分
实际上,只要除号两边都是整数时,只会取算式答案的整数部分作为结果;
只要有一边为浮点数时,结果才会取小数部分,存放结果的变量类型需为浮点型
>Code Ⅱ:
int main()
{
float a = 5 / 2.0;
printf("%f\\n",a);
return 0;
}
运行结果:
②移位操作符
>> | 右移操作符 |
<< | 左移操作符 |
移位操作符是在二进制条件下进行运算的:
>Code Ⅰ:
int main()
{
int a = 6;
int b = a<<1;
printf("%d\\n",b);
return 0;
}
运算过程:
移位操作符在二进制条件下运算的:
(1)二进制转换:
对a的值6进行左移操作时,需要先将6转换成二进制
6 --二进制--> 110;
(2)补位:
因为a是整型变量,所占大小为4字节;
1字节=8bit,共32bit,一个二进制数占1bit,所以用二进制数运算时,先用0补满32位
|0000 0000 0000 0000 0000 0000 0000 0110|;
(3)移位操作:
进行左移操作,将整个二进制数往左移一位
0|0000 0000 0000 0000 0000 0000 0000 110 |;
(4)溢出丢弃,空位补0:
右边空出的位补上0,左边的一位丢弃,得到移位后的二进制数:
|0000 0000 0000 0000 0000 0000 0000 1100|;
(5)十进制转换:
将新的二进制数转换回十进制,得到十进制数12,运算结束
运行结果:
③位操作符
& | 按位与 |
^ | 按位异或 |
| | 按位或 |
>Code Ⅰ:按位与
int main()
{
int a = 3;
int b = 5;
int c = a & b;
printf("%d",c);
return 0;
}
运算过程:
和移位操作符相同,位操作符也是运算于二进制条件下的
(1)二进制转换:
3 --二进制--> 11;
5 --二进制--> 101;
(2)补位:
0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0101
(3)对应位进行按位与
两数补满32位后,使两数对齐,每一位相对
上下相对的两个数中:只要有0,则该位上按位与得到的结果为0;当同为1时,该位上按位与得到的结果位1
0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0101
按位与之后:
0000 0000 0000 0000 0000 0000 0000 0001
(4)十进制转换:
将得到的按位与结果转换回十进制,得到结果1;
运行结果:
>Code Ⅱ:按位异或
int main()
{
int a = 3;
int b = 5;
int c = a ^ b;
printf("%d",c);
return 0;
}
运算过程:
(1)前三步和按位与操作相同
(2)对应位进行按位异或
按位异或运算:对应位两数相同,得到结果为0;对应位两数相异,得到结果位1
0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0101
按位异或后:
0000 0000 0000 0000 0000 0000 0000 0110
(3)十进制转换
将得到的结果转换成十进制,得到结果6;
运行结果:
>Code Ⅲ:按位或
int main()
{
int a = 3;
int b = 5;
int c = a | b;
printf("%d",c);
return 0;
}
运算过程
(1)前三步同按位与
(2)对应位进行按位异或
按位或运算:对应位的两个数中,只要有1,得到的结果即为1
0000 0000 0000 0000 0000 0000 0000 0011
0000 0000 0000 0000 0000 0000 0000 0101
按位异或后:
0000 0000 0000 0000 0000 0000 0000 0111
(3)十进制转换
将得到的结果转换成十进制,得到结果7
运行结果:
④赋值操作符
= | 赋值操作符 |
+= | 复合赋值 |
-= | |
*= | |
/= | |
&= | |
^= | |
|= | |
>>= | |
<<= |
(1)赋值
定义一个变量时并给予变量一个值,如:
int a = 10;
该过程称为a的初始化,即定义变量a的时候,使其初识值为10;
如果在后续使用到该变量并需要改变其值时,如:
a = 20;
该过程则称为赋值
(2)复合赋值
以+=举例,其作用可以简化表达式
a = a+1;
该表达式可等价为:
a += 1;
其他的复合赋值同理
⑤单目操作符
! | 逻辑反操作 |
- | 负值(和数学理解相同) |
+ | 正值 |
& | 取地址 |
sizeof | 操作数的类型长度 |
~ | 对一个数的二进制按位取反 |
-- | 前置,后置-- |
++ | 前置,后置++ |
* | 间接访问操作符(解引用操作符) |
(类型) | 强制类型转换 |
前面所介绍的操作符,使用时需要两个操作符,才能使运算关系成立
如:
int c = a + b;
其中a和b就是+的两个操作数。
而只有一个操作数的运算符,则被称为单目操作符
>Code Ⅰ:逻辑反操作符
int main()
{
int a = 10;
int b = 0;
printf("%d\\n",!a);
printf("%d\\n",!b);
return 0;
}
C语言中,强调真和假;0代表假,非0则为真;且如不特别赋值,默认的真值为1
上述代码中,变量a此时也可以视作为表示真,变量b可视作表示假分别对a和b进行逻辑反操作后:
!a 此时则表示为假,输出结果应为0
!b此时则表示为真,输出结果应为默认真值1
运行结果 :
>Code Ⅱ:sizeof
int main()
{
int a = 10;
printf("%d\\n",sizeof(a)); //计算变量a所占空间的大小
printf("%d\\n",sizeof(int)); //计算int类型创建的变量所占的空间大小
return 0 ;
}
运行结果:
补充知识——原码、反码和补码:
一个整数的二进制有3中形式:原码、反码、补码
正整数的三码相同,负整数的三码是需要计算的
以正整数1举例:
其二进制为:
0000 0000 0000 0000 0000 0000 0000 0001
根据十进制与二进制之间的转换规则,计算得到的二进制,称为原码,其最高位为符号位,0代表正数,1代表负数
由于正整数三码相同,由此得到
反码:
0000 0000 0000 0000 0000 0000 0000 0001
补码:
0000 0000 0000 0000 0000 0000 0000 0001
再看负数的情况,以负整数-1举例:
根据转换规则得到原码:
1000 0000 0000 0000 0000 0000 0000 0001
符号位不变,其他位按位取反,得到反码:
1111 1111 1111 1111 1111 1111 1111 1110
反码+1,得到补码:
1111 1111 1111 1111 1111 1111 1111 1111
要注意的是,整数存储在计算机中时,是以补码形式存储的;运算时,用的也是补码二进制序列
>Code Ⅲ:~按位取反
int main()
{
int a = 0;
printf("%d\\n",~a);
}
运算过程:
(1)0的补码:
0000 0000 0000 0000 0000 0000 0000 0000
(2)按位取反得到运算结果的补码:
1111 1111 1111 1111 1111 1111 1111 1111
(3)我们能够读懂的时原码,所以将补码计算得到原码:
补码-1 --> 反码按位取反 --> 原码
1000 0000 0000 0000 0000 0000 0000 0001
(4)转换成十进制,得到结果-1
运行结果:
>Code Ⅳ:-- 和 ++
int main()
{
int a1 = 2;
int a2 = 2;
int b = ++a1;
int c = a2++;
printf("b的值为:%d\\n",b);
printf("c的值为:%d\\n",c);
printf("a1的值为:%d\\n",a1);
printf("a2的值为:%d\\n",a2);
return 0;
}
前置++和后置++的区别:
为了方便记忆,记住就近原则:
如果++的操作数离=比较远,如代码中的a1,则在赋值给b时,先自增,再赋值;即b的结果位3
如果++的操作数离=比较进,如代码中的a2,则再赋值给c时,先将a2原来的值赋给c,再自增;即c的结果为2
而不管a1还是a2,程序运行结束时都自增了。前置--和后置--同理。
运行结果:
⑥关系操作符
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
!= | 不等于 |
== | 等于 |
⑦逻辑操作符
&& | 逻辑与(并且) |
|| | 逻辑或(或者) |
>Code Ⅰ:
int main()
{
int a = 3;
int b = 4;
//如果a=3并且b=4,就打印HelloWorld
if((a==3) && (b==4))
{
printf("HelloWorld");
}
//如果a=3并且b=4,就打印C语言
if((a==3) && (b==5))
{
printf("C语言");
}
return 0;
}
逻辑与操作符相当于生活中说的并且,需要条件都满足时,才能继续执行后续的代码;
上述代码中,a的值为3,b的值为4,不能满足a=3并且b=5,所以“C语言”不会被打印;
运行结果:
>Code Ⅱ:
int main()
{
int a = 3;
int b = 4;
//如果a=3或者b=4,就打印HelloWorld
if((a==3) || (b==4))
{
printf("HelloWorld\\n");
}
//如果a=3或者b=4,就打印C语言
if((a==3) || (b==5))
{
printf("C语言\\n");
}
//如果a=2或者b=5,就打印C++
if((a==2) || (b==5))
{
printf("C++");
}
return 0;
}
逻辑或操作符相当于现实中说的或者,只要多个条件中满足一个条件,就能继续执行相应的代码
上述代码中,只有最后一个打印C++是a和b的值都不满足的,所以不会打印C++
运行结果:
⑧条件操作符(三目操作符)
exp1 ? exp2 : exp3
>Code Ⅰ:写一个简单的分支逻辑
int main()
{
int a = 10;
int b = 0;
//分支逻辑:
//如果a等于5,就将-6赋值给b;否则将6赋值给b
if(a==5)
{
b = -6;
}
else
{
b = 6;
}
return 0 ;
}
运行结果:
CodeⅠ中的代码,可以通过条件操作符更简洁的实现
>Code Ⅱ:
int main()
{
int a =10;
int b = 0;
b = (a == 5) ? -6 : 6;
return 0;
}
CodeⅡ中,问号前的表达式1为我们需要判断真假的表达式;若表达式1的值为真,则取表达式2结果作为整个表达式得结果;否则取表达式3作为整个表达式的结果
运行结果:
⑨逗号表达式
exp1,exp2,exp3...
>Code Ⅰ:
int main()
{
int a = 0;
int b = 3;
int c = -1;
int d = (a = b - 5, b = a + c , c = a + b , c -= 5);
pritnf("%d\\n", d);
}
上述代码将一个逗号表达式的结果赋值给变量d,逗号表达式会从左向右依次计算;逗号表达式的最后一个结果被作为整个表达式的结果。
计算过程
(1)a = b-5 --> a = -2,b = 3,c = -1
(2)b = a+c -->a = -2,b = -3,c = -1
(3)c = a+b -->a = -2,b = -3,c = -5
(4)c -= 5 -->a = -2,b = -3,c = -10
因为c -= 5
以上是关于C语言学习概览的主要内容,如果未能解决你的问题,请参考以下文章
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段
我的C语言学习进阶之旅解决 Visual Studio 2019 报错:错误 C4996 ‘fscanf‘: This function or variable may be unsafe.(代码片段