前言:本篇文章主要用于记录博主本人从事C软件开发过程中遇到的各种疑难杂症和奇技淫巧,以知识点的形式将其总结,以做后观。(亦是记录博主如何从C语言小白一步一步走向软件开发......)
目录
1 const
const用以声明变量永不变化的常数。一般来说这些变量都应该被放在ROM区(也就是Flash程序空间)以节约宝贵的RAM内存。但一个简单的const声明并不能保证变量最后会被分配到ROM区,安全的做法必须配合#pragma声明的CONST_SEG或INTO_ROM数据段一起实现。
任何类型的变量,都可以冠以const声明。
2 运算符
- %:取余数
- >>:移位运算符。a >>= b相当于 a = a >> b,将二进制a右移b位(低位丢弃)
- &&:逻辑与运算符
- &:位与运算符。a &= b 相当于 a = a & b,按位与运算之后赋值给a
- ||:逻辑或运算符
- |:位或运算符
- ^:异或运算符,位运算的一种。a ^= b,a、b相同a为0,a、b不同a为1
- ! :逻辑非运算符。!0为真,其余为假
- ~:按位取反运算符
3 数据格式声明
格式字符:
- %d:有符号十进制整数
- %c:一个字符
- %s:一个字符串
- %f:输出实数【以小数形式,默认实数的整数部分全部输出,小数部分输出6位】
- %e:以指数形式输出实数
- %ld、%lld:长整型数据、双长整型数据
- %x:十六进制数
% 是格式声明符,若想输出 %,则应连用两个 % 表示,例如:printf("%%\n");
- %m.nf:m代表输出数据的宽度,该宽度包括整数。n代表输出数据的小数位数(末尾以四舍五入原则,若格式为%-m.nf,表示数据向左对齐)
- %m.ns:m代表输出字符的宽度,n代表只打印前n个字符(%-m.ns标记使得文本左对齐输出)
4 逃逸字符
- \b:回退一格
- \t:到下一个表格位
- \n:换行
- \r:回车
- \’:单引号
- \”:双引号
- \\:反斜杠本身
\ 在C语言中被称之为转义字符。
5 scanf函数
scanf类似于一个获取单词的函数,若用其读取字符串,从第一个非空白字符作为字符串的开始,以下一个空白字符作为字符串的结束。若指定了字段宽度,则在读取字段宽度的字符或读到空白字符后结束。其具有返回值,可以分成以下3类情况:
- 正整数:表示成功读取的项数
- 0:表示用户输入的值不匹配
- EOF:表示检测到“文件结尾”
scanf中的 * :用于抑制赋值
6 取整相关
- i=(int)2.5; // int:直接舍去小数部分,i=2
- floor(x); // 返回的是小于或等于x的最大整数
- ceil(x); // 返回的是大于x的最小整数
7 单反斜杠(\)的作用
- 可以作为转义字符使用,例如 \n 表示换行符
- 可以作为续行符使用,用于一行的结尾,表示本行与下一行连接起来
8 switch 与 if
- 若根据浮点类型的变量或表达式来选择,则无法使用 switch
- 若根据变量在某范围类决定程序流的去向,则推荐使用 if
- 使用 switch 程序通常运行快一些,生成的代码少一些
9 for
for 循环后面直接加分号,则表示只进行 for 循环而跳过后面的语句。且当其后面没有语句时,必须要加一个分号。
10 链表和数组
选择何种数据类型取决于具体的问题。
- 如果因频繁地插入和删除项导致经常调整大小,而且不需要经常查找,选择链表会更好。
- 如果只是偶尔插入或删除项,但是经常进行查找,使用数组会更好。
- 如果既需要频繁插入和删除项,又要频繁查找,则选择二叉查找树。
11 const与数组
a[] = {1,2,3,4,5}; // 表示a只能指向该数组, 不能指向其他数组 const int a[] = {1,2,3,4,5}; // 不止a为const的指针,数组内部的每个单元都是const int类型,若有以上类型定义,则必须通过初始化进行赋值
12 const与指针
int* const q = &i; // 指针本身被定义为const // 表示一旦q得到了某个变量的地址,其就不可以再指向其他变量, q只能指向一个固定的地址 *q = 26; // ok q++; // ERROR const int* p = &i; // 指针所指的变量被定义为const // 表示不能通过这个指针去修改指向的变量的值(并不表示指向的变量变成const) *p = 26; //error i = 26; // ok p = &j; // ok
13 数组指针
数组指针定义:int (*p)[n];
()优先级高,先与p结合成为一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
// 将二维数组赋给数组指针: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 p=a; // 将该二维数组的首地址赋给p, 也就是a[0]或&a[0][0] p++; // 该语句执行过后, 也就是执行p=p+1后, p跨过行a[0][]指向了行a[1][] // 所以数组指针也称指向一维数组的指针, 亦称行指针。
14 指针数组
指针数组定义:int* p[n];
[]优先级高,先与p结合成为一个数组,再由 int* 说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,p会指向下一个数组元素。
// 将二维数组赋给指针数组: int a[3][4]; int* p[3]; for (i=0; i<3; i++) { p[i]=a[i]; } // 这里int* p[3]表示一个一维数组内存放着三个指针变量, 分别是p[0]、p[1]、p[2], 所以要分别赋值 // p=a; 这样赋值是错误的 // 因为p是个不可知的表示, 只存在p[0]、p[1]、p[2]…p[n-1], 而且它们分别是指针变量可以用来存放变量地址。 // *p=a; 这样赋值是可以的, *p表示指针数组第一个元素的值, 即相当于 p[0] = a[0][]
通过以上,数组指针和指针数组两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
当数组指针和指针数组都指向二维数组,要表示数组中i行j列的一个元素时,以下引用方式等价:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
符号优先级:()>[]>*