C语言笔记
学习自:C语言中文网
1 基础
1.1 字符编码
字符编码 | 说明 |
---|---|
ASCII | 只显示英文字符(基本拉丁字母) |
GB2312 | 简体中文字符集,1980年发布 |
GBK | 中文字符集,在GB2312基础上扩展,1995年发布 |
GB18030 | 中文字符集,GBK的再扩展,2000年发布 |
Big5 | 繁体中文字符集,台湾、香港地区 |
ISO/IEC 8859 | 欧洲字符集(ASCII的扩展) |
Unicode | 统一码,万国码 |
Unicode方案 | 说明 |
---|---|
UTF-8 | 变长编码方案,使用1~6个字节存储 |
UTF-32 | 固定长度编码方案,始终4个字节 |
UTF-16 | 使用2or4个字节存储 |
1.2 编译(Compile)、链接(Link)
编译器(Compiler)
编译:将程序转换成计算机能够识别的二进制文件
链接器(Linker)
链接:将目标文件(Object File)和系统组件(比如标准库、动态链接库等)结合起来。
1.3 数据类型
说明 | 数据类型 | 数据长度 |
---|---|---|
字符型 | char | 1 |
短整型 | short | 2 |
整型 | int | 4 |
长整型 | long | 4 |
单精度浮点型 | float | 4 |
双精度浮点型 | double | 8 |
无类型 | void |
1.4 常用库
1.4.1 stdio.h
全称:standard input and output
1 | puts();//output string,自动换行 |
1.4.2 wchar.h
1 | wchar_t a = L'A'; //英文字符(基本拉丁字符) |
1.4.3 conio.h
1 | //只能用于windows平台 |
1.4.4 string.h
1 | strcat(arrayName1,arrayName2);//string catenate,把两个字符串拼接在一起 |
2 指针
&:取地址
*:指向地址
*(&a)=a
&(*pa)=pa
定 义 | 含 义 |
---|---|
int *p; | p 可以指向 int 类型的数据,也可以指向类似 int arr[n] 的数组。 |
int **p; | p 为二级指针,指向 int * 类型的数据。 |
int *p[n]; | p 为指针数组。[ ] 的优先级高于 *,所以应该理解为 int *(p[n]); |
int (*p)[n]; | p 为二维数组指针。 |
int *p(); | p 是一个函数,它的返回值类型为 int *。 |
int (*p)(); | p 是一个函数指针,指向原型为 int func() 的函数。 |
3 结构体
1 | struct 结构体名{ |
位域:
1 | struct bs{ |
4 知识点补充
1 | typedef oldName newName; |
const:
1 | const int MaxNum=100; |
随机数:
1 | srand((unsigned)time(NULL));//重新播种 |
5 文件操作
FILE是<stdio.h>头文件中的一个结构体,专门保存文件信息
5.1 fopen()
fopen()获取文件信息,包括文件名、文件状态、当前读写位置等,并将这些信息保存到一个FILE类型的结构体变量中,然后将该变量的地址返回。
1 | FILE *fp = fopen("demo.txt", "r");//只读 |
判断文件是否打开成功
fopen()打开错误返回值是NULL
打开方式 | 说明 |
---|---|
“r” | 以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。 |
“w” | 以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 |
“a” | 以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 |
“r+” | 以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。 |
“w+” | 以“写入/更新”方式打开文件,相当于w 和r+ 叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 |
“a+” | 以“追加/更新”方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。 |
5.2 fclose()
1 | int fclose(FILE *fp); |
5.3 字符形式读写文件
fgetc()
file get char
1 | int fgetc(FILE *fp); |
fputc()
file put char
1 | int fputc ( int ch, FILE *fp ); |
5.4 字符串形式读写文件
fgets()
file get string
1 | char *fgets(char *str,int n, FILE *fp); |
fputs()
file put string
1 | int fputs(char *str, FILE *fp); |
5.5 数据块形式读写文件
fread()和fwrite()时应该以二进制形式打开文件
fread()
1 | size_t fread(void *ptr, size_t size,size_t count, FILE *fp); |
对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror() 或 feof() 检测
fwrite()
1 | size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp ); |
对于 fwrite() 来说,肯定发生了写入错误,可以用 ferror() 函数检测。
5.6 格式化读写文件
fscanf()和fprintf()的读写对象不是键盘和显示器,而是磁盘文件
1 | int fscanf ( FILE *fp, char * format, ... ); |
5.7 随机读写文件
rewind()用来将位置指针移动到文件开头
1 | void rewind(FILE *fp); |
fseek()用来将位置指针移动到任意位置
1 | int fseek(FILE *fp, long offset, int origin); |
- fp:文件指针
- offset:偏移量,也就是要移动的字节数
- origin:起始位置
5.8 ftell()
1 | long int ftell(FILE *fp); |
6 内存分区
内存分区 | 说明 |
---|---|
程序代码区 (code) | 存放函数体的二进制代码。一个C语言程序由多个函数构成,C语言程序的执行就是函数之间的相互调用。 |
常量区 (constant) | 存放一般的常量、字符串常量等。这块内存只有读取权限,没有写入权限,因此它们的值在程序运行期间不能改变。 |
全局数据区 (global data) | 存放全局变量、静态变量等。这块内存有读写权限,因此它们的值在程序运行期间可以任意改变。 |
堆区 (heap) | 一般由程序员分配和释放,若程序员不释放,程序运行结束时由操作系统回收。malloc()、calloc()、free() 等函数操作的就是这块内存,这也是本章要讲解的重点。 注意:这里所说的堆区与数据结构中的堆不是一个概念,堆区的分配方式倒是类似于链表。 |
动态链接库 | 用于在程序运行期间加载和卸载动态链接库。 |
栈区 (stack) | 存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。 |
6.1 栈和堆的区别
栈区:系统分配和释放,不受程序员控制
堆区:完全由程序员掌控,自主可控
6.2 动态内存分配函数
malloc()
原型:void* malloc(size_t size);
作用:在堆区分配 size 字节的内存空间。
返回值:成功返回分配的内存地址,失败则返回NULL。
注意:分配内存在动态存储区(堆区),手动分配,手动释放,申请时空间可能有也可能没有,需要自行判断,由于返回的是void*,建议手动强制类型转换。
calloc()
原型:void* calloc(size_t n, size_t size);
功能:在堆区分配 n*size 字节的连续空间。
返回值:成功返回分配的内存地址,失败则返回NULL。
注意:calloc() 函数是对 malloc() 函数的简单封装,参数不同,使用时务必小心,第一参数是第二参数的单元个数,第二参数是单位的字节数。
realloc()
原型:void* realloc(void *ptr, size_t size);
功能:对 ptr 指向的内存重新分配 size 大小的空间,size 可比原来的大或者小,还可以不变(如果你无聊的话)。
返回值:成功返回更改后的内存地址,失败则返回NULL。
free()
原型:void free(void* ptr);
功能:释放由 malloc()、calloc()、realloc() 申请的内存空间。
7 Socket
- Windows下socket程序依赖Winsock.dll或ws2_32.dll,必须提前加载。
- Windows使用“文件句柄”概念,区分socket文件和普通文件;socket()返回值为SOCKET类型(即句柄)
- Windows下使用recv()/send()函数发送和接收
- 关闭socket时,Windows使用closesocket()函数
7.1 socket()
1 | SOCKET socket(int af, int type, int protocol); |
7.2 bind()
服务器端:将套接字与特定的IP地址和端口绑定起来
1 | int bind(SOCKET sock, const struct sockaddr *addr, int addrlen); //Windows |
7.3 connect()
客户端:用connect()函数建立连接
1 | int connect(SOCKET sock, const struct sockaddr *serv_addr, int addrlen); //Windows |
7.4 listen()
让套接字进入被动监听状态
1 | int listen(SOCKET sock, int backlog); |
7.5 accept()
套接字处于监听状态时,可以通过accept()函数接收客户端请求
1 | SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen); //Windows |
7.6 数据接收和发送
1 | //发送 |