c专家编程笔记

1. 赋值约束

要使赋值形式合法,必须满足下列条件之一:  两个操作数都是指向限定符或无限定符的相容类型指针, 左边指针所指向的类型必须具有右边指针所指向类型的全部限定符

char *cp;   

const char *ccp;

ccp = cp;

这个赋值是合法的, 而 cp = ccp;  产生生警告


const float* 类型并不是一个有限定符的类型,它的类型是  指向一个具有const 限定符的float类型的指针, 也就是说const修饰符石修饰指针所指向的类型,而不是指针本身

const char** 也是一个没有限定为的指针类型,他的类型是指向有const限定符的char类型的指针的指针

所以, char** , 和 const char**  都是没有限定符的指针类型,但是他们所指向的类型不一样  前者是 char*, 后者是 const char* ,因此他们不相容

2.const陷阱

当const出现在*号左边时指针指向的数据为常量

当const出现在*后右边时指针本身为常量



3.算术运算

多个运算符都会引发转换,以类似的方式产生结果类型。称为寻常算术转换

类型为char 或 short 的操作数被转换为 int, float 转换为 double , 如果其中一个操作数是 double,另一个就转换成double. 其中一个是long,另一个就转换long

当执行算术运算时,操作数的类型如果不同,就会发生转换。数据类型一般朝着浮点精度更高,长度更长的方向转换,整数如果转换为signed不会丢失信息,那就转换成他,

否则转换为unsigned

所以当  int a = -1 ;   a 与一个无符号类型 unsigned比较时,会升级成无符号类型,所以a的值会是一个很大的整数

这在判断指令中,往往会照成Bug ,当你试图比较 某个函数的返回至 与 -1 时,请注意这个问题,sizeof就返回无符号整数


建议:尽量不要在代码中使用无符号类型,尽量使用像int这样的有符号类型.


优先级与结合性

在表达式中,优先级处于同一级别时,结合型就发挥作用,来解决求值顺序

所有的赋值符都具有右结合性,就是表达式最右边最先执行,然后依次往左边执行,

& , | 这些位操作符具有左结合性,从左往右依次执行

所有优先级相同的操作符,结合性也是相同的


4. gcc 编译器设计者抵制的 #pragma

#pragma 指示符的行为由编译器定义,在GUN c编译器中,他会尝试打开几个游戏

vs 下它可以链接到库

#pragma comment(lib,"DllDemo.lib")    or    #pragma comment(dll,"DllDemo.dll")


5.小知识

NUL 用于结束一个ACSII字符串

NULL 用于表示什么也不指向 ,空指针

break 跳出最近的一层循环

static 申明静态变量,会在第一次执行时初始化,而后一直保存变量直到程序结束

static 放在函数前,会使此函数在这个文件之外不可见

extern 用于变量表示它在其他地方定义,用于函数表示全局可见此函数,属于多余的,不加也是全局可见

void 用作函数的返回类型表示不返回任何值, 在指针中表示通用指针,在参数列表中表示没有参数

* 乘法运算符, 用于指针,间接引用, 在声明中,表示指针

&取地址操作符, 位与操作符

<<= 左移复合赋值运算符

< 小于运算符, #include指令的左定界符


*指针数组 int * (ap[]) 数组每个成员都是 int* 类型


6.小心Bug

strlen(str)+1 永远记得这个函数只取不包含/0的长度


switch 语句中defaoult可以出现在任何位置,注意每条分支的break


字符串自动合并约定, printf("abcde" "fghijk" "opqrst" ) 相恋的字符串在编译时自动合并,除了最后一个字符串,其余字符串末尾的\0 自动删除

由此引发问题:

char *p[] = {

"abhd" ,

"retd",

"dsfs" //忘记了逗号,所以这2条字符串合并了,

"sds", //末尾使用逗号也没关系

} 由此造成字符串的数组不是我们想要的

p[2] 时候的值不是我们想要的, p[3]还会超出数组下标!!!


if(x>>4) 是什么意思

p = N * sizeof *q // 你能不能马上判断出这是一个乘号还是两个

apple = sizeof( int ; *p ; //这又代表什么


优先级问题

.的优先级高于* , -> 用于解决这个问题

[] 高于 *

函数() 高于 *

== 和 != 高于位操作符

== 和 != 高于赋值赋

算术运算高于位移运算符

逗号在所有运算符中优先级最低


*p.f 容易以为是 (*p).f 实际上是 *(p.f) //. 优先级高于*

int *ap[] 容易以为 int (*ap)[] ap是指向int数组的指针, 实际上 int*(ap[]) ap是元素为int指针的数组, [] 高于 *

int *fp() 容易以为 int (*fp)() 指针函数。 实际上 int* (fp()) 返回值类型为int*的函数 函数() 高于*

(val & mask != 0) 容易以为 (val & mask) != 0 , 实际上 val & (mask != 0) == 和 !=高于位操作符

c = getchar() != EOF 容易以为 (c = getchar()) != EOF ,实际上 c = (getchar != EOF) == != 高于赋值福

msb << 4 + lsb 容易以为 (msb<<4) + lsb , 实际 msb << (4+lsb) 运算高于位移

i = 1,2 容易以为 i = (1,2) 实际上 (i = 1),2 逗号优先级最低


计次顺序问题:

x = f() + g() * h() ;

g() 和 h() 会先执行乘法运算,但是他们的调用可能以任何顺序出现.所以避免这类代码


7.指针与数组

char *j[20] //一个指针数组,数组里所有元素都是char*指针

char (*j)[20] //一个数组指针,数组内元素都是char

const int * a ; //指针所指对象是const

int const * a //指针所指对象是const

int * const a; //指针是const

const在*号右边,指针就是const


数组并非指针!

文件1: int mango[100];

文件2: extern int *mango;

这是错误的,究其原因,要知道数组和指针的访问方式

数组只需要知道数组的起始地址+ 偏移即可 比如 mango[2]

而指针需要先得到知道内保存的地址,再到地址中去相加偏移 mango[2] 指针的

而文件2中只是声明了mango,定义在文件1,所以mango是一个数组

所以文件2的 mango[2] 访问时应该直接取得基址+偏移 ,而编译器却认为这是一个指针,他先读取指针所指向的地址然后加偏移



 关键字:

struct 结构名 {} 申明一个结构

union 联合名 {} 申明一个联合,联合与结构的区别在于内存布局,在联合中,所有成员都是从便宜地址0开始存储,这样每个成员重叠在一起

某一时刻,只有一个成员正在存储于该地址。一般用来节省空间,比如2个相互排斥的字段,不可能同时弧线,就可以放在一个联合中爱节省空间

enum 枚举名 {} ; 把一串名字与一串整型值联系在一起,

typedf 为类型引入一个新名字

#define 宏文本替换

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值