本文为作者本人笔记,来源为网上的视频和文章。如有错误,请批评指正。
各种符号和运算符
各种字符和常量
整型常量:整数
实型常量:
①十进制小数:如123.456 0.789
②指数形式:由于计算机输入或输出时无法表示上标和下标,所以规定以字母e或E代表以10为底的指数,需要注意的是E和e之前必须要有数字,且e和E后面必须为整数,不能写成e4 12e2.5
如:12.34e3(表示12.34103) -37.89e-16(表示-67.8910-16)等
字符常量:
①普通字符常量:用单引号 如:‘a’ ‘@’ ‘#’不能写成‘ab’或‘12’
②转义字符:
\n
换行\t
水平制表符\'
单引号\"
双引号\?
问号\\
斜杠\a
警告声音提示\b
退格删除符\f
换页符\r
回车\v
垂直制表符\.
八进制形式\x
十六进制形式 等字符对齐:
%8d
: 右对齐,且占8个字符(空格在数字左边凑位数)
%-d
: 强制左对齐
%-8d
: 左对齐,且占8个字符(空格在数字右边凑位数)
%.3lf
: 保留三位有效数字
%+d
: 输出自带±号
%e
:以指数形式输出数据
%p
:输入地址
%s
:用来输出字符串的格式占位符
%g
: 自动选择合适的表示法输出*打印不同进制的数:*
八进制:%o
十进制:%d
十六进制:%x
显示不同进制的前缀:
八进制:%#o
十进制:%#x
十六进制:%#X字符串常量:如
abc``123
用双引号符号常量:用
#define
指令指定一个符号代表一个常量注:在需要改变程序中多处用到了同一个常量时,能够做到“一改全改”。
如:
#define PI 3.1415926
(注意末尾没有分号)地址常量:每一个常量、变量、数组的地址在程序运行期间是不能够改变的,称为地址常量
基本数据类型
Int(整数)、char(字符型)、float(单精度浮点型)、double(双精度浮点型)、long(长整型)、short(短整型)
单精度:精确到小数点后6-7位
双精度:精确到小数点后16-17位
编译器默认小数类型为double
高精度:精度高,比如说能计算到小数点后10位
低精度:精度低,比如说能计算到小数点后2位
基本数据类型之间,是可以转换,如果是计算,会往高精度转
小数和整数之间转换,如果把一个小数数据赋值给你一个整型变量,那么整型变量只会保留整数部分,小数部分会被省略掉
数据类型 | 关键字 | 内存大小(字节) |
---|---|---|
整型 | int | 4 |
无符号整型 | unsigned int | 4 |
短整型 | short | 2 |
无符号短整型 | unsigned short | 2 |
长整型 | long | 4 |
无符号长整型 | unsigned long | 4 |
双长整型 | long long | 8 |
无符号双长整型 | unsigned long long | 8 |
小数类型 | 精度 | 字节大小 |
---|---|---|
float | 单精度 | 4 |
double | 双精度 | 8 |
long double | 长双精度 | 8 |
ASCII码表
格式占位符:
int(%d) char(%c) float(%f) double(%lf)
在输出小数时,默认输出小数点后6位,,不够补0,多了四舍五入
{
getchar()
从键盘获取一个字符}
运算符
算术运算符
自增、自减运算符
前缀:
a++
先自增再参与运算后缀:
++a
先参与运算再自增
关系运算符
关系表达式的结果只有两种:真(1)和假(0)
逻辑运算符
位运算符
左移:<< 左移相当于乘以2的n次方,移几位就乘以2的几次方
右移:>> 右移相当于除以2的n次方,移几位就除以2的几次方
按位非(取反):~ 二进制1变0,0变1 二进制数最高位表示符号位,0正数,1负数
按位或:| 对应位置,有1则为1,否则为0
按位与:& 对应位置,都为1则为1,否则为0
按位异或:^ 对应位置,相同为0,不同为1
二进制数
二进制数:原码 反码 补码正数原码:0000 0000 0000 0000 0000 0000 0000 0001
反码:0000 0000 0000 0000 0000 0000 0000 0001
补码:0000 0000 0000 0000 0000 0000 0000 0001
负数原码:0000 0000 0000 0000 0000 0000 0000 0001
反码:1111 1111 1111 1111 1111 1111 1111 1110
补码(=反码+1):1111 1111 1111 1111 1111 1111 1111 1111
赋值运算符
b+=a;//b=b+a
b-=a;//b=b-a
b*=a;//b=b*a
b/=a;//b=b/a
b%=a;//b=b%a
逗号运算符和强制类型转换
条件运算符: 表达式1?表达式2:表达式3
表达式1的结果为真,执行表达式2,否则执行表达式3
例如:
int main()
{
int a=10;
int b=2;
a>b?a=11:b=11;
//printf(“%d\n”,a)的输出结果为11
}
循环和分支
流程控制
顺序结构:顺序结构的程序设计是最简单的,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自下而上从左至右,依次执行。
分支结构:分支结构是依据一定的条件选择执行的路径,而不是严格按照语句出现的前后顺序执行。
循环结构:循环结构是依据一定的条件重复执行某一句或某几句代码,是为反复做某个操作而设置的一种程序结构
选择分支结构
If选择结构
基本格式:
if(表达式)
{
语句1;
}
else if(表达式2)
{
语句2;
}
else
{
语句3;
}
执行流程:
首先判断if之后的条件表达式的逻辑值,如果逻辑为真则执行语句1,否则如果逻辑为假则不执行语句1,如有
else
则执行else
之后的语句2(else
语句可有可无)
switch多分支结构
基本格式:
switch(表达式)
{
case 常量1:语句1;break;
case 常量2:语句2;break;
……
case 常量n:语句n;break;
default:语句n+1;
}
执行流程:
首先判断
switch
之后的表达式的值,如果这个值和case
之后的某个常量相等则执行对应case
之后的语句,若与所有值都不相等,则执行default
之后的语句
循环结构
for循环
基本格式:
for(表达式1;表达式2;表达式3)
{
循环体;
}
//表达式1:初始化语句,只有开始循环时才执行一次
//表达式2:循环的判定条件
//表达式3:循环条件的改变
//循环体;需要重复执行的代码段
//注意:表达式之间的分隔符;不能少
执行流程:
首先执行初始化语句,然后判断条件,如果条件满足则继续执行循环体,否则结束循环。
数组
数组元素基本格式:数组名[下标]
数组:数据的组合,数据类型相同、内存连续的集合
数组的初始化: 数组={存储的数据}
数组的定义格式: 类型说明符 数组名[数组的大小]
数组名:必须是合法的标识符,满足规则和规范
数组大小:是一个常量,或者是一个字符
数组中的数据的访问:通过下标来访问,下标可以理解为某个数据的编号
数组的下标的表示方法:
数组名[数组下标]
数据是占内存的,并且操作系统会给你随机分配内存地址编号
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
printf("%d\n", arr[4]);//5
scanf("%d", &arr[4]);//55
例:
arr[i]是一个数,输入时要加&(取地址符),而arr是一个数组不需要&
注意:数据的序号是从0开始的
不给数组大小时,必须给数组初始化,那么初始化数据的个数就是数组的大小
未初始化部分的数据会被系统自动默认为0
Maxsize
:数组能够储存的数据最大个数
len
:当前数组已经储存了多少个数据
二维数据的定义: 类型说明符 数组名[数组大小][数组大小]
二维数组的是一行一行的赋值
//二维数组的几种初始化方式:
int arr [2][3]={{1,2,3},{3,2,1}
int arr[2][3]={1,2,3,3,2,1}
int arr[2][3]={
{1,2,3},
{3,2,1}
}
//三维函数:
int arr[2][4][3]={
{{1,2,3},{4,5,6},{7,8,9},{10}},
{{1,2,3},{4,5,6},{7,8,9},{10}}
}//输出arr[1][2][1]的结果为8
字符数组
字符数组:存储字符类型数据的集合
int c = a > b ? a : b; //它与下面的语句等效: int c; if (a > b) c = a; else c = b; c++
printf(“%s”,数组名);
//输出数组中全部数据\0表示字符串的结尾(在输入和输出时等于空格)
%s表示输出到字符串\0的位置
中文也是字符,但是一个汉字占两个字符
gets(数组名)
;输入数据
puts(数组名)
;输出数据
strcmp(数组1,数组2)
用来比较两个字符串比较完后返回一个结果
0表示数组1=数组2
大于0表示数组1>数组2
小于0表示数组1<数组2
预处理
预处理是编译之前做的一些事情
初学c语言者可不考虑
常用的预定义符号:
__FILE__ //当前编译的文件的名字路径
__FUNCTION__ //当前所在函数的函数名
__DATE__ //当前编译日期
__TIME__ //当前编译日期
//以上格式占位符都用%s
__LINE__ //当前行数 格式占位符%d
//注意:以上这些宏定义的前后分别有两个’_’,而不是一个下划线
_CRT_SECURE_NO_WARNINGS //关闭安全检查
宏
宏定义的本质是替换
宏定义:一改全改
宏定义-无参宏 #define 宏名 内容
//如:
#define pi 3.1415926
//带参宏定义
//带参宏类型一个函数,带参宏的参数是没有类型的,带参宏没有返回值
//带参宏定义 #define 宏名(参数列表) 内容
#define FUN(a,b) {printf("%d,%d\n",a,b);printf("%d\n",a+b);}
int main()
{
printf("%d\n",FUN(1,2));
//输出结果:
//1,2
//3
}
注意:宏定义的本质是替换
常量的定义
const int a = 10;
注意:常量必须初始化,常量不允许被修改
头文件
<stdlib.h>
!
<string.h>
C标准要求在使用字符串函数时要包含头文件string.h,在使用字符函数时要包含ctype.h
文件操作
文件:①文本文件②二进制文件
编译器:源文件(.c/.cpp)<–>二进制文件(.obj)
操作数据文件
-
打开文件:通过定义文件指针指向文件
文件指针的定义: FILE * 名字
-
用文件指针指向文件
fopen("文件路径","打开方式");
//如:
file = fopen("1.txt","w");
文件路径:①绝对路径②相对路径
如果文件存在,直接覆盖文件内的内容写入。
如果文件不存在,会自动创建这个文件
-
文件操作:通过函数对文件中的数据进行操作
-
关闭文件:
fclose(file);
/*向文件中写入一个字符*/
fputc('c',file);//向文件file中写入一个c
//换行为一个字符
fputc('\n', file);
/*向文件中写入一个字符串*/
fputs(“sdsd”,file);//向文件file中写入sdsd
char arr[] = “dsdsd”;
sputs(arr,file);//向文件file中写入dsdsd
fprintf(file,"%d %s\n",a,str);//向文件中输出一个整数和字符串
fwrite(&a,//写入的东西
4,//写入数据的字节大小
1,//写入的个数
file);
/*读取一个字符*/
char c;
c = fgetc(file);
printf("%c\n", c);//读取file中一个字符
/*读取字符串*/
char arr[1024] = { 0 };
fgets(arr,3,file);//读取长度为2的字符串(\0占一个字符)
fread(&a,//读到哪里去
4,//读取的字节大小
1,//读取的个数
file);
while(!feof(file))//判断文件指针释放读到了末尾,到了返回一个真,否则返回一个假
{
}
//文件指针移动
fseek(file,
1,//移动的字节数 正数往后移动 负数往前移动
2);//从哪个位置开始移动(0:文件开头 1:文件指针当前位置 2:文件指针末尾的位置)
ftell();//获取文件指针的偏移量
注意:图片是以二进制形式存储的,要以rb的方式打开。
结构体
*自定义数据类型*
结构体类型的声明和结构体变量的定义:
声明一个结构体类型的一般形式为:
struct 结构体类型名{成员列表}
//定义了一个名字叫做Student的结构
struct Student
{
int ID;
char name[10];
float score;
}
Student ab = {2, "李四", 90.9f};
可以使用tyoedef
给类型取别名
当数据成员面前有更大的数据类型所占内存,先按照顺序进行最大的数据类型进行内存分配对齐
如果在最后还有比前面更大的基本数据类型所占内存,那么就按照更大的进行对齐
共用体
共用体关键字:union
内存储存:共用体所有成员共用里面最大的成员的空间,在同一时刻只能存一个成员的值,但是要以共用体中最大的基本数据类型所占内存对齐
枚举类型:enum
内存大小:就是int类型所占内存大小。
枚举的元素有默认的值,为整数,第一个第二个第三个……的默认值依次为0 1 2……
指针
地址:数据在内存中的存储位置编号,是常量
指针:指针的本质就是地址
指针变量:存储的数据是地址
指针是有类型的,指针的类型就是定义的时候——类型*
类型* 标识符;
取地址符:&
指针变量取了谁的地址,就指向谁
*
的作用:指针变量的标志
*
:解引用 取内容
指针变量所占的内存大小为4字节
*定义指针的时候,要马上给指针变量赋值,防止出现野指针*
*NULL:空*
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
for(int i = 0; i < 10; i++)
{
printf("%p\n", &arr[i]);
}
int *p = arr;
p+=9;//指针偏移
printf("%d\n", *p);
*指针函数和函数指针*
指针函数:是一个函数,但是这个函数的返回值类型是一个指针。
函数指针:是一个指针,这个指针的指向是一个函数。
函数指针的定义格式:
函数的返回值类型 (*函数指针名) (函数的形参列表)
typedef int (*pF) (int,int);//函数指针取别名,别名就是他自己(pF)
常量指针:定义不用初始化,能改变指向,指向的内容不能被修改。
作用:保护实参不被函数形参调用修改。
指针常量:定义的时候必须要初始化,不能改变指向,可以改变指向的内容。
*大端存储和小端存储*
数据的地址: 0x12345678 存储到0x0-0x3这四个字节当中
大端存储: 0x0[12] 0x1[34] 0x2[56] 0x3[78]
小端存储: 0x0[78] 0x1[56] 0x2[34] 0x3[12]
*数组指针和指针数组*
指针数组:是一个数组,存储的是指针。
数组指针:是一个指针,指向的是一个数组(至少是二维数组)。
数组名本身就表示这个数组的首地址。
/*数组指针的偏移*/
//如有定义:
int arr[3][4];
int (*p)[4];
p = arr;
p++;//移动一整行,也就是4个int的大小,通过两次解引用可得到元素值
*(*(p+i)+j);//可以把数组指针理解成为二级指针,通过两次解引用得到元素值
p[i][j];//指针带数组下标的形式访问数组元素
*(p[i]+j);//一半下标一半解引用
(*(p+i))[j]
*内存四区*
栈区:存储局部变量,系统会自动申请内存和释放内存。
堆区:手动申请的内存区域,需要我们自己手动释放。
代码区:存储是的函数等等。
静态全局区:存储的静态和全局变量数据,内存只会存在一份,只会初始化一次
结构体指针
结构体指针访问成员通过->进行访问
动态内存分配:从堆区申请内存,自己使用
通过函数 malloc
calloc
realloc
(默认类型均为void
)
赋值的条件:类型相同
从堆区申请的内存都是通过指针执行管理的
在函数里面申请的堆区内存,不会随着函数结束而释放,需要手动释放
使用free函数进行释放:free();
(需要用到头文件stdlib.h
)
在释放内存时,在free函数中填的指针,必须要指向内存的首地址
堆区的内存是比较大的,比栈区大
//malloc
int *p1 = (int *)malloc(sizeof(int)* 25);//申请25个int大小的内存(即4*25字节)
//memset
memset(p1, 0, sizeof(int)* 25);//逐字符赋值(需要用到头文件string.h)(默认赋值为0)
//realloc
int *p = (int *)realloc(p, sizeof(int)* 50);//重新分配内存,不会初始化
//calloc
int *p = (int *)calloc(25, sizeof(int));//默认初始化为0
附件
清楚控制台内的内容
#include<window.h>
sysrem(“cls”)//清楚控制台内的内容
VS scanf不报错代码
#define _CRT_SECURE_NO_WARNINGS 1