序言
通过这篇文章记录平时不解的C语言基础知识点,比较零散。
指针
指针类型和指针指向的变量类型
- 指针本身是内存地址,指针的类型只是给编程的人阅读方便。在x86平台,不管什么类型的指针,都占用4字节,x86_64平台,8字节。
- 指针指向的变量类型可以千变万化,对指针的操作因其指向的变量类型的不同而有所区别。比如int类型变量和char类型变量,p+1分别表示地址加4字节和1字节。(内存最小可寻址单位为1字节)
结构体指针数组和结构体数组
- 结构体指针数组:数组元素为结构体,该指针数组存储的是指向结构体元素的“地址”数组,并不包含结构体的具体内容(尚未分配)。
- 可用malloc()为数组每个指针元素分配内存。
- 可通过(*ele).data来访问结构体成员
- 结构体数组:数组元素为结构体,数组存储的是每个结构体。
- 可直接通过ele.data访问结构体成员
- 结构体指针数组:数组元素为结构体,该指针数组存储的是指向结构体元素的“地址”数组,并不包含结构体的具体内容(尚未分配)。
sizeof计算指针指向内容大小:sizeof(*p)
- 有结构体Struct A{char a; short *b;}a; sizeof(*(a.b)) = 1
- 既不是指针大小8(64位编译器),也不是b指向的实际内容的大小,*(a.b)是第一个字符
char类型的指针是否一定要指向char类型变量的地址
- 否。
- C语言没有Byte类型,在按字节操作内存时使用char *
- 其可以指向任意类型变量的地址
char类型的指针能表示的地址范围是0x00~0xFF?
- 否。
- 指针类型:一般指针类型要与其所指向的变量类型一致(char *可以指向任意类型)
- 指针地址:与操作系统有关,64位操作系统下是8字节,32位操作系统下是4字节
- 所以即使是char类型的指针,其地址仍然是8字节(64位操作系统)
结构体
- 数组名和结构体名
- 数组名
- 数组名表示数组首地址
- 相同类型的数组不能直接赋值
- 结构体名:
- 不是结构体首地址,取地址用&等
- 相同类型的结构体变量可以直接赋值
- 比如struct A{…}a; &a表示结构体a在内存区的首地址,a.data就是直接对结构体元素操作
- 数组名
数据存储
网络字节序和比特序
- 网络字节序:即大端序,地位地址存高位数据,高位地址存地位数据
- 比特序:字节内部的比特序对程序来说是不可见的,大端序CPU和小端序CPU的比特读取方式不一样
- 大端序CPU从左往右读这8个比特
- 小端序CPU从右往左读这8个比特
- 比特序:对于确定的计算机系统,比特序通常与字节序保持一致。
- 大端序CPU:字节的最高位bit存放在内存的最低位
- 小端序CPU:字节的最低位bit存放在内存的最低位
0x07和0x7有区别吗
- 程序输出均为7,没有区别
程序
程序执行顺序:整体顺序就是从上到下
- 进入程序后,就开始找main函数,可能是int main也可能是void main等。
- 然后可能遇到判断、循环、分支结构,然后按各自的语法分别执行
- 还可能遇到被调函数,到了那里就再去执行被调函数,执行完被调函数就再回来(或者退出)。
- 被调函数可能是一个单独.c源程序,也可以是某个头文件中声明的局部函数
- 直到main函数全部执行完毕,直到最后一行结束,程序退出,运行界面出现press any key to continue。
Cross GCC和Linux GCC区别
- Cross GCC指生成可用于不同目标硬件架构(x86 or ARM)或不同操作系统的代码的编译器,是比较通用的编译器
- Linux GCC指本地标准GCC编译器,Linux使用使用这个就可以
头文件
一个头文件可以包含别的头文件吗
- 可以。但不建议这么做,因为它会导致相关定义难以找到,造成头文件重复定义(报错),令makefile人工维护变得困难
头文件添加
- <> 在系统文件下查找该头文件
- “” 在当前文件夹下查找该头文件
头文件防止重定义
- #ifndef _RTP_H_
- #define _RTP_H_
- #endif
- 可以大写也可以小写,习惯上大写
- 然后两次_RTP_H_要统一,否则可能还是会报重定义错误
函数
fgets函数
- 头文件 stdio.h
- 函数原型:char * fgets(char * string, int size, FILE * stream);
- 函数说明:
- string为字符数组
- size为字符大小
- stream为文件流指针
- 注:每次最多读取的字符数为size-1,因为需要在数组最后字符填’\0’
wait()函数和sleep()函数
- wait()函数头文件:sys/types.h,sys/wait.h
- sleep()函数头文件:unistd.h
- sleep是休眠指定时间后继续往后执行;wait是等待一定时间需要触发才能继续往下执行,一般用于进程管理
- sleep函数在linux下计时单位是s,在windows下计时单位是ms; wait函数的计时单位是ms,wait函数运行时间可能没有sleep准确
- sleep只能暂停本线程不能暂停其他线程,wait可以暂停任意线程
- 还有一个重要的区别,sleep属于‘占着CPU睡觉’,不释放对象锁占着资源,线程被挂起到ready queue,会增加时间限制;wait函数则是‘等待使用CPU’,释放对象锁,不占用任何资源,不增加时间限制
delay()函数和usleep()函数
- delay()函数头文件:linux/delay.h
- usleep()函数头文件:unistd.h
- delay函数是循环等待,进程/线程还在运行,占用CPU,计时单位是ms;sleep函数虽然也占用CPU资源,但进程/线程会被挂起
- usleep函数与sleep函数有相同的头文件,不过是us计时,如果延时时间为数秒使用sleep函数,小于几十毫秒尽量使用usleep函数
exit()函数和return
- exit()函数:头文件 stdlib.h,exit(0)表示是正常退出,非零表示非正常退出
- exit结束运行的程序,将参数返回给OS,把控制权交给操作系统;return是退出当前函数,返回函数值,把控制权交给调用函数
2017.05.26