• 字符集定义了字符和二进制的对应关系,为每个字符分配了唯一的编号
  • 而字符编码规定了如何将字符的编号存储到计算机中
  • Unicode 可以使用的编码方案
  • 多字节字符,或者窄字符
  • 宽字符。

变量和数据类型

称为格式控制符

  • %d
  • %f
  • %c
  • %s

sizeof:sizeof 是C语言中的操作符,不是函数

1
2
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
    2
    char 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
2
3
4
int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
int (*p)[4] = a;
printf("%d\n", sizeof(*(p+1)));
16
  • 指针数组和二维数组指针
  • 函数指针

只需一招,彻底攻克C语言指针


  • 复杂数据类型或构造数据类型。
  • 结构体是一种自定义的数据类型,是创建变量的模板,不占用内存空间;结构体变量才包含了实实在在的数据,需要内存空间来存储。
  • 数组名在表达式中会被转换为数组指针,而结构体变量名不会
  • 结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针
  • enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
  • 不能用&取得它们的地址。这就是枚举的本质。
  • 操作文件的正确流程为:打开文件 –> 读写文件 –> 关闭文件
  • fclose(fp);