《C和指针》学习小记

下面的内容主要是个人的学习笔记,以便日后复习使用,内容比较简单,大牛们可以略过了,初学者可以互相交流。

1.关于/* */注释符的使用

注释符不能嵌套,在一段代码中,第一个/*和第一个*/直接的所有内容都是注释,包括注释符/*。所以假如有一段代码: 

int a;

/*

int b;

*/

int c;

我们想注释这段代码,于是在int a;和int c;之前之后分别加上/* */,会发现注释是错的。解决办法可以用预处理指令#if,改为:

#if 0

...

#endif

另外和注释符相关的一个问题是运算符问题,int a=b/*p;本意是b/(*p),结果由于词法分析的贪心原则,导致/*结合为注释符,因此在编程时候需要注意下。上述这两个问题在编辑器里面写错了都可以直接看出来,就算不用注意也不会导致错误的发生,除非编辑器的字体没有颜色标识。


2.在使用函数getchar() getc() fgetc()时候,接收返回值的变量应该声明为int,即int a=getchar();因为getchar()的返回值为int类型,且结束符EOF也是值为-1的int类型,使用char类型变量来接收返回结果时,如果编译器没有做处理容易出现错误。


3.关于指针的const声明

int const *p;//p是指向整型常量的指针,可以修改p的值,不能修改p指向内容的值

int * const p;//p是一个常量指针,可以修改p指向内容的值,不能修改p的指向

int  const * const p;//这种声明也是正确的,效果参考上述


4.关于static的声明

当static用于修饰代码块之外的变量或者函数时,static用于修改标识符的链接属性,由external改为internal,被修饰标识符只能在其声明的源文件中被访问。

当static用于修饰代码块内部的变量时,static修改的是标识符的存储类型,为静态存储,不影响变量的链接属性和作用域。用这种方式声明的变量在程序执行之前创建,在程序的执行期间一直存在。


5.sizeof 的一个问题,sizeof是判断表达式的长度,因此并不需要对表达式求值,因此sizeof(a=b+1)并没有对a赋值。


6.关于运算符的求值顺序

a*b+c*d+e*f 在这个表达式中,编译器只保证乘法操作在其相邻的加法操作之前进行,并不保证先算a*b还是先算c*d,因此c+(--c)这样的表达式很容易出现错误。

另外,在表达式f()+g()+k()中,编译器只保证左边的加号先于右边的加号执行,但并不能保证三个函数的调用顺序,因此如果三个函数间存在数据耦合,那么这样的书写方式是存在风险的。


7.关于移位符的一个应用 点击打开链接


8.C中函数的可变参数列表实现方法点击打开链接


9.strlen()返回的是size_t类型的值,它是一个无符号整数类型,因此表达式

if( strlen(x) - strlen(y) >=0) ...中,if的判断值始终为真,因为两个无符号整数做运算结果还是无符号整数,不会为负数


10.char *strncpy(char *dst ,char *src, size_t len),该函数总是正好向dst写入len个字符,src长度如果不够len,就用NUL填充,如果大于等于len,就写入len个字符,但是不会在复制结尾插入NUL。因此在程序中可以在len-1处赋值'\0'。使用此函数时要注意确定好len的值,不要越界。

char *strncat(char *dst ,char *src, size_t len),该函数至多向dst添加len个字符并在结尾添加'\0',如果超出dst的剩余空间了仍会在dst尾部添加字符,产生越界,因此len的大小也需要确定好。


11.字符串查找函数:

char *strchr(char const *str, int ch);//从左向右

char *strrchr(char const *str, int ch);//从右向左

char *strpbrk(char const *str, char const *group);//匹配组中任何一个 

char *strstr(char const *str1, char const *str2);//如果str2为空字符串,则返回str1


size_t strspn(char const *str, char const *group);//返回str开头部分属于group的元素个数,即返回第一个不在group中的元素的下标

size_t strcspn(char const *str, char const *group);//返回str开头部分不属于group的元素个数

char *strtok(char *str, char const *sep);//根据sep分隔str,会修改str


12.如果要初始化union类型变量,初始值必须是union变量的第一个成员的类型。struct类型变量作为函数参数使用时大多数情况下传递一个struct类型的指针更为合适,因为C的函数参数是传值的,如果传递一个struct类型的变量,那么需要把整个变量拷贝到栈中,效率很低。


13.所有用于对数值表达式进行求值的宏定义都应该加上括号,避免在使用宏时,由于参数中操作符之间产生不可预料的相互作用。例如 #define DOUBLE(x) ((x) + (x))


14.条件编译,可以用来调试程序。在程序中如果有如下语句:

#if expr

    statements

#endif

expr是常量表达式,一般通过#define 定义,该表达式的值在预处理时进行求值,如果为真,则statements部分被编译,否则被忽略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值