c语言基础1,void func1(void);普通函数声明任意参数无返回值需要实现函数体才能使用。2,void *func2(void);普通函数声明任意参数返回任意函数指针需要实现函数体才能使用。3,void (*func3)(void);函数指针声明函数任意参数无返回值属于变量声明可以赋值。4,void (*func4(void))(void);函数指针声明属于一个返回函数指针的函数指针本体函数指针任意参数返回的函数指针任意参数无返回值5fork使用只会复制当前进程的调用fork的线程到子进程中。6c/c可以看到0x0001u的用法这个u表示unsigned还有其他的一些修饰数字的前后缀比如01中0表示8进制1L中L表示long int , 1u中u表示unsigned int。7c语言中变量定义和赋值中逗号和分号的应用结构体定义内部用分号结尾用分号。枚举定义内部逗号结尾分号。c类定义内部分号结尾分号。8数组指针的部分误解如果有int a[10];那么a和a表示相同的地址但是代表不同的含义a表示数组的首地址a表示数组大小为10的数组的地址。也就是a1表示a[1]的地址但是a1表示a[10]的地址常见应用如下①指针的加减运算和整数的加减运算的差别指针加减是变更n * sizeof(*p)整数时变更n比较维度指针算术运算整数算术运算运算单位以指向类型的大小为单位以1为单位示例p n地址增加n * sizeof(*p)字节数值增加n常见用途数组遍历、内存块操作普通数值计算是否可跨类型不建议会破坏对齐和访问规则不同类型可混合隐式提升nullptr / 0不能对空指针解引用但可加减 0正常数值 0减法结果返回元素个数ptrdiff_t不是字节数返回数值差合法性只能在同一数组或其后一位置范围内合法始终合法9当表达式中有有符号数据和无符号数据一律将有符号转化为无符号。这一点可能和向上转换原则不太一样一般情况是小范围转大范围但是有符号和无符号其实范围是一样的10结构体补齐规则以前总是按照那3个准则来记忆类似于对齐原则每一成员的结束偏移量需对齐为后一成员类型的倍数补齐原则最终大小补齐为成员中最大值的倍数有种方法更容易记忆。结构体成员以最大成员补齐如果下个成员能填充到上个成员为对齐而空出的内容中的话则这个成员会挤到上个成员会移到上个成员后的空位中typedef struct A{ int a; //aaaa ***b cccccccc //如果没有b则a后仍空出4字节b发现可以b的大小小于到4字节就会挤到空位中 char b; double c; }A; //16byte typedef struct B{ char b;//b*** aaaa cccccccc int a; double c; }B;//16byte typedef struct C{ int a;//aaaa**** cccccccc b******* double c; char b; }C;//24byte typedef struct D{ char b;//bbbbbbbb cccccccc aaaa**** double c; int a; }D;//24byte typedef struct E{ char b;//b*** aaaa c*** int a; char c; }E;//12byte11thread默认是非分离的也就是如果thread_create后不进行thread_join,线程资源是不会释放的一般可以手动设置detach接下来线程结束后会自动释放或者不设置detach调用thread_join等待线程结束并释放资源。12、头文件分类stdlib.h:getenv();atoi();abort();exit();free();malloc();unistd.h:getcwd();getpid();access();read();write();ISO C标准定义的头文件(24项)assert.h ---------------------- 验证程序断言complex.h ---------------------- 支持复数算术运算ctype.h ---------------------- 字符类型errno.h ---------------------- 出错码fenv.h ---------------------- 浮点环境float.h ---------------------- 浮点常量inttypes.h ---------------------- 整型格式转换iso646.h ---------------------- 替代关系操作符宏limits.h ---------------------- 实现常量locale.h ---------------------- 局部类别math.h ---------------------- 数学常量setjmp.h ---------------------- 非局部gotosignal.h ---------------------- 信号stdarg.h ---------------------- 可变参数表stdbool.h ---------------------- 布尔类型和值stddef.h ---------------------- 标准定义stdint.h ---------------------- 整型stdio.h ---------------------- 标准I/O库stdlib.h ---------------------- 实用程序库函数string.h ---------------------- 字符串操作tgmath.h ---------------------- 通用类型数学宏time.h ---------------------- 时间和日期wchar.h ---------------------- 扩展的多字节和宽字符支持wctype.h ---------------------- 宽字符分类和映射支持POSIX标准定义的必须的头文件(26项)dirent.h ---------------------- 目录项fcntl.h ---------------------- 文件控制fnmatch.h ---------------------- 文件名匹配类型glob.h ---------------------- 路径名模式匹配类型grp.h ---------------------- 组文件netdb.h ---------------------- 网络数据库操作pwd.h ---------------------- 口令文件regex.h ---------------------- 正则表达式tar.h ---------------------- tar归档值termios.h ---------------------- 终端I/Ounistd.h ---------------------- 符号常量utime.h ---------------------- 文件时间wordexp.h ---------------------- 字扩展类型arpa/inet.h ---------------------- Internet定义net/if..h ---------------------- 套接字本地接口netinet/in.h ---------------------- Internet地址族netinet/tcp.h---------------------- 传输控制协议定义sys/mman.h---------------------- 内存管理声明sys/select.h---------------------- select函数sys/socket.h---------------------- 套接字接口sys/stat.h ---------------------- 文件状态sys/times.h ---------------------- 进程时间sys/types.h ---------------------- 基本系统数据类型sys/un.h ---------------------- UNIX域套接字定义sys/utsname.h----------------------系统名sys/wait.h ---------------------- 进程控制POSIX标准定义的XSI扩展头文件(26项)cpio.h ---------------------- cpio归档值dlfcn.h ---------------------- 动态链接fmtmsg.h ---------------------- 消息显示结构ftw.h ---------------------- 文件树漫游iconv.h ---------------------- 代码集转换实用程序langinfo.h ---------------------- 语言信息常量libgen.h ---------------------- 模式匹配函数定义monetary.h ---------------------- 货币类型ndbm.h ---------------------- 数据库操作nl_types.h ---------------------- 消息类别poll.h ---------------------- 轮询函数search.h ---------------------- 搜索表strings.h ---------------------- 字符串操作syslog.h ---------------------- 系统出错日志记录ucontext.h ---------------------- 用户上下文ulimit.h ---------------------- 用户限制utmpx.h ---------------------- 用户帐户数据库sys/ipc.h ---------------------- IPCsys/msg.h ---------------------- 消息队列sys/resource.h------------------- 资源操作sys/sem.h ---------------------- 信号量sys/shm.h ---------------------- 共享存储sys/statvfs.h---------------------- 文件系统信息sys/time.h ---------------------- 时间类型sys/timeb.h ---------------------- 附加的日期和时间定义sys/uio.h ---------------------- 矢量I/O操作POSIX标准定义的可选头文件(8项)aio.h ---------------------- 异步I/Omqueue.h ---------------------- 消息队列pthread.h ---------------------- 线程sched.h ---------------------- 执行调度semaphore.h--------------------- 信号量spawn.h ---------------------- 实时spawn接口stropts.h ---------------------- XSI STREAMS接口trace.h ---------------------- 时间跟踪What is glibc?The GNU C Library project providesthecore libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. These libraries provide critical APIs including ISO C11, POSIX.1-2008, BSD, OS-specific APIs and more. These APIs include such foundational facilities as open, read, write, malloc, printf, getaddrinfo, dlopen, pthread_create, crypt, login, exit and more.The GNU C Library is designed to be a backwards compatible, portable, and high performance ISO C library. It aims to follow all relevant standards including ISO C11, POSIX.1-2008, and IEEE 754-2008.The project was started circa 1988 and is more than 30 years old. You can see the complete project release history on the wiki.Despite the projects age there is still a lot to do so please Get Started and Get Involved!13、无符号类型和有符号类型进行算术运算和比较运算相同值域范围时有符号转换为无符号 不同值域范围时小范围转换位大范围int aa -1; unsigned int bb 16; if (aa bb) cout 负数竟然大于正数了\n;//实际aa转为无符号大于bb但是在算术运算时无符号和有符号相加结果一般也不会出什么问题因为都是补码运算unsigned int b 1; int c -1; printf(%d\n,c b);//结果为014,16进制数据可以正数可以负数int a -0x87654321;//error C4146: 一元负运算符应用于无符号类型结果仍为无符号类型。原因是编译期首先将0x87654321赋予int然后看到0x87654321大于INT_MAX所以将0x87654321赋予unsigned int然后看到前面有个负号不能再讲unsigned转为有符号所以报错但是使用%x输出时会输出其补码其实就是有符号转无符号的值原因是%x默认是输出无符号16进制数据,%x和%0x意义一样但是和%05x意义不一样。%x默认接受数据是unsigned int,先把数据转换位unsigned int再输出。int a -0x01; printf(%x,%d\n, a,a);// ;ffffffff,-1可以看到0x87654321虽然超过了MAX_INT但是使用补码可以存下来输出的时候用%x可以原封不动输出int a 0x87654321; printf(%x,%d\n, a,a);// ;87654321,-202340681515、c语言符号~表示按位取反表示逻辑取反^表示按位异或异或表示不同为116printf家族printf表示格式化输入到标准输出中。sprintf表示格式化输入到字符串中。vprintf表示使用可变参数输入到标准输出。vsprintf表示使用可变参数输入到字符串中。vsnprintf表示使用可变参数输入到限制最大长度的字符串中。17__attribute__关键字用法和含义__attribute__主要用于补充函数和变量的属性比如限制函数参数类型限制变量宽度等等下面给出三个例子1,extern int my_printf(void *my_object, const char *my_format, ...) __attribute__((format (printf, 2, 3))); //摘取printf的定义为 int printf(const char *format, ...) //archetypeprintf:按照printf格式进行检查my_printf //string-index2:my_printf的第2个参数(my_format)对应了printf参数中的format //first-to-check3:my_printf的第3个参数(...)对应了printf参数中的...2,int y __attribute__((aligned (16))) 0; char z[15] __attribute__((aligned (16))); //aligned应用于基础类型变量和数组时 //编译器对于基础类型变量和数组的编译原则如下 //系统默认按照变量类型本身占用内存的字节数来对齐边界(地址原则) //系统按照变量类型本身占用内存来分配内存字节数(内存原则) //通俗来讲针对于基础类型变量和数组时属性限定了变量存储的内存首地址但是并没有影响变量实际占用 //内存的大小。3typedef struct F1{ char i; int j[2] __attribute__((packed)); }F1_T; //9btyes typedef struct F2{ char i; int j[2] __attribute__((packed)); int k; }F2_T; //16btyes //系统应该为结构体成员按照最小的对齐方式来对齐边界(1bit或者1字节)18mmap使用方法mmap主要作用是可以将外设硬件/flash等地址空间映射到当前进程的虚拟地址空间从而可以通过内存操作来控制外设硬件/flash常常用于外设驱动当中。下面的例子是通过将一个文件映射到当前虚拟地址中从而可以通过控制一块地址空间实现文件的读写。#include sys/mman.h #include sys/types.h #include sys/stat.h #include fcntl.h #include string.h #include unistd.h int main() { int fd open(./file.txt, O_RDWR);//读写权限 if(fd 0) { perror(\n); return -1; } int len lseek(fd, 0, SEEK_END);//读取文件大小 void* addr mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);//只有文件大小不为空时才能创建成功 if(addr MAP_FAILED) { perror(mmap failed\n); return -1; } close(fd);//内存映射成功后关闭文件描述符依然保持着映射 const char* str hello, world; memcpy(addr, str, strlen(str)); return 0; }此例子使用有以下点需要注意①映射建立后可以关闭文件描述符②文件大小必须要大于0并且文件大小映射后不能再改变$ gcc test_mmap.c -o test_mmap $ touch file.txt $ echo test123 file.txt $ ./test_mmap $ cat file.txt $ hello wo19补码编码深入理解原码到补码是一种映射[-2^(n-1),2^(n-1)-1] 映射到------ [0,2^n]正数的补码是原码所以其实就是负数进行了映射[-2^(n-1),-1] ----- [2^(n-1),2^n-1]很容易看出映射公式补码2^n负数原码 原码是负数补码正数原码 原码是正数根据这个映射原理我们不再需要进行原码-反码-补码计算而是进行原码-补码计算例如1求int a-1的补码补码2^32-10xffffffff2,int a-1求printf(%x,a);%x默认输出无符号16进制需要把有符号转化位无符号我们知道计算机是以补码保存所以其实就是原码转补码(原码是负数)再补码转原码原码是正数原码等于补码所以最后求补码即可补码2^32-10xffffffff20结构体位域结构体位域表示使用此类型的多少位如果相邻相同类型使用位数能挤进来则挤进来。struct test { int a:1; int b:1; int c:1; int d; };sizeof(struct test) 448细节是abc00000000000000000000000000000d前面三个成员使用4个字节的前三位,后面的d使用单独的4个字节20,scanf格式化输入①格式化输入多个内容的时候每个格式化输入内容前可以有无数个空格和换行例如int a,b; sscanf(123\n\n\n\n456,%d%d,a,b);//找到第一个非空字符为1匹配到123赋值给a接下来找非空字符为4因此将456赋值给b printf(%d,%d\n,a,b);//a123,b456②格式化字符含义%d int%ffloat%lfdouble%c: char%s:char *%0X:unsigned int%l:long21fgets和strtok的区别fgets遇到换行和文件尾结束strtok会修改原字符串22,for循环表达式的执行顺序for(a,b,c)d; //上述表达式执行顺序为abdc注意d和c的顺序d大于c23sscanf连续多个变量赋值int a,b; sscanf(123 456,%d%d,a,b);//连续两个变量赋值时指定字符串遇到空格/制表/换行时停止赋值也就是123赋给a456赋给b,返回值为赋值变量的个数也就是2 sscanf(123,456,%d%d,a,b);//匹配的字符串有空格也就是没有遇到空格/制表/换行所以123赋值给ab没有赋值返回124,嵌套指针的使用int a0; int *ba; int **cb; *(*c)1;//如果需要通过c来修改a则需要双引用25数组作为函数入参时可以不填数组大小void func(int a[],int b[1]) { }上述参数都允许的实际调用时的数组是否越界得看具体编译器行为26fopen的参数含义File fpfopen(/home/test.txt,w);//只允许写不允许读文件不存在会创建文件存在则清空 File fpfopen(/home/test.txt,w);//允许写允许读文件不存在会创建文件存在则清空 File fpfopen(/home/test.txt,r);//不允许写允许读文件不存在不会创建 File fpfopen(/home/test.txt,r);//允许写允许读文件不存在不会创建 File fpfopen(/home/test.txt,a);//只允许写不允许读文件不存在会创建文件存在则seek到文件末尾 File fpfopen(/home/test.txt,a);//允许写允许读文件不存在会创建文件存在则seek到文件末尾27turboC2.0操作系统turboC2.0是16位操作系统28类型转换①大值域向小值域的类型转换会进行截断int a -0x10001; short b a; printf(%d\r\n, b);//-1步骤 1计算int a -0x10001;0x10001是十六进制转十进制0x10001 1*16⁴ 0*16³ 0*16² 0*16¹ 1 65537加上负号a -65537计算机用补码存储32 位 int 的补码为0xFFFF FFFF步骤 2short b a;核心截断short是16 位有符号整数赋值时会直接截取 int 的低 16 位0xFFFF FFFF的低 16 位是0xFFFF16 位补码0xFFFF代表的十进制数就是-1步骤 3printf(%d\r\n, b);输出printf用%d打印时会把short类型符号扩展为 int0xFFFF扩展为 32 位0xFFFF FFFF值还是-1最终输出-1②小值域向大值域的类型转换会进行符号扩展short int a -1; int b a; printf(%d\r\n, b);//-1步骤 1short int a -1;short int是16 位有符号整数十进制-1的 16 位补码是1111 1111 1111 11110xFFFF步骤 2int b a;核心符号扩展把 16 位short赋值给 32 位int时有符号数会执行符号扩展看最高位符号位0xFFFF最高位是1负数高位全部补 1扩展为 32 位1111 1111 1111 1111 1111 1111 1111 11110xFFFFFFFF这个 32 位补码代表的数值依然是-1步骤 3printf(%d\r\n, b);%d直接打印有符号 int输出结果-129常量声明①单引号字符例如a②单引号转义例如‘\n’③单引号8进制或者16进制转义例如8进制‘\17’16进制‘\xff’注意没有十进制和二进制转义表示字符30常见指针错误①. 非法访问空指针例如int *pNULL; *p0;②. 非法访问野指针int *p; *p0;③. 内存泄漏int main() { void *pmalloc(1); return 0; }30 内存拷贝内存拷贝可能存在源地址和目的地址重叠的问题遇到重叠的问题需要使用memmove方法此方法会判断源地址和目的地址的高低从而避免目的地址的数据覆盖了源地址的值