c语言
- 字符集定义了字符和二进制的对应关系,为每个字符分配了唯一的编号
- 而字符编码规定了如何将字符的编号存储到计算机中
- Unicode 可以使用的编码方案
- 多字节字符,或者窄字符
- 宽字符。
变量和数据类型
称为格式控制符
- %d
- %f
- %c
- %s
sizeof:sizeof 是C语言中的操作符,不是函数
1 | printf("a=%#ho, b=%#x, c=%ld\n", a, b, c); |
char 是一个字符类型,是用来存放字符的,但是它同时也是一个整数类型,也可以用来存放整数
- %g 默认最多保留六位有效数字,包括整数部分和小数部分;%f 和 %e 默认保留六位小数,只包括小数部分。
- %g 不会在最后强加 0 来凑够有效数字的位数,而 %f 和 %e 会在最后强加 0 来凑够小数部分的位数。
- 计算机在存储字符时并不是真的要存储字符实体,而是存储该字符在字符集中的编号
- 无论在哪个字符集中,字符编号都是一个整数;从这个角度考虑,字符类型和整数类型本质上没有什么区别。
- wchar_t:宽字符类型。wchar_t 其实是用 typedef 关键字定义的一个别名
- putchar、printf 只能输出不加L前缀的窄字符
- putwchar 和 wprintf:
- 在输出宽字符之前还要使用 setlocale 函数进行本地化设置
- 对于转义字符来说,只能使用八进制或者十六进制。
- 余数可以是正数也可以是负数,由 % 左边的整数决定:
- printf() 执行结束以后数据并没有直接输出到显示器上,而是放入了缓冲区,直到遇见换行符\n才将缓冲区中的数据输出到显示器上
- &称为取地址符
- 里看到的地址都是假的,是虚拟地址
1
2char str1[] = "http://c.biancheng.net"; 读写
char *str2 = "C语言中文网";读 - scanf() 读取数据时需要的是数据的地址
- 字符串的名字会自动转换为字符串的地址
- gets() 能读取含有空格的字符串,而 scanf() 不能。
- case 后面必须是一个整数
- break:跳出循环
- continue
- 数组可以作为缓存(临时存储数据的一块内存)使用
- 按行连续赋值应该写作:
1
int a[5][3]={80, 75, 92, 61, 65, 71, 59, 63, 70, 85, 87, 90, 76, 77, 85};
- 字符数组只有在定义时才能将整个字符串一次性地赋值给它,一旦定义完了,就只能一个字符一个字符地赋值了
- ‘\0’是 ASCII 码表中的第 0 个字符,英文称为 NUL: 它在C语言中唯一的作用就是作为字符串结束标志。
- 需要注意的是,逐个字符地给数组赋值并不会自动添加’\0’
- 更加专业的做法是将数组的所有元素都初始化为“零”值
- 因为字符串名字或者数组名字在使用的过程中一般都会转换为地址
- 静态数组。
- 在用字符串给字符数组赋值时,要保证数组长度大于字符串长度,以容纳结束符’\0’。
- 普通数组(固定长度的数组)是在编译期间分配内存的,而变长数组是在运行期间分配内存的。
- 函数不能嵌套定义
- 函数声明
- 头文件中包含的都是函数声明,而不是函数定义,函数定义都在系统库中
- 以#号开头的命令称为预处理命令
- 在编译之前对源文件进行简单加工的过程,就称为预处理(即预先处理、提前处理)
- 文件包含允许嵌套,也就是说在一个被包含的文件中又可以包含另一个文件。
- 宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串
- 宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起替换
- 终止其作用域可使用#undef命令
- 宏在编译之前就被处理掉了,它没有机会参与编译,也不会占用内存
- 条件编译:条件编译是预处理程序的功能
#if
后面跟的是“整型常量表达式”
指针
- 指针变量
- 指针运算符
- 使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价要高
*
可以用在指针变量的定义中,表明这是一个指针变量- 使用指针变量时在前面加
*
表示获取指针指向的数据 - 如果一个指针指向了数组,我们就称它为数组指针
- 根据数组指针不能逆推出整个数组元素的个数,以及数组从哪里开始、到哪里结束等信息
- 数组名是常量
- 字符串常量,意思很明显,常量只能读取不能写入
- 不管使用哪种方式传递数组,都不能在函数内部求得数组长度,因为 intArr 仅仅是一个指针,而不是真正的数组
- 指针函数
- 对没有初始化的指针赋值为 NULL:
char *str = NULL;
- 从整体上来看,NULL 指向了地址为 0 的内存,而不是前面说的不指向任何数据。
- 在大多数操作系统中,极小的地址通常不保存数据,也不允许程序访问,NULL 可以指向这段地址区间中的任何一个地址。
- void *表示一个有效指针,它确实指向实实在在的数据,只是数据的类型尚未确定
- C语言动态内存分配函数 malloc() 的返回值就是void *类型
void *
,它不是空指针的意思,而是实实在在的指针,只是指针指向的内存中不知道保存的是什么类型的数据。- sizeof 是根据符号类型来求长度的
- C语言标准规定,当数组名作为数组定义的标识符(也就是定义或声明数组时)、sizeof 或 & 的操作数时,它才表示整个数组本身,在其他的表达式中,数组名会被转换为指向第 0 个元素的指针(地址)。
- 对数组的引用 a[i] 在编译时总是被编译器改写成
*(a+i)
的形式 - 取下标操作符[ ]是建立在指针的基础上
- 函数内部,arr 会被转换成一个指针变量,编译器为 arr 分配 4 个字节的内存
- 指针数组(每个元素都是指针)
- 二维数组指针:int (*p)[4] = a;
1 | int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} }; |
- 指针数组和二维数组指针
- 函数指针
- 复杂数据类型或构造数据类型。
- 结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。
- 数组名在表达式中会被转换为数组指针,而结构体变量名不会
- 结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
- 不能用&取得它们的地址。这就是枚举的本质。
- 操作文件的正确流程为:打开文件 –> 读写文件 –> 关闭文件
- fclose(fp);