C专家编程--随记(一)

第二章------BUG

一.多做过之(不该做的做了)**

1.一个L和两个L的区别

‘NUL’ —> 表示结束一个acsii字符串(’\0’)
‘NULL’ —> 表示空指针

2.switch … case…问题:

(1) case里出现的值过于任性,可以避免在switch{ }再去声明一些变量,再对这些变量赋予初值,是没有必要的。

(2)switch内部语句可以添加任何标签,可以用goto,但是会破坏程序的结构化。

(3)不会在执行完每个case之后自动终止,需要在每个case后面加break,但要注意使用break会带来什么影响,如果没有break,则会造成fall through。

3.合并相邻字符串
(1) 旧风格

printf("you are a boy, but you should good \
study day day up.so you must be work hard \
everyday!\n");
//除了最后一行,其余每一行字符最后的'\0'会被删掉,编译时自动合并

(2)新风格

printf("you are a boy, but you should good"
"study day day up.so you must be work hard "
"everyday!\n");
//除了最后一行,其余每一行字符最后的'\0'会被删掉,编译时自动合并

tips:使用时要注意,如果需要逗号分隔的,不能遗漏

(3) 是否需要预留逗号(古老方法)
–其实本无必要,没有意义
可以用以下方式解决:

func(char *string)
{
    static char str1=' ';
    printf("%c %s\n",str1,string);
    str1=',';
}
//开头给个空格,之后就自动在字符串前面加个逗号,
//比一开始让逗号加在后面方便多了

4.缺省可见性
在缺省情况下,函数的名字是全局可见的,前面可以加个多余的extern 关键字.

func apple()  //全局可见
extern func pear() //全局可见
static func water() //在此文件之外不可见
//如果要限制函数的可见性的话就加上 static(局部作用域和全局生命期)
二.误做之过(该做的没做)

1.符号重载
在这里插入图片描述

int i = 1 , 2;
//逗号运算符最低,约等于int (i = 1),2;--->i=1

tips:记住两个优先级即可,乘法除法先与加减,其余的一律加括号

3.gets()缺陷
gets( )是从流中读入一个字符串,但不检查缓冲空间,很容易出问题
—解决方法用fgets( ),对读取字符设置了限制

:char *fgets (char *buf, int n, FILE *fp) 
// n 表示空间长度 可以用 sizeof(buf)
三.少做之过(该做但做的不合适)

1.空格
"\ "是转义字符,可以和回车使用,当做下一行对当前行的延续,用于连接长字符串。
—但是\newline 和 \ newline 是不一样的
注意:空格不要随便省略,否则会造成错误
eg:z = y+++x -->会导致error

2.要合理运用"//"注释符

3.编译器日期被破坏

//把源文件的timetamp转换为表示当地格式日期的字符串
char *localized_time(char *filename)
{
    struct tm *tm_ptr;
    struct stat stat_block;
    char buffer[120];
    //获得原文件的timestamp,格式为time_t
    stat(filename,&stat_block);
    //把UNIX的time_t转换成tm结构,里面保存当地时间
    tm_ptr = localtime(&stat_block.st_mtime);
    //把tm结构转换成以当地日期格式表示的字符串
    strftime(buffer,sizeof(buffer),"%a %b %e %T %Y",tm_ptr);
    return buffer;
}

----问题出在数组buffer是局部变量,局部作用域和生存期,是自动分配内存的数组,一旦离开函数就是自动销毁内存!!
改进方法:
(1) 返回一个指向字符串常量的指针

char *fun(){return "you are good!"};
//缺点是字符串常量存储于只读内存区是不能改的

(2) 使用全局声明的数组
该情况只适用于自己创建字符串的情况,缺点是任何人都可以修改这个全局数组,而且函数下一次调用的时候也会覆盖内容.

(3)使用静态数组

char *func()
{
    static char buffer[20];
    ....
    return buffer;
}

–可以防止其他人修改数组,只有拥有指向该数组的指针的函数才能修改这个静态数组,但下一次调用也会覆盖内容,所以需要调用函数将其备份。
—如果大型的缓冲区闲置的话是非常浪费空间的

(4)用动态分配内存,保存返回的值`

char *func()
{
    char *s = malloc(120);
    ...
    return s;
}

----该函数每次调用时都会创建一个新的缓冲区,而且不会覆盖以前的返回值,适合多线程的代码;
—但是对内存管理非常严格,如果还在使用就释放或者内存泄漏(用了没有free)就会发生错误!!

(5)调用者分配内存来保存函数的返回值,还应该同时指定缓冲区的大小

void func(char *result , int size)
{
    strncpy (result,"you are good!",size);
}
buffer = malloc(size);
func(buffer,size);
....
free(buffer);

拓展:
1.char ** 和 const char
**

char *cp;
const char *ccp;
ccp = cp;
//是合法的,左操作数是一个指向有const限定符的char的指针
//右操作数是一个指向无限定符的char的指针
****************
char **cp;
const char **ccp;
ccp = cp;
//是不合法的,操作数不同,两者不相容
//char ** 所指是 char * 
//const char ** 所指是 const char* 

2.const与指针

int const *p  ---> 不能通过p指针去修改所指的变量,但那个变量不是const
int * const p --->指的是p只能指向那个变量,不能指向其他变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值