1.单位
bit--8--byte--1024--kb--1024--mb--1024--tb--1024--pb (bit为比特位,byte为字节)
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
2.进制转化
以十进制12为例
十进制
1 2
1 * 10^1 + 2 * 10^0 = 12
二进制
1 1 0 0
1 * 2^3 + 1 * 2^2 + 0* 2^1 + 0 * 2^0 = 12
总结:二进制位中从第一位开始对应要乘的数依次成等比数列{1,2,4,8...2^n},故计算时将1或0乘上对应数列中的数即可(例如:1101=8+4+0+1=13)
注:在编写代码时,以数据123的表示方法为例
十进制:123 八进制:0123 十六进制:0x123或0X123
附科学表示法: 12*10^2 = 12e2 或 12E2
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
3.数据类型
char 字符数据类型 1 byte %c
short 短整型 2 byte
int 整形 4 byte %d
long 长整型 4/8 byte %ld
long long 更长的整形 8 byte
float 单精度浮点数 4 byte %f
double 双精度浮点数 8 byte %lf
* 指针 4/8 byte %p
注:int最大表示约9位数,long long最大表示约18位数
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
4.输入输出
输入
scanf
//例 scanf("%d%d",&x,&y):
注:
①需要声明输入格式,存入的对象前面需要加&
②只会读取声明的格式,两个输入值间以空格(若读取格式为字符串,则将其空格转化为\0)作为间隔符,以换行或EOF作为输入结束标志,读取后缓冲区会剩一个\n
③若读取时遇到双引号中未声明的形式,则读取终止,如下
//若x=1,y=2 scanf("%d%d",&x,&y); //正确输入为1 2,输入1a2或1 a 2或1,2或1 , 2都只会读取到1就结束 scanf("%d %d",&x,&y); //正确输入为1 2 scanf("%da%d",&x,&y); //正确输入为1a2,输入1 a 2或其他都只会读取到1 scanf("%d a %d",&x,&y); //正确输入为1 a 2 scanf("%d , %d",&x,&y); //正确输入为1 , 2
gets
//例 gets(str);
注:
①读取缓冲区所有字符
②严格遵循字符串形式,以换行或EOF作为输入结束标志,同时将/n转化为/0
③不安全,会溢出
fgets
//例 char a[10] = {0}; fgets(a, 5, stdin);
注:
①从某个源读取特定长度字符串。第一个参数是存入对象,第二个参数是读取长度,第三个参数是读取源,stdin为标准输入设备即键盘
②安全,不会溢出
getchar()
//例 str[0]=getchar(); getchar();
注:
①从缓冲区读取一个字符,可以只读取数据而不储存起来
②一般与循环搭配使用,在循环以EOF作为结束标志
区别:scanf不能读空格和\n,回车结束;gets能读空格和\n,但\n转化成\0,回车结束;getchar()能读空格和\n
输出
printf
输出格式控制
printf("%011d",x); //输出11位整数x,不足位数用0补全(超过部分原样输出) printf("%-11d",x); //左对齐,在输出结果右边用空格补齐 printf("%11d",x); //右对齐,在输出结果左边用空格补齐 printf("%.3f",x); //输出x保留3位小数:
puts
//例 puts(arr);
注:
①输出字符串
②输出结果自带\n(可以理解为\0转化为\n)
putchar()
//例 putchar('A'); //以下输出结果均为A putchar(65); char ch='A';putchar(ch);
注:
①只输出一个字符
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
4.特定符
关键字
1.数据类型关键字(12个)
- (1)char: 声明字符型变量或函数(1字节)
- (2)short: 声明短整型变量和函数(2字节)
- (3)int: 声明整型变量或函数(2/4字节)
- (4)long: 声明长整型变量或函数(4/8字节)
- (5)float: 声明浮点型变量或函数(4字节)
- (6)double: 声明双精度变量或函数(8字节)
- (7)signed: 声明有符号类型变量或函数
- (8)unsigned: 声明无符号类型变量或函数
- (9)void: 声明函数无返回值或无参数,声明无类型指针
- (10)enum: 声明枚举类型
- (11)struct: 声明结构体变量
- (12)union: 声明共用体(联合)数据类型
2.控制语句关键字(12个)
循环语句
- (1)for: 一种循环语句
- (2)do: 循环语句的循环体
- (3)while : 循环语句的循环条件
- (4)break: 跳出当前循环
- (5)continue: 结束当前循环,开始下一轮循环
条件语句
- (6)if: 条件语句
- (7)else: 条件语句否定分支(与 if 连用)
- (8)goto: 无条件跳转语句
开关语句
- (9)switch : 用于开关语句
- (10)case: 开关语句分支
- (11)default:开关语句中的“其他”分支
返回语句
- (12)return:子程序返回语句(可以带参数,也可不带参数)
3. 存储类型关键字(4个)
- (1)auto: 声明自动变量
- (2)extern: 声明全局变量
- (3)register: 声明寄存器变量
- (3)static:声明全局变量
4. 其他功能关键字 (4个)
- (1)const: 声明只读变量
- (2)sizeof: 计算存储空间
- (3)typedef: 给数据类型取别名
- (4)volatile: 说明变量在程序执行中可被隐含地改变
5. C99新增(5个)
- (1)inline:内联函数,是为了解决C 预处理器宏存在的问题所提出一种解决方案,用来提高函数使用效率。内联函数使用inline关键字定义,并且函数体和申明必须结合在一起, 否则编译器将他作为普通函数对待。
- (2)restric: 关键字只用于限定指针;该关键字用于告知编译器,所有修改该指针所指向内容的操作全部都是基于(base on)该指针的,即不存在其它进行修改操作的途径;这样的后果是帮助编译器进行更好的代码优化,生成更有效率的汇编代码。
- (3)bool:布尔类型,用来表示真或假,零表示假,非零表示真。所有非零的数赋值给布尔型变量,最终的值还是1,包含标准头文件 stdbool.h 后,我们可以用 bool 代替 _Bool ,true 代替 1 ,false 代替 0
- (4)_complex:表示复数,复数类型包括一个实部和一个虚部: 说明变量在程序执行中可被隐含地改变
- (5)_Imaginary:表示虚数,虚数类型没有实部,只有虚部
分隔符
/ # () [] {} ' " ; : ,
运算符(缺)
5.标识符和间隔符
标识符:变量,类型,函数等的名字
规则;①以字母开头②内容仅包括字母和数字③下划线看作字母
(例:"_abc_123"正确,"0abc 123&"错误)
间隔符:用于分离两个相邻的语法单位。包括空格,空白,行结束符,水平制表符,垂直制表符,换页符等
规定:由字面常量组成的两个相邻的语法单位之间至少存在一个间隔符
(例:"#define pi 3.14"正确,"int x,y;"正确,"< ="错误)
6.转义字符
\? 在书写连续多个问号时使用,防止他们被解析成三字母词
\' 用于表示字符常量'
\“ 用于表示一个字符串内部的双引号
\\ 用于表示一个反斜杠,防止它被解释为一个转义序列符
\a 警告字符,蜂鸣
\b 退格符
\f 进纸符
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\ddd ddd表示1~3个八进制的数字。 如: \32 表示ASCII值26对应的字符(八进制32的 十进制值为26)
\xdd dd表示2个十六进制数字。 如: \x61 表示ASCII值97对应的字符(十六进制61的十 进制值为97)
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
7.常量
const 修饰的常变量
#define 定义的标识符常量
枚举常量
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
8.*字符串
定义:由双引号引起来的一串字符。
注:字符串的结束标志是一个\0 的转义字符。在计算字符串长度的时候\0 是结束标志,不算作字符串内容。
以打印字符串test为例:
char arr1[] = "test";
char arr2[] = {'t','e','s','t'};
char arr3[] = {'t','e','s','t''\0'};
*其sizeof和strlen
//sizeof用来计算占有几个字节,包括\0
//strlen用来计算字符串长度,需引头文件,包括\0
char arr1[9] = "abc"; //sizeof为9,strlen为3
char arr2[] = "abc"; //sizeof为4,strlen为3
char arr3[] = {'a','b','c','\0'}; //sizeof为4,strlen为3
char arr4[] = {'a','b','c'}; //sizeof为3,strlen为35(随机值)
//arr1虽然指定大小大于字符串大小,但计算机以9字节的空间存储字符串abc,并不附加内容以补全大小
//arr2和arr3是相同数据的两种不同表达形式,双引号自带\0,大括号不带\0
//arr4由于没有\0,所以字符串长度为随机值
//说明:1个char类型占1个字节
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
*数组
一维数组
以数组{1,2,3}为例:
int arr[3] = {1,2,3}; //该数组内元素对应下标依次为0,1,2 (范围0~+∞)
注:①中括号内数值为数组大小,若填入则指定数组大小,否则自适应
②若指定大小大于实际大小,则默认用0补全(二维数组同样也是),该形式为不完全初始化
printf("%d",arr[0]); //输出结果为1,即第一个元素
二维数组
以矩阵 [1 2 3]为例
[4 5 6]
int arr[2][3]={{1,2,3},{4,5,6}}; //二维数组的两个中括号分别表示行和列
int arr[ ][3]={{1,2,3},{4,5,6}}; //行的初始化可以省略,但列的不行
printf("%c",arr[0][1]); //输出结果为2,即第一行第二列的元素
注:①一二维数组在内存中的储存都是连续的,且相邻地址间差十六进制的4
②数组名可以看作是指针变量,存放的是首元素的地址,例:arr和&arr[0]的打印结果相同且 都是首元素的地址
③&arr打印的结果虽然与前两者相同,但后者打印的是整个数组的地址
④arr+1和&arr[0]+1的结果是下一位元素的地址,&arr+1的结果是该数组外的下一个地址
⑤一维数组本质是列指针,二维数组本质是行指针
*其sizeof和strlen
int arr1[ ] = {1,2}; //sizeof为2*4=8,strlen为1
int arr2[20] = {1,2}; //sizeof为20*4=80,strlrn为1
//说明:1个int类型占4个字节,任何数组字符串长度都为1
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
操作符
单目操作符:
! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--
++ 前置、后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换
关系操作符:
>
>=
<
<=
!= 或 - “不等”
== “相等”
逻辑操作符:
&& 逻辑与
|| 逻辑或
条件操作符:
exp1 ? exp2 : exp3
如果表达式1为真,那么就运行表达式2,否则为表达式3
例如:
if (a == 1)
b = 666 ;
else
b = 233 ;
可以写成
b = ( a == 1 ? 666 : 233 ) ;
逗号表达式
exp1, exp2, exp3, …expN
- 逗号表达式从表达式1开始顺序从左向右执行;
- 其逗号表达式最后的值为最后一个表达式的值;
- 逗号运算的优先级最低,也就说明与其他运算符结合使用的时候,在没有括号的情况下逗号运算符最后才执行。
//用法举例//
//声明变量
int a = 0,b = 0,x = 0,y= 0 ;
//作为表达式
a = (x = 1,y = 2,x + y);//输出结果为3
//for循环
for(a = 0,b = 10;(a < 5)&&(b > 5);a++,b++)
{
printf("%d %d\n",a,b);
}
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
*函数
①库函数
//strcpy
//字符串拷贝,直接将源字符串覆盖到目标字符串上
//由于字符串结束符\0也会被拷贝
//所以输出的结果只会包括被覆盖的内容,多余的部分因为\0而被忽略
//反过来,若源字符串过长则会溢出
//语法
strcpy(str2,str1); //将str1的内容拷贝至str2中
②自定义函数(分有返回值和无返回值两种形式)
实际参数(实参):真实传给函数的参数,叫实际参数。
形式参数(形参):形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用 的过程中才实例化(分配内存单元),所以叫形式参数。
//以加法为例:
//传值调用(有返回值需求)
int Add(int x, int y)
{
int z = x+y;
return z;
}
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
scanf("%d %d", &num1, &num2);
sum = Add(num1, num2); //sum= 这一步体现了这种写法需要返回值
printf("sum = %d\n", sum);
return 0;
}
//以两值互换函数为例
//传址调用(有改变外部变量需求)
void swap(int* x, int* y)
{
int z = 0;
z = *x;
*x = *y;
*y = z;
}
int main()
{
int a = 123, b = 456;
swap(&a, &b); //没有等号,不需要返回值,此函数起到操作作用
return 0;
}
//以下是复合用法函数+指针
//head.h
void search(int x[], int y,int* z); //在头文件中声明后
//主函数中函数的定义就可以放在任意位置
//main.c
#include "head.h"
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int t=9;
int sz= sizeof(arr) / sizeof(arr[0]);
search(arr, sz,&t);
if (t != -1)
printf("FOUND\nIt's NO.%d\n", t);
else
printf("NOT FOUND\n");
return 0;
}
void search(int x[], int y,int* z)
{
int left = 0;
int right = y;
while (left<right-1)
{
int mid = (left + right) / 2;
if (x[mid] > *z)
right = mid;
else if (x[mid] < *z)
left = mid;
else
{
*z = mid;
return 0;
}
}
*z=-1;
}
typedef
含义:类型定义,或类型重命名
typedef unsigned int zhengxing;
int main()
{
unsigned int num1 = 0; //unsigned 声明被修饰数据类型为无符号数据类型
zhengxing num2 = 0;
//num1和num2的类型是一样的
return 0;
}
static
1. 修饰局部变量-称为静态局部变量:可以将局部变量的作用域扩大至整个程序
2. 修饰全局变量-称为静态全局变量:可以将全局变量的作用域缩小至其所在源文件
3. 修饰函数-称为静态函数:可以将函数的作用域缩小至其所在源文件
#define
#define又称宏定义,标识符为所定义的宏名,简称宏。#define 的功能是将标识符定义为其后的常量。一经定义,程序中就可以直接用标识符来表示这个常量,且不能被赋值
定义标识符常量:
#define _CRT_SECURE_NO_WARNINGS //scanf不报错
定义宏:
#define ADD(x,y) ((x)+(y)) ;
#define ADD(x+y) ;
//以上ADD在程序中代表表达式x+y
*指针
//取出并打印变量地址
int main()
{
int num = 10;
# //这里num的4个字节,每个字节都有地址,取出的是第一个字节的地址(较小的地址)
printf("%p\n", &num);
return 0;
}
//利用指针变量储存变量地址
int main()
{
int num = 10;
int* p;
p = # //指针变量只能被赋值变量的地址
return 0;
}
//另一种直接写法
int main()
{
int num = 10;
int* p= #
return 0;
}
//利用指针变量修改变量的值
int main()
{
int a = 10;
int* pa = &a;
*pa = 20; //*为解引用操作符,使得我们能通过指针变量间接对变量的值进行修改
//在解引用前,pa只是a的内存地址
return 0;
}
注:指针变量的大小只取决于地址的大小
32位平台下地址是32个bit位(即4个字节)
64位平台下地址是64个bit位(即8个字节)
*结构体
//结构体单独定义
struct student
{
char name[20]; //名字
int age; //年龄
char sex[5]; //性别
char id[15]; //学号
};
//结构体单独声明
struct student xiaoming={"xiongming",18,"male","12345"};
//结构体同时声明和定义
struct student
{
char name[20]; //名字
int age; //年龄
char sex[5]; //性别
char id[15]; //学号
}xiaoming={"xiongming",18,"male","12345"};
//以复数加减乘法运算为例
#include<stdio.h>
//结构体定义
struct complex
{
float real;
float imag;
};
//结构体类函数声明
struct complex add(struct complex c1, struct complex c2);
struct complex subtract(struct complex c1, struct complex c2);
struct complex multiply(struct complex c1, struct complex c2);
void complexprint(struct complex c);
//主函数
int main()
{
float r1, i1, r2, i2;
scanf("%f%f%f%f", &r1, &i1, &r2, &i2);
struct complex c1 = { r1,i1 }, c2 = { r2,i2 };
complexprint(add(c1, c2));
complexprint(subtract(c1, c2));
complexprint(multiply(c1, c2));
}
//打印功能函数
void complexprint(struct complex c)
{
if (c.imag > 0) printf("%.2f+%.2fi", c.real, c.imag);
else if (c.imag < 0) printf("%.2f%.2fi", c.real, c.imag);
else printf("%.2f", c.real);
}
//加法功能函数
struct complex add(struct complex c1, struct complex c2)
{
struct complex result;
result.real = c1.real + c2.real;
result.imag = c1.imag + c2.imag;
return result;
}
//减法功能函数
struct complex subtract(struct complex c1, struct complex c2)
{
struct complex result;
result.real = c1.real - c2.real;
result.imag = c1.imag - c2.imag;
return result;
}
//乘法功能函数
struct complex multiply(struct complex c1, struct complex c2)
{
struct complex result;
result.real = c1.real * c2.real- c1.imag * c2.imag;
result.imag = c1.real * c2.imag + c2.real * c1.imag;
return result;
}
分支语句
if语句:
//第一种
if(表达式)
{
语句;
}
//第二种
if(表达式)
{
语句;
}
else
{
语句;
}
//第三种
if(表达式)
{
语句;
}
else if(表达式)
{
语句;
}
else
{
语句;
}
switch语句
//例子
int main()
{
int day = 0;
switch(day)
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("weekend\n");
break;
default: //当switch表达式的值并不匹配所有case标签的值时,这个default子句后面的语句就会执行
break;
}
return 0;
}
循环语句
break:终止本次循环
coutine:跳过本次循环
while(表达式)
{
循环语句;
}
for(表达式1; 表达式2; 表达式3)
{
循环语句;
}
//表达式1进行变量初始化,表达式2进行条件判断,表达式3进行变量调整
//循环语句在表达式2判断为真之后才会执行
*递归
//通过递推实现strlen函数
int newstrlen(char* str)
{
if (*str != '\0')
return 1 + newstrlen(str + 1);
else
return 0;
}
int main()
{
char str[] = "string";
printf("%d\n",newstrlen(str));
return 0;
}
迭代
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
算法
//栈判断括号匹配问题
#include <stdio.h>
#include <stdlib.h>
char ch, stack[1000];
int left=0;
void push(void); char pop(void); void check(char left, char right);
int main()
{
do
{
ch = getchar();
switch (ch)
{
case '(':
case '[':
case '{':push(); break;
case ')':check(pop(), '('); break;
case ']':check(pop(), '['); break;
case '}':check(pop(), '{'); break;
}
} while (ch!='@');
printf("YES");
return 0;
}
void push(void)
{
stack[left++] = ch;
}
char pop(void)
{
if (left > 0)
return stack[--left];
else
{
printf("NO");
exit(0);
}
}
void check(char left, char right)
{
if (left != right)
{
printf("NO");
exit(0);
}
}