C语言一些笔记
常用头文件
math.h
常用函数
abs(); // 求绝对值 返回值int
sqrt(); // 求平方根 返回值double
sin()
stdio.h
printf();
scanf();
getc();
string.h
strlen(); // 返回字符串个数
strcpy(); // 字符串拷贝函数 返回值返回类型为char*,返回参数1的地址
strcmp(const char *p1, const char * p2); // 逐个比较字符,当某个字符不一样的时候就返回,如果p1大于p2那么返回正数;如果p1小于p2返回负数;如果等于返回0
/*
p1 大 返回整数
p2 大 返回负数
p1 == p2 返回0
如p1= "hello"
p2 = "y";
那么就是p2大,因为y大于h;这个函数比较的是单个字符,根据ASCII码比较,并不是比较字符个数
*/
strcat(const char *p1, const char * p2); // 将两个字符串连接,就是p1字符串基础上追加p2字符串内容,前提是p1得有空间容得下p2;如果装不下
char ch = getchar(); // 从键盘获取单个字符
putchar(char ch); // 输出字符到屏幕
int gets(const char * p); // 从键盘录入字符串到p内存空间里去
int puts(const char * p); // 输出字符串到屏幕上去
无符号类型
unsigned
浮点数问题
浮点数无法精确存储的原因
一个单精度的变量只能保证有效数位是7位。7位后面的数字是无意义的,并不准确表示该数
在C语言中尽量避免将一个很大的数和很小的数直接相加或相减,否则会丢失小数
输出控制符
\t
:制表符,输出8个空格\r
:跳到一行初始位置
char类型的八进制
char c = '\729'; // 错误的代码,以\开头的是八进制,而八进制不能有9
%m.n问题
m是占位,n是小数
m如果是正数,要输出的数小于m,那么是右对齐左补空格,如果是大于m,那么是以原来的数输出
m如果是负数,要输出的数小于m,那么是左对齐右补空格,如果是大于m,那么是以原来的数输出
char s[100] = { "Whatisyourname" };
printf("%30.5s", s);
// 输出结果是:` Whati`
scanf()的问题
scanf("%2d %*3d %d", &a, &b);
如果输入以下信息:
12 345 67
系统会将12赋给a,在%*3d
表示读入3位整数,但不赋值给任何变量,所以跳过345,将67给b
switch
switch
与case
常量表达式只能是整数类型、字符型;
case
只能是常量表达式
二维数组
int a[3][4] = {0}; // 数组的初始化,每个元素都为0
int a[][4] = {1, 2, 3, ...}; // 合法的,可以这么玩
字符数组
可以理解为字符串,C语言中没有字符串类型,但是可以是字符数组来模拟。
因此,每个字符数组的最后一位是\0
字符串的初始化
char ch[10] = {"xxx"};
char ch[] = "xxx"; // 和上面一样都是等价的
// 只不过这样的话,系统会自动在最后面加\0
字符数组与printf应用
char * p = "%d %d";
int a = 10, b = 20;
printf(p, a, b);
字符处理函数
puts(str); // 将一个以'\0'结束的字符串输出的终端
gets(str); // 从终端输入字符串到str并返回str首地址
strcat(str1, str2); // 把str2中字符串追加到str1后面,并删除str1后的'\0'字符,并返回str1的首地址
strcpy(str1, str2); // 将str2中字符拷贝的str1中,最后的'\0'也会拷贝。前提是str1必须可以装下str2
strcpy(str1, str2, size); // 将str2装入str1中,指定复制的长度size
strcmp(str1, str2); // 按ASCII码从左到右逐个比较字符串内容,直到出现'\0',然后返回结构
str1 == str2 返回值==0
str1 > str2 返回值>0
str1 < str2 返回值<0
strlen(str); //返回str的长度,不包括字符串结束符'\0'
strlwr(str); // 将字符串中大写字母转换为小写字母
strupr(str); // 将字符串中小写字符转换为大写字母
变量修饰符
auto : 定义变量默认就是这个
static : 定义静态变量
register: 使用该关键字,变量会存放在寄存器里,有效提高运算速度
extern : 外部变量,放在静态存储区,意思就是说别的.c文件可以使用 默认函数就是该类型
宏定义
无参
#define 宏名 字符串(常数,表达式)
在使用的时候,当编译器扫描到宏时,会直接替换
有参数
#define 宏名(参数表) 字符串
#define ADD(X, Y) (X+Y)
使用
int sum = ADD(5, 10); 展开后 int sum = (5, 10); // 注意替换的时候会有括号的,因为在定义时候就有括号
头文件
<>
:到存放C库函数的头文件所在目录
""
:现在当前目录找,找不到时,回去C库函数所在目录找
条件编译
满足条件编译,不满足不编译;条件编译作用:直接在语法检查的时候判断是否编译
使用格式一
#ifdef 标识符
程序段1
#endif
格式二:
#ifdef 标识符
程序段1
#else
程序段2
#end
格式三:
#if 常量表达式
程序段1
#else
程序段2
#endif
函数指针
格式:
类型说明符 (* 指针名)();
类型说明符:函数返回类型
() 表示是一个函数指针
指针数组
int * a[5]; 存放地址的数组
数组指针
指向数组的指针
int (*pl)[5];
数组关于数组名和&数组名
&a+1
:是加整个数组的大小
&a[0] + 1
:是一个元素的大小
逗号表达式
int a = (2, 3, 4);
// 先计算左边的操作数,再计算右边的操作数
// 右边的操作数的类型的值作为整个表达式的结果
scanf()问题
如果在scanf()
中有非输入控制符,要原样输入
如:
scanf("m%d", &a); // 要想使用先输入m,再输入要给a的值
三目运算符
格式:A?B:C
等价于
if(A)
B;
else
C;
数据类型
int
、long int
、 short int
、 char
、 float
、double
位运算
运算符 | 操作 | 优先级 |
---|---|---|
~ | 按位取反 | 1 |
<< | 左移 | 2 |
>> |
右移 | 2 |
& | 按位与 | 3 |
^ | 按位异或 | 4 |
| | 按位或 | 5 |
注意事项:
-
~
的运算操作数是1个,其余都是两个 -
可以与赋值结合
<<=
、>>=
、&=
、^=
、|=
-
异或运算,相同为1,不同为0
<<左移
操作数直接左移,高位丢掉,低位补0
>>
右移
如果无符号右移,空位直接补0
如果是有符号右移,
- 如果是正数,右移补0
- 如果是负数,
- 左边补1,称为算数右移【实际上是使用这个】
- 左边补0,称为逻辑右移
动态内存
malloc(size); // 在内存申请开辟长度为size的连续空间
calloc(n, size); // 在内存范围n个长度为size的连续空间,函数返回初始地址,若分配失败则返回NULL
free(p); 释放p指向的内存
共用体
union 共用体名
{
数据类型1 成员1;
数组类型2 成员2;
...
}
为共用体变量分为空间大小是以所有成员中占用空间字节数最大的成员为标准
如:
union Myunion
{
int age;
char names[20];
}
sizeof(union Myunion) == 20
共用体的初始化
- 只能对第一个成员初始化
- 共用体在使用的时候,会只保留最后一次对成员赋值的值
与结构体不同的是
- 只按空间最大的成员来分配空间
- 在同一时刻,只存放一个成员的值
共用体中内存空间是共用体里占用最大的那个类型为准,它的内存分配情况是都是以头开始,具体看http://c.biancheng.net/view/2035.html这篇博客
枚举
enum 枚举名
{
枚举元素
...
}
typedef
typedef 起别名
typedef int Num[100];
Num a; // 那么a就是一个数组,且元素有100个
文件
输入:数据从文件到内存
输出:数据从内存到文件
文件分类
按存储介质分
- 普通文件
- 设备文件:键盘、鼠标
按数据组织分
- 文本文件:ASCII码文件
- 二进制文件
C语言中文件的操作类型FILE
是C为我们定义好的文件结构体
FILE * fp1, *fp2, *fp3;
文件常用函数
fopen(); 打开文件
fclose(); 关闭文件
系统自动打开和关闭的三个标准文件
标注输入 --- 键盘 stdin
标准输出 --- 显示器 stdout
标出错输出 --- 显示器 stdern
fopen作用
- 建立文件信息区
- 建立文件缓冲区
FILE * fopen(char * name, char * mode);
name: 文件路径
mode: 打开文件方式
返回值:如果正常打开文件会返回文件结构体地址,反之返回NULL
文件的打开方式
r | 打开文件必须存在,且每次都会覆盖 读 |
---|---|
w | 没有文件立刻建立;有文件覆盖该文件 写 |
rb | 二进制 |
wb | 二进制 |
a | 向文件末尾添加新的数据,且文件必须存在 |
ab | 二进制 |
r+ | 既读既写,文件必须存在 |
w+ | 新建一个文件,既读既写 |
a+ | 源文件不删除,末尾添加数据,既读既写 |
rb+ | |
ab+ | |
wb+ | |
文本文件:回车 转换为 换行符
二进制文件:不会转换
读写函数-字符
读取字符
fgetc(fp)
:从fp
指向文件读入一个字符并返回,读成功返回。读失败返回EOF
既-1
fputc(ch, fp)
:把字符ch
写到文件指针变量,所指向的文件中- 写成功:返回输出字符
- 写失败:返回
EOF
既-1
feof()
:对于二进制文件读取时判断文件是否结束,返回值文件结束为1,否则为0
读取字符串
fgets(str, n, fp)
:从fp
文件读入长度为(n-1)
的字符串,存入str数组中- 返回值:
- 成功返回
str
首地址 - 失败返回
NULL
- 成功返回
- 读完
n-1
之前遇到\n
或EOF
字符,读入既结束,但也将\n
按字符读入
- 返回值:
fputs(str, fp)
:str
所指向的字符数组写入文件中- 返回值:
- 成功返回0
- 失败返回非零
- 返回值:
读写函数-二进制
fread(buffer, size, count, fp)
fwrite(buffer, size, count, fp)
buffer
:要读/写首地址szie
:要读/写文件大小(长度)count
:要读/写数据块的个数fp
:文件指针
随机读写
rewind(fp)
:让文件指针重新指向文件开头fseek(fp, 位偏移, 起始点)
:- 起始点:0:文件开始位置;1:当前位置;2:文件末尾
- 位偏移:
long
类型加L
fseek(fp, 100L, 0); // 文件开始偏移100个字节
fseek(fp, -10L, 2); // 文件末尾往前偏移10个字节
ftell()
:获取文件标记当前指向的位置ferror(fp)
:文件读写的出错检测,0是没有出错,非0是出错;每次读写时都会有新的ferror()
函数clearerr()
:使文件错误标志和文件结束标志为0
二进制读写2个字节
putw
getw
&&与||运算符
- && (逻辑与):(三种)
① 当逻辑与左边为false(假),则不再进行逻辑与右边的判断,结果为false(假)
② 当逻辑与左边为true(真)则进行右边判断,右边为false(假),结果为false(假)
③ 当逻辑与左边为true(真)则进行右边判断,右边也为true(真),则结果为true(真) - || (逻辑或):(三种)
① 当逻辑或左边为false(假),继续逻辑或右边的判断,如果也为false(假),结果为false(假)
② 当逻辑或左边为false(假),继续逻辑或右边的判断,如果为true(真),结果为true(真)
③ 当逻辑或左边为true(真),则不再进行逻辑或右边的判断,结果为true(真)
ASCII码表

