读书笔记-C语言关键字
#include <stdio.h>#include <string.h>int main(){ signed char a[1000]; int i = 0; for (i = 0; i < 1000; i++) { a[i] = -1 - i; } printf("%d\n", strlen(a)); return 0;}
当 i = 128 的时候,a[128] = -1 - 128 = -129 ,signed char 的取值范围是 -128~127,所以超出了范围,-129 源码: 1 1000 0001 ,补码:1 0111 1111 ,低 8 位 0111 1111 ,即 127。
当 i = 255 的时候,a[255] = -1 - 255 = -256 , -256 的原码 11 0000 0000 补码:11 0000 0000 ,低 8 位全为 0, strlen 遇到 '\0' 就结束,所以上述代码输出 255。
所以,char 类型如果直接使用就用来表示字符,如果加了 signed 和 unsigned 限定符的话就用来表示数字。
2.7. if else 组合bool变量与“零值”比较bool b = FALSE;if(b) printf("TRUE");if(!b) printf("FALSE");
上面这种写法是值得推荐的,其他方式会有问题。
float 变量与“零值”比较if(test > -EPSINON) || (test < EPSINON); // EPSINON 为定义好的精度
指针变量与“零值”比较
if(NULL == p)if(NULL != p)
先处理正常情况后处理异常情况或者说先处理概率大的,再处理概率小的赋值运算不能用在产生 bool 值得表达式上
if((x = y) != 0 )printf("------");
这样写是错误的,应该这样写
x = y;if(x != 0)printf("-----");
2.8. switch case 组合
当嵌套比较少量的分支的时候可以使用 if else 组合,但是当嵌套的分支多的时候就要使用 switch case 组合了,但是也不要刻意去创造一个 switch 变量。
每个case 的结尾不要忘了 break; 除非你有意让多个分支重合。最后必须使用 default 分支,也需要 break; 。在 switch case 组合中禁止使用 return 语句。switch 表达式不应该是有效的 bool 值,例如下面的表达式是不允许的。switch (x == 0){......}
case 后面的值只能是×××或者字符型的常量或者常量表达式。case 语句的拍立顺序按照字母顺序排列把正常情况放在前面,把异常情况放在后面,并做好注释,哪里是开始,哪里是结束。把常执行的情况放在前面,不常执行的情况放在后面。没种情况的相关代码要尽量简洁,必要时可以使用函数。2.9. do while for 关键字break 和 continue 的区别break 跳出循环continue 终止本次循环,进入下一次循环多重循环的时候应该把最长的循环放在最内层,最短的循环放在最外层,这样可以有效降低CPU切换循环层数的次数。for 循环中,半开区间比闭区间直观,能写成 a < 10,绝不写成 a <= 9。不要在 for 循环体内改变循环变量,否则会导致循环失控,像下面这种代码是不好的。
for(int i = 0; i < n; i++){n = 10;}
循环嵌套控制在3层以内。for 循环的控制语句不能包含任何浮点类型的变量。2.10. goto 关键字
goto 关键字可以在代码中灵活的跳转,存在很大的争议,有的建议慎用 goto ,有的建议不要用。我觉得用得好还是可以用。
int *p = NULL;...goto error;...error: return -1;
2.11. void 关键字
void *p = NULL;int *p_int = NULL;p = p_int; //不会报错,是正确的p_int = p; //报错,是错误的
void 修饰函数返回值和函数参数如果函数没有返回值应该将其声明为 void 类型,函数没有参数也应该将其声明为 void 类型如果函数的参数可以是任意类型的指针,则声明为 void *
void *memcpy(void *dest, const void *src, size_t len)
void 不能代表一个真实的变量,例如下面的代码是错的
void a;fun(void a);
2.12. return 关键字return 用来终止一个函数,并返回其后跟的值。
return(value); //括号可以省略,但一般不省略,尤其是返回一个表达式的值得时候
return 不能返回指向栈内存的指针,因为该内存在函数体结束的时候就被销毁了。2.13. const 关键字const 修饰的只读变量必须在定义的同事初始化(首先 const 修饰的变量,其次是只读,两层含义)想一想 switch case 中 case 语句后面就可以是 const 修饰的只读变量吗?
先忽略类型,看 const 离谁近就修饰谁
const int *p; // const *p ,修饰 *p , p 可以改变, p 指向的内容不可变int const *p; // const *p ,同上int * const p; // * const p ,修饰 p,p 不可以改变,p 指向的内容可以改变const int * const p; // const * const p ,第一个 const 修饰 *p,第二个 const 修饰 p,所以 p 和 p 指向的内容都不能改变
修饰函数的参数,当不希望函数的参数在函数体中被改变的时候可以使用 const 修饰函数的参数。修饰函数的返回值(const int fun(void))。在另一个文件引用 const 变量时使用 extern const int i; 声明即可,而不是定义。2.14. volatile 最易变的关键字volatile 关键字和 const 一样,是一种类型修饰符。它修饰的变量表示可以被某些编译器未知的因素更改,比如操作系统,硬件或其他线程。遇到这个关键字修饰的变量,编译器就不对它做优化,每次需要访问的时候都重新去内存中读取。
在这里 volatile 只是告诉编译器 a 的值可能会被改变,需要访问时每次都要重新到内存中去取。
2.15. extern 最会戴帽子的关键字修饰函数和变量,表示函数和变量不是在本文件定义的,在本文件只是使用 extern 声明。2.16. struct 关键字空结构体占多大内存?大多数编译器是 1,gcc 是 0。所以不要太相信书本上的东西,一定要自己亲自验证。
柔性数组不要惊讶,C语言中确实有柔性数组这个说法的。C99 中,结构体最后一个成员允许是未知大小的数组,这就是柔性数组。但是柔性数组成员前必须至少有一个其他成员。sizeof 计算的大小不包含柔性数组所占的空间。为包含柔性数组的结构体分配内存要使用 malloc ,并且分配的内存应该大于 sizeof计算的值。typedef struct st_type{ int i; a[0];}type_a;//有些编译器会报错,可以改成typedef struct st_type{ int i; int a[];}type_a;
//可以使用下面的代码为柔性数组分配内存,但是分配好之后使用 sizeof 计算结构体的大小依然是不包含柔性数组所占的内存的。type_a *p = (type_a *)malloc(sizeof(type_a) + 100 * sizeof(int));//记得用完之后要 freefree(p);
结构体里面能不能放函数呢?
union { int i; char ch;}c;c.i = 1;//这时候 ch 只需要一个字节存储,在低地址,如果 ch 的值等于 1, 说明 i 的值得低字节 1 存储在低地址,是小端模式。Ubuntu、Windows 等 x86 架构都是小端模式。
int main(){ int a[5] = { 1, 2, 3, 4, 5 }; int *p1 = (int *)(&a + 1); int *p2 = (int *)((int)a + 1); printf("%x %x\n", p1[-1], *p2); return 0;}// 5 2000000 小端模式 大端模式 5 100
2.18. enum 关键字
enum enum_type_name{ ENUM_CONST_1, ENUM_CONST_2, ENUM_CONST_3, ... ENUM_CONST_n} enum_variable_name;
enum_type_name 是自定义的枚举类型,而 enum_variable_name 是 enum_type_name 类型的一个变量。sizeof(enum_variable_name) 的值是多少呢? 想想枚举成员的类型就会知道是 4 了, 空枚举类型的大小也是 4。2.19. typedef 关键字,最伟大的缝纫师typedef 是给已经存在的数据类型取一个别名,而不是重新定义新的数据类型。
typedef struct student{ int age; char name;} stu_1, *stu_2;const stu_2 student_1; // 其实是 const (struct student *)student_1; 所以 修饰的是 student_1 本身,而不是指向的内容stu_2 const student_2; // 其实是 (struct student *)const student_2; 所以 修饰的也是 student_2 这个指针本身,而不是指向的内容
typedef 和 #define 之间的区别
#defien INT32 inttypedef int INT32_tunsigned INT32 i = 10; //没问题,只是替换unsigned INT32_t j = 10; //错误,不支持#defien PCHAR char*typedef char* pcharPCHAR ch2, ch3; //ch2 是 char * 类型,ch3 却是 char 类型pchar ch3, ch5; //ch4, ch5 都是 char * 类型
不复习不知道,一复习吓一跳,原来 C语言 关键字还有这么多知识点,以前也没怎么注意,当然不止这些,我只是记录了我认为比较重要而且容易搞混淆的。
如果你觉得我的读书笔记对你有用,可以关注微信公众号 kalier 哦,最新的文章和读书笔记都将在这里首发。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。