冒泡排序没有查找的步骤,而是不断前后交换,做n次
选择排序是先找到目前最大的元素排到后方
插入排序类似于扑克的整理手牌
fabs()是绝对值函数
for(,,)是个死循环
switch()的括号里可以是变量;case后可以是1+1,a
n=z也是表达式,计算结果是n
%的前后都要是整数,结果的符号与左值相同 /则无要求,当两边都是整形时,结构也是整形
对正数来说,补码就是源码;对负数来说,补码是源码的首位符号码不变,剩下所有位数取反,最后再加一
当变量发生上溢时,会被赋一个表示无穷大的特定值
字符宽度包括整数部分、小数部分和小数点
若要输出对象的实际宽度大于指定宽度,会无视要求全部输出
%20.2d 表示输出一个小数点后有2位的十进制数,打印宽度为20
%010.2f 第一个0表示用0填充以满足字段宽度要求,10表示字段宽度,2表示小数点后有2个数字,f表示打印一个浮点数
(double)1/2的值是0.500000,实际是1.0/2
getchar()有时用来吸收回车字符,返回类型是int
putchar()返回类型是int,返回-1表示输出失败
getche()读取一个字符后无需回车马上输入,有回显
getch()读取一个字符后无需回车马上输入,无回显
gets()在读取字符串时不会遇空格停止,只有按下回车才读取完成,与scanf("%s",a)不同
%d:十进制 %o:八进制 %x:十六进制 %#o:带前缀地打印八进制 %#x:带前缀地打印十六进制
%lf仅用于十进制输入double,输出double用%f
%e用指数计数法打印浮点数;%g会自动选择%f或%e打印浮点数,会去除浮点数后面多余的0
sizeof(a)以字节为单位给出a的大小,返回类型是size_t,对应的是%zd
符号常量尽量大写
短路:逻辑运算时,若左侧已能决定结果,则右侧不会进行运算,例:a=-1, a>0&&a++>-1 之后a仍是-1
欧几里得算法(求最大公约数) int a,b; a%b=d a=b,b=d 当余数为0是,b就是最大公约数
自定义函数若写成int a(),则是告诉编译器我也不知道参数具体情况;若无参数应写成int a(void)
,也是运算符,结果值为右侧的值;但更多情况下只是个标点符号
一个函数中不能放另外一个函数的body,仅能放声明(函数头)
若int a[ ] = { [0] = 1, [2] = 5,6 };则a[0] = 1, a[2] = 5, a[3] = 6,其他值都是0
数组变量其实是const的指针,所以不能被赋值,例:int a[ ],b[ ]; b = a; 就不合法
scanf("%7s",a)限制了最多读取7个字符,且不再遇空格即停止;剩下的部分会自动给下一次scanf
Tab键不是输出4个空格,而是把光标移到固定的下一个预定位置
\n是换行 \r是回车
函数指针:int (*a)()
数组指针:char(*a)[5] 指针a指向一个长度为5的字符数组,*a等同于数组的首地址,**a等同于数组的第一个值,a+1则是把地址后移20(4*5)
两个相邻的字符串会自动串起来
char *s = "hello,world"; s[0] = 'B'就非法。因为这时s的定义其实是const char *s,被放入一个只读的地方(代码段),无法修改。而且如果有chart *s2 = "hello,world",则s与s2指向一个地方,因为是先在内存中有一个"hello,world",再让指针指向它
所以如果要一个能修改的字符串就要用数组,如果无需修改就用指针
取地址符&带出的结果不一定与int大小相同,所以最好用%p,而不是%x
char *s,这时scanf("%s",s)是非法的
printf("%f",2)会打印出0.000000
const在*之后:指针是const,不能再指向其他变量,int *const q=&a;
const在*之前:指针与变量都可以变,只是无法通过指针修改变量,const int *p=&a;
void f(const int *p)的意义是函数保证不会修改地址p对应的值
const int a[]={1,2,3,4}; //数组本身就是const的指针,这里的意义是让数组的每一位都变成const
*p++ , ++的优先级比*高,意义是先取出p对应的值,再把p移到下一个位置
指针可以比较大小,比较的是值,即所指变量地址的大小
0地址用处:1.函数返回0地址,表示失败、拒绝 2.初始化时指向0,等于未真正初始化,因为0地址不能访问,所以帮助后面排查问题
int *a与char *b大小相同,但不能相互赋值
void *表示不关心所指对象的类型,可以得到int *的值,但此时通过void *访问int对象,编译器就不会在意它是int了
%s输出__func__(预定义宏)会显示当前函数名,如"main"
文本文件(ASCII文件)中,每一个显示的字符都单独占空间用ASCII表示,二进制文件则会依据实际内容决定空间
优先级:
1. ()
2. ! + - ++ --
3. * / %
4. + -
5. << >>
6. < > <= >=
7. == !=
8. ^ 9. & 10. |
11. && 12.||
13. ? :
14. = += -= *= /= %=
15. ,
二分查找:
int search(int s[],int n,int k)
{
int bottom=0,top=n-1,mid;
while(bottom<=top)
{
mid=(top+bottom)/2;
if(k<s[mid]) top=mid-1;
else if(k>s[mid]) bottom=mid+1;
else return mid;
}
return -1;
}
判断素数:
int prime(int n)
{
for(int t=2;i<=(int)sqrt(n);i++)
{
if(n%i==0) return 0;
}
return 1;
}
八进制字符串转换为十进制整数:
int change(char s[])
{
int i,n;
i=n=0;
s[i]=='0'?i+=1:i;
for(;s[i]!='\0';i++)
{
if(s[i]>='0'&&s[i]<='7')
n=n*8+s[i]-'0';
}
return n;
}
冒泡排序:
void sort(int a[],int n)
{
int flag=1;
int gj;
for(int i=0;flag&&i<n-1;i++)
{
flag=0;
for(int j=0;j<n-i-1;j++)
{
if(a[j]>a[j+1])
{
gj=a[j],a[j]=a[j+1];a[j+1]=gj;
flag=1; //注意flag
}
}
}
}
字符串函数:
strcat(a,b); //把b拷贝到a后面,形成一个大字符串,但a必须要有足够的空间,返回值为a
//所以strcpy与strcat都可能会出现没有足够空间的情况,不够安全,不推荐用
//安全版本:strncpy,strncat
strncmp(a[],b[],t); //只比较前t个字符的大小
char * strchr(const char*s,int c); //是查找函数,从左往右查找字符c第一次出现的位置
//从右往左查找的版本是strrchr,如果没有找到会返回NULL\
利用strchr查找字符c第二次出现的位置:
char str[]="hello";
char *p=strchr(s,'l');
p=strchr(p+1,'l');
strstr(a[],b[]); //在字符串中查找字符串。返回指针
strcasestr(a[],b[]); //不计大小写地查找
enum:枚举
enum 枚举类型名字{名字0,名字1,名字n};
//枚举类型名字通常无用,有用的是大括号里的名字,它们是常量符号,类型是int,值依次为0,1,2...
enum:color{Red,Blue,Yellow}; //color此时与int平等,但使用时前面要加enum
enum color t=Red; //t=o
scanf("%d",&t); //enum实际就是int,所以可以用%d
//套路:enum color{A,B,C,number of color};
//这时number of color就自动棒我们计数前面的元素个数了
enum color{Red=1,Yellow,Green=5}; //也合法,Red=1,Yellow=2,Green=5
结构类型:
struct date{int month;int day;int tear;}; //声明结构类型
struct date today; //定义一个date类型的变量today
//如果struct声明在一个函数内,则这个自定义结构类型只能在该函数内使用
第二种声明方法: struct {int month;int day;} today1,today2;
//today1与today2没有类型名,但可以正常使用
第三种声明方法: struct date {int month;int day;} today1,today2;
//声明后立即创建变量
结构变量初始化:
struct date{int month;int day;int tear;} today;
struct date today = {07,31,2014};
struct date thismonth = {.month=7, .year=2014}; // /day默认为0
结构变量辅助:
point_a = (struct point){5,10}; //之后point_a.x=5,point_a.y=10
结构指针:
(*p).month=12 等价于 p->month
typedef与结构类型:
typedef struct{int a,int b} Date; //之后这个类型可以直接写Date,无需struct关键字
// typedef 旧 新
联合:
union {int i;char c;}elt1,elt2;
//所有空间共享空间,同一时间只有一个成员有效
//union的大小为最大成员的大小
//初始化是对第一个成员做初始化
计算机内存分为系统区与用户区。用户区下有程序区,静态存储区,动态存储区。程序区存放C语言程序编译后的可执行代码;静态存储区存放静态变量,占用固定地址,程序结束后释放;动态存储区存放动态变量,函数结束后释放。
静动态描述的是生存期(时间),内外部描述的是作用域(空间)
静态存储变量分为外部型(extern)和静态性(static)
动态存储变量分为自动型(auto)和寄存器型(register)
局部变量说明:auto(默认),static(局部静态变量,作用域在一个块内,如不初始化则值为0),register
全局(外部)变量说明:extern(默认,在其他文件使用前要先声明),static(外部静态变量,作用域在定义处到文件结束)
全局变量:
全局变量若没有初始化,会自动得到0(NULL)值
全局变量初始化发生在main之前
若全局变量之前有const int a =1;则a也可以用来赋值全局变量
全局变量若不在开头定义,则作用域在说明处到文件结束
静态本地变量:
其实就是全局变量,与全局变量位于相同内存区域,而不与本地变量在一起
与全局变量的区别只在作用域仅限在此函数中。生存期也为全局
本地变量前加上static变成静态本地变量
所在函数结束时,静态本地变量继续存在,值不变
静态本地变量的初始化仅在第一次进入此函数才发生,非首次进入静态本地变量会保持上次结束时的值
本地变量在离开函数后值不变,只是无法再找到,地址也会被其他新变量占据
函数以能否被其他文件调用分为外部函数与内部函数
外部函数(默认,extern) 内部函数(static)
一个全局变量如果也想在其他文件使用,就要在对应.h文件加上一句声明:extern int a;再把这个.h文件#include在其他文件中
#开头的是编译预处理指令
#define用来定义一个宏,例: #define PI 3.14159
宏可以互相嵌套,""双引号内部的宏不会被替换
预定义宏:__LINE__ __FILE__ __ DATE__ __TIME__ __STDC__等
宏可以带参数,例:#define cube(x) ((x)*(x)),但一定要尽可能加括号!
把函数原型写入头文件,若想要在其他.c文件使用此函数,则需要在两个.c文件头都#include这个头文件
所谓的头文件里全是声明
#include 后用" "会让编译器优先.c文件所在目录寻找文件,< >会让编译器优先在指定目录寻找
#include实际只是把对应文件的内容放在此文件中
stdio.h里只有printf函数的原型,真正的代码在其他地方
标准头文件结构:
#ifndef _LIST_HEAD_
#define _LIST_HEAD_
#endif
格式化输入输出:
输出: %[flags][width][.prec][hil] type
flags 含义
- 左对齐
+ 如果是正数,就强制输出+
//+与-可以放在一起,两者顺序无所谓,意义为两者叠加
(space) 正数留空
0 用0填充
width或prec 含义
number 最小字符数
* 下一个字符是字符数 // %*d,6,123等价于%6d,123
.number 小数点后的位数
.* 下一个参数是小数点后的位数
hil(类型修饰) 含义
hh 单个字节
h short
l long
ll long long
L long double
.type 含义
i/d int
u unsigned int
o 八进制
x 十六进制
X 字母大写的十六进制
f/F float,6
e/E 指数
g float
G float
a/A 十六进制浮点
c char
s 字符串
p 指针
n 读入/输出的个数
// printf("123%n",&a); 这样a就得到3的值
// printf的返回值是输出的字符数,\n也算
输入:
%[flag]type
flag 含义
* 跳过 // %*d 意为跳过这个整数
number 最大字符数
hh char
h short
l long,double
ll long long
L long double
type 含义
d int
i 整数,可能是八进制、十六进制
u unsigned int
o 八进制
x 十六进制
a,e,f,g float
c char
s 字符串
[...] 所允许的字符
p 指针
//scanf的返回值是读入的项目数
按位运算:
&(按位与) 偏向0
|(按位或) 偏向1
~(按位取反)
^(按位异或) 相同为0,不相同为1 // x^y^y=x
移位运算:
i<<y 将i以二进制形式左移j位,右侧补0。小于int的类型,移位以int的方式做,结果是int
x<<=n等价于x *= 2的n次方
对于>>来说,当对象是unsigned时,左侧填0,;当对象是signed时,左侧填原来最高位的数(保持符号不变)
main函数的真实参数:
main(int argc,char *argv[ ])
参数值在操作系统命令行上获得,一般形式:C:\>可执行文件名 参数一 参数二 ...
argc的值是命令行中参数个数(包括可执行文件名)
C:\> E24 BASIC B C 则argc得到4,argv(字符串指针的数组)是:
argv[0]指向E24\0 argv[1]指向BASIC\0 ...
文件输入输出:
>文件名 将输出结果写到该文件中
<文件名 从该文件中得到输入内容
<文件a >文件b 从文件a输入,输出到文件b
FILE *a=fopen("文件名","r"); //a是一个文件指针,如果打开失败,函数会返回NULL
if(a) //a不为NULL
{
int num;
fscanf(a,"%d",&num);
printf("%d\n",num);
fclose(a);
}
fopen函数的第二个参数:
"r" 打开只读
"r+" 打开读写,从文件头开始
"w" 打开只写,若不存在该文件则新建它,如果存在则先清空
"w+" 打开读写,若不存在该文件则新建它,如果存在则先清空
"a" 打开追加,若不存在该文件则新建它,如果存在则从文件尾开始
"..x" 只新建,如果文件已存在则不能打开
//以上只针对文本文件(ASCII文件)
二进制读写:
fread(要被读的文件指针,内存大小,有几个这样的内存,文件指针)
fwrite(要被写的文件指针,内存大小,有几个这样的内存,文件指针)
//二者返回值是成功读/写的字节数
//第二三个参数解释:一般使用这两个函数的都是结构体数组
//第二个参数是单个结构的大小,第三个参数是有几个结构
位段:
struct a{int a1:3;int a2=2;};
//成员a1占3bit,成员a2占2bit
//但是该结构的总长度仍然为8(4*2)