优先级表
https://blog.csdn.net/changexhao/article/details/82556761
C语言坑的总结
- 一个函数的组成分贝是函数名、函数体
- 一个函数的函数体一般包括声明部分和执行部分
- C语言本身没有输入输出语句,其输入输出是由系统标准输入输出函数来完成
- 任何数对1取余都是0
- a=2, b=3, c=4, 执行 a=16+(b++)-(++c) == (16+3-5)2==28
- double d = 20/3; b==6.00 因为常量都是Int类型
- 如果输出语句中是这样的 printf("a=%%d", a); 会输出a=%d,不会格式化
- case后面只能是整数或布尔值
- 当for(表达式1; ; 表达式3)这样写法的时候,中间的值是1
- 共用体特性1)共用体变量分为空间大小是以所有成员中占用空间字节数最大的成员为标准2)只能对第一个成员初始化3)共用体在使用的时候,会只保留最后一次对成员赋值的值
- 浮点数可以这么写-.18就是0.18
- 八进制以0开头,十六进制以0x开头,二进制没有明确规定
- 5e2.5是错误的,e前面可以是小数,e后面必须是整数
- 0除以任何数字,商是0,余数是0
- 二维数组,a[x][y]; 中 x可以省略,但是y必须写
- strlen()函数计算字符串\0之前的字符个数;当字符串中没有\0时,该返回的数值就不准确了
- 注意字符串,如果容量刚好C语言不会补\0;如果容量充足C语言会自动补\0
- C语言中,不写返回类型,函数自动返回int类型
- 如果函数中有static变量,那么下次执行的时候,会跳过用static声明的变量,接着用之前已经创建好的
- 宏只是简单的替换,别自作聪明加括号
- char a = '\72'; 这里使用的是八进制
- C语言常用的数学函数、字符串函数
- long 4字节 double 8个字节,32位机器int 为4个字节,16位字节int 为2字节
- C语言中基本数据类型有整形、实型(小数)、枚举、字符
- C语言中标准函数名可以做用户标识符
- %u是无符号输出
- 负数对整数取余,余数是正或负是根据被除数来说的 如 -10%3 余数是-1
- scanf("%2d, %*3d, %2d", &a, &b) 输入1234567 12给a,345越过67给b
- scanf("%7.2f"); 不能控制精度输入,是错误的
- 运算对象非0真,0是假;结果1真0假
- C语言中,char str[] = "abc\000def\n"; 这道题str中\0可以跟3个0,也就是八进制所以sizeof(str) == 9
- 全局变量属于静态变量,只是没有办法调用
- register(寄存器变量)为了提高某变量和函数形参的存取速度;extern声明使用全局变量(外部变量);auto动态变量默认定义的都是此类型变量;static静态变量定义后默认为0程序结束后释放内存
- 指针悬挂就是野指针
- int p[3] // 这个是指针数组,元素都是指针;int (p)[3] // 这个是数组指针p指向三个元素的指针
#define SQ(n) n * n; int s2 = SQ(x+y)
// 展开后x+y*x+y- 共用体只能对第一个成员初始化
- 浮点数判断是否为0,尽量不要直接与0判断要使用if(fabs(a) < 1e-6)来判断
- 取余运算符两边必须是整形 3.0%2取余就是错误的
- C语言中实数表示两种1)3.12;.12;10.;2)e前e后必有数,e后必须为正整数
- 指针变量不能整数赋值
- char p1[] = "hello" 与 char p2[] = {'h', 'e', 'l', 'l', 'o'}; 长度是不一样的,p1末尾有\0,p2末尾没有
- C语言0是假,非0是真
- scanf(); 输入字符串,遇到空白结束如"I am" 会录入到I后结束;gets()遇到回车结束
- 全局变量和局部静态变量都是在编译的时候进行变量初始化的
- 不管是16位机还是32位机,长整行(long)都占用4个字节
- 不管一个多大的数,对100取余,结果都是0~99。
- 两个相同类型的指针变量,不可以相加