@(C 语言)[基础, 编程]
薄薄一本书, 却记录了c 编程经常犯下的错误,再读,记录下。
a---b // (a--) - b
别复杂化, 使用括号,清晰直观
char* pStr = "YES" // 'Y', 'E', 'S', 0 , 4 char
char ch = 'y'// a char
单引号实际代表一个整数 双引号代表指向无名数组的起始字符的指针(字符结尾 0) 使用库函数计算得到的字符串长度不包括结尾的0!
(* (void(*)())0 )();
// call void fun()
// 声明指向上述fun的指针
void (*pfun)();
// 注意括号,void *rf(); 声明了返回void* 指针的函数。
pfun = &fun;// pfun = fun; 也可以
(*pfun)();
pfun(); // 简写
// 对0地址进行类型转换
pfun = (void (*)())0;
没必要多声明一个‘哑’变量pfun,因此如开端所写,对0进行类型转换,再解引用调用
// 直观的话
typedef void (*pfun)();
(* (pfun)0 )();
准则 : 按照使用的方式来声明
if (flag & 0x01 != 0) {}...
//want
if ((flag & 0x01) != 0) {}...
//actualy
if (flag & (0x01 != 0)) {}...
r = hi << 4 + low;
//watnt
r = (hi << 4) + low;
// actually
r = hi << (4 + low);
a = *p++;
// == *(p++) <——
a = *p; p++;
记录优先级可以写出更加优雅的代码, 不装X。
//少写出错
if (i < 2)
return
i = 2;
//->
if (i < 2) return (i = 2);
//多写出错
if (i < 2);
a = 1;
//->
if (i < 2);
a = 1; // every time
break
!!!!if (x == 0)
if (y == 0 ) {..}
else {
..
}
// 不同所缩进, 实际是
if (x == 0) {
if (y == 0) {..}
else {..}
}
避免悬挂式else, 使用{}进行匹配
if (x == 0) {
if (y == 0 ) {..}
} else {
..
}
C语言中只有一维数组
int a[12] // 12个 int
int b[12][31] // 12个 int[31]类型数组的元素
// sizeof(a) == 12 * sizeof(int);
// sizeof(b) == 12 * (31 * sizeof(int))
// attention
/*
* 数组名是数组的首地址(符号表中对应地址)
* 数组操作 :数组地址 + 偏移地址 --> 内容
* 指针操作 : 指针 --> 数组地址 + 偏移 --> 内容
*/
int *p = a;
//sizeof(p) == sizeof(int*) // sizeof of pointer(32位 4, 64位 8)
//sizeof(*p) == sizeof(int)
对数组取sizeof可以得到数组的大小,但是对其他指针取sizeof取到的是平台地址的长度
2.数组根据他自身的类型,决定其在加减时,实际增减的内存地址值
int *p0 = (int*)0x0000;
char *p1 = (char*)0x0000;
++p0; ++p1; // p0 += 1; p1 += 1;
//p0 == 0x0004; p1 == 0x0001; // if sizeof int == 4
指向数组的的指针
char array[12][31];
char (*p)[31];
char **pp = array; //注意这里
p = array;
p[0] -->array[0];
++p -->array[1];
假设array在地址0x0000,那么p 也是地址0x0000, ++p后,p指到array[1],所以地址就是array + sizeof(char)*31
; 但是,pp,指向指针的指针,一开始也是指向array[0], 但是,++pp后,指向的和p不一样,而是加了一个sizeof(char*)的长度
,因为他的单位是一个指针大小,而p的单位是一个char charxx[31]的大小。
所以,请告诉指针,我指的到底是谁?
char *s = "jj";
char *t = "xx";
//1 :strlen 不包括字符串结束字符
char *r = (char*)malloc(strlen(s) + strlen(t) + 1);
if (!r) {
//2 : malloc 可能申请失败
} else {
strcpy(r, s);
strcpy(r, t);
//..
}
//3 : 记得释放!
free(r);
左闭右开
, 在一些用变量去索引的情况下,没有处理好,导致访问读取未位置的内容带来的错误。)
提到这种不对称数学角度来说不优美,却给程序设计带来了一些简化。for (int i = 0; i < 6; ++i) {
...
}
1, 上下边界差就是元素数目
2, 上下相等,范围为空
3, 即使取值为空,上边界永远不小于下边界
...
#define f (x) ((x) -1)
// #define f ((x) ((x) - 1))
宏定义中恰当使用括号,避免实际使用展开后由于优先级而带来的错误。
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
if (..)
assert(..);
else
assert(..);
// 展开
if (..)
if (..) assert_error(__FILE__, __LINE__)
else
if (..) assert_error(__FILE__, __LINE__)
// 参考前面悬挂式else, 整理后看到实际效果不一致
if (..)
if (..)
assert_error(__FILE__, __LINE__)
else
if (..)
assert_error(__FILE__, __LINE__)
char fifo[SIZE];
// 指针指向,不能通过指针修改fifo内容
char const *pff = fifo;
// 指针指向,不能修改指针内容, 即保证pff == fifo 永远
char * const pff = fifo;
// 修饰谁,靠近谁。
// pff 不可变,*(pff + xx) 随时可能改变。
static volatile char* const pff = fifo;
char a = 0x03;
char b = 0x81;
uint16_t c = a <<8 | b;
// c = 0xFF81 -->
// b 变成16bit 的时候,char b是有符号数,高位填充1(填充符号位)
unsigned char a = 0x03;
unsigned char b = 0x81;
uint16_t c = a <<8 | b; // c = 0x0381