本文记录C语言学习的基础内容。
一、基本数据类型
(一)变量的定义
定义格式:变量类型 变量名;
或变量类型 变量名 = 初值;
变量名命名注意事项:
- 不能使用C语言标识符;
- 变量名的第一个字符必须是字母或下划线,除第一个字符之外的其他字符必须是字母、数字或下划线;
- 区分大小写。
(二)变量类型
1、整型
整型一般分为短整型、整型和长整型,短整型一般用不到,这里只介绍整型和长整型。
(1)整型
占用32bit,4Byte,取值范围是(-2^31-+(2^31-1)。10^9以内的整数都可以定义为int型。
int num = 5; |
(2)长整型
占用64bit,8Byte,取值范围是(-2^63-+(2^63-1)。10^10以外的整数都可以定义为长整型。
long long bignum; |
补充: unsigned int
和unsigned long long
的取值范围分别为0-2^32-1和0-2^64-1。
2、浮点型
(1)单精度浮点数
一个浮点数占用32bit,其中1bit作为符号位,8bit作为指数位,23bit作为位数位,可以存放的浮点数范围是-2^128-+2^128,但有效精度只有6-7位,对于精度要求比较高的场景不合适。
float f1; |
(2)双精度浮点数
一个浮点数占用64bit,其中1bit作为符号位,11bit作为指数位,52bit作为位数位,可以存放的浮点数范围是-2^1024-+2^1024,但有效精度只有15-16位。
double db; |
3、字符型
(1)字符变量
char c; |
(2)转义字符
printf("%d\n\n%d",1,3); |
(3)字符串常量
|
4、布尔型
在C++中可以直接使用,但在C语言中必须天剑stdbool.h
头文件才可以使用。
|
(三)强制类型转换
格式:(新类型名)变量名
|
(四)符号常量和const常量
符号常量:又称为替换,宏定义或者宏替换。#define 标识符 常量
。
const常量:const 数据类型 变量名 = 常量
const double pi = 3.14; |
常量定义后无法改变。
|
输出:5 4
(五)运算符
1、算术运算符
+ - * / % ++ --
。++i
VSi++
:
i++是先使用再讲i加1,++i是先将i加1再使用i。
2、关系运算符
< > <= >= == !=
。
3、逻辑运算符
运算符 | 含义 | 语法 | 返回值 |
---|---|---|---|
&& | 与 | a&&b |
ab都真,则返回真 |
` | ` | 或 | |
! | 非 | !a |
如果a为真,则返回假 |
4、条件运算符
三目运算符:A?B:C;
,含义是:如果A为真,那么执行并返回B的结果;如果A为假,那么执行并返回C的结果。
|
5、位运算符
运算符 | 含义 | 语法 | 效果 |
---|---|---|---|
<< |
左移 | a<<x |
整数a按二进制位左移x位 |
>> |
右移 | a>>x |
整数按二进制位右移x位 |
& |
位与 | a&b |
整数a和b按二进制对其,按位进行与运算(除了11得1,其他均为0) |
` | ` | 位或 | `a |
^ |
位异或 | a^b |
整数a和b按二进制对齐,按位进行异或运算(相同为0,不同为1) |
~ |
位取反 | ~a |
整数a的二进制的每一位进行0变1、1变0的操作 |
二、顺序结构
(一)赋值表达式
int n = 5; |
(二)使用scanf和printf输入/输出
1、scanf函数使用
scanf("格式控制",变量地址)
。
数据类型 | 格式符 | 举例 |
---|---|---|
int | %d | scanf("%d",&n) |
long long | %lld | scanf("%lld",&n) |
float | %f | scanf("%f",&f1) |
double | %lf | scanf("%lf",&db) |
char | %c | scanf("%c",&c) |
字符串(char数组) | %s | scanf("%s",str) |
在scanf中,除了char数组整个输入的情况下不加&之外,其他变量类型都需要加&。
如果输入3 4
这种用空格隔开的两个数字,两个%d之间可以不加空格。可以不加空格的原因是:除了%c外,scanf对其他葛师傅的输入是可以以空白符为结束判断标志的,因此除非使用%c把空格字符读入,其他情况都会自动跳过空格。另外,字符数组使用%s读入的时候以空格跟换行为读入结束的标志。
2、printf函数
printf("格式控制",变量名称);
数据类型 | 格式符 | 举例 |
---|---|---|
int | %d | printf("%d",n) |
long long | %lld | printf("%lld",n) |
float | %f | printf("%f",f1) |
double | %f | printf("%f",db) |
char | %c | printf("%c",c) |
字符串(char数组) | %s | printf("%s",str) |
两个浮点数相乘时使用double类型。
%和\的输入:printf("%%");printf("\\")
(1)%md
%md可以使不足m位的int型变量进行右对齐输出,其中高位用空格补;如果变量本身超过m位,则保持原样。
(2)%0md
%md可以使不足m位的int型变量进行右对齐输出,其中高位用0补;如果变量本身超过m位,则保持原样。
(3)%.mf
%.mf可以让浮点数保留m位小数输出,这个“保留”使用的是精度的“四舍六入五成双规则”。
(三)使用getchar和putchar输出输出字符
|
输入数据:abcd
,输出结果:acd
。
(四)注释
1、”/**/“
注释若干连续行的内容。
2、”//“
注释一行中在该符号之后的所有内容,效果仅限于改行。
(五)typedef
可以给一个很复杂的数据类型起一个别名。
|
(六)常用math函数
1、fabs(double x)
printf("%.2f",fabs(-12.56)); |
输出结果:12.56
2、floor(double x)和ceil(double x)
printf("%.0f %.0f",floor(5.2),ceil(5.2)); |
输出结果:-6 -5
5 6
3、pow(double r,double p)
printf("%f\n",pow(2.0,3.0)); |
输出结果:8.00000
4、sqrt(double x)
printf("%f\n",sqrt(2.0)); |
输出结果:1.414214
5、log(double x)
printf("%f\n",log(1.0)); |
输出结果:0.00000
6、sin(double x)、cos(double x)、tan(double x)
7、round(double x)
三、选择结构
(一)if语句
|
(二)switch语句
|
四、循环结构
(一)while语句
|
(二)do…while语句
|
(三)for语句
|
(四)break和continue语句
break是跳出整个循环,continue是跳出当前轮回,进入下一个轮回。
五、数组
(一)一维数组
|
(二)冒泡排序
|
(三)二维数组
|
(四)memset-对数组中每一个元素赋相同的值
格式:memset(数组名,值,sizeof(数组名))
。
使用menset需要在程序开头添加string.h头文件,且只建议初学者使用memset赋值0或-1。这是因为memset使用的是按字节赋值,即对每个字节赋同样的值,这样组成int型的4个字节就会赋成同样的值。0的二进制补码为全0,-1的二进制补码为全1,不容易出错。赋值其他数字使用fill函数。
|
(五)字符数组
1、scanf输入,printf输出
|
注意:%s通过空格或字符来识别一个字符串的结束。
2、getchar输入,putchar输出
|
3、gets输入,puts输出
gets用来输入一行字符串(注意:gets识别换行符\n作为输入结束,因此scanf完一个整数后,如果要使用gets,需要先用getchar接收整数后的换行符),并将其存放在一维数组(或二维数组的一维中);puts用来输出一行字符串,即将一维数组(或二维数组的一维)在界面中输出,并紧跟一个换行。
|
(六)string.h头文件
1、strlen()
计算字符数组中第一个\0
前的字符的个数。
|
2、strcmp()
返回两个字符串大小的比较结果,比较原则是按字典序。
|
3、strcpy()
把字符数组2复制给字符数组1,这里的复制包括了结束符\0
。
|
4、strcat()
把字符数组2接到字符数组1互后面。
|
(七)sscanf与sprintf
1、sscanf函数
|
输出:123
。把str的内容以“%d”的格式写到n中(从左至右)。
2、sprintf函数
|
输出:233
。把n以”%d”的格式写到str字符数组中(从右至左)。
六、函数
(一)函数的定义
1、全局变量
|
输出结果:11
2、局部变量
|
输出结果:10
(二)main函数
主函数对于一个程序来说只能有一个,并且无论主函数写在哪个位置,整个程序一定是从主函数的第一个语句开始执行,然后在需要调用其他函数时才去调用。
(三)以数组作为函数参数
函数的参数也可以是数组,且数组作为参数时,参数中数组的第一位不需要填写长度(如果是二维数组,那么第二维需要填写长度),实际调用时也只需要填写数组名。数组作为参数时,在函数中对数组元素的修改就等同于对原数组元素的修改。
|
输出结果:1 3 5
。
数组可以作为参数,但是却不允许作为返回类型出现。如果想要返回数组,只能传数组进去。
(四)函数的递归调用
|
七、指针
(一)什么是指针
在C语言中用“指针”来表示内存地址,而如果这个内存地址恰好是某个变量的地址,那么又称“这个指针指向该变量”。指针是一个unsigned类型的整数。
(二)指针变量
|
输出结果:233,233
指针变量也可以进行加减法,其中减法的结构就是两个地址偏移的距离。对一个int*型的指针变量p来说, p+1是指p所指的int型变量的下一个int型变量地址。
(三)指针与数组
|
(四)使用指针变量作为函数参数
|
八、结构体的使用
(一)结构体的定义
struct StudentInfo { |
StudentInfo为结构体的名字,内部分别定义了id、gender、name和major,这些是单个学生的信息。大括号外定义了结构体变量Bob,后面的stu[1000]就是当有很多学生时定义的一个结构体数组。
注意:结构体里面能定义除了自己本身之外的任何数据类型。不过虽然不能定义自己本身,但可以定义自身类型的指针变量。
struct Node { |
(二)访问结构体内的元素
struct StudentInfo { |
访问stu中变量:
stu.id |
访问指针变量p中元素:
(*p).id |
(三)结构体的初始化
单个赋值:
stu.id = 1; |
或:
scanf("%d %c",&stu.id,&stu.gender); |
定义多个构造函数:
struct StudentInfo { |