英文名:《C Primer Plus》(5th)
作者:Stephen Parta
出版社:Sams
新公司的第一个月,重心放在了解项目组的基本情况,另外,通过配合前辈们做些简单的测试工作,学习一些工作上的知识和技能。一个偶然的机会,看到同组的同事在案头放了一本《C Primer Plus》,好奇心的驱使下,向同事借阅了一下,由于时间比较短,当时只看了一下目录和某一章的一小节,然后,决定买一本。
作为C语言的入门级教材,相当喜欢这本书。里面的内容丰富全面,把我大学时候的C语言基础,好好的填补了一下。而且作为将近1000页的英文书来说,读起来还不让人感觉太枯燥,当然时间不可能少花,3个多月的时间,不知不觉的就花在它身上了。
其中,我印象比较深刻的部分有以下几个:
1. 指针
指针对我来说,可以算的上是一个老大难了。从大学一直到现在都还在困扰我,特别是指针的指针,很多时候都会被绕晕,不知道它在上下文中应该是一个地址呢,还是应该是最终的值?还是平时用的比较少,对指针的理解不太彻底。不过,我想这个情况后面应该会有所好转,虽然工作当中接触指针的机会只是在定义函数参数的时候,但是,以后的Linux内核代码应该不会让人失望。
虽然指针学习来比较麻烦,不过它用起来还是相当强大的。到现在我都还对函数指针的使用啧啧称奇,特别是在编写回调函数的时候。
e.g
#include<stdio.h>
#include<string.h>
/*
** operation: compare two values, val1 and val2
** if val1 not equalval2, return 1
** otherwise, return 0
*/
int
compare_two(void const *val1, void const *val2,
int(*foo)(void const *arg1, void const *arg2))
{
return foo(val1, val2);
}
/*
** operation: compare two integer values, arg1 and arg2
** if arg1 not equalarg2, return 1
** otherwise, return 0
*/
int
compare_int(void const *arg1, void const *arg2)
{
if(*(int *)arg1 == *(int *)arg2)
return 0;
else
return 1;
}
int
main(int argc, char **argv)
{
int a = 45;
int b = 35;
int c = 20;
int d = 20;
char *str = "I love theworld";
/*
** whether a equals b
*/
if(0 == compare_two(&a,&b, compare_int))
printf("Ah, a and bare really equal.\n");
else
printf("Uh, a and bcan't reach the agreement.\n");
/*
** whether a and b hold thesame value
*/
if(0 == compare_two(&c,&d, compare_int))
printf("Haha, c and dmay be the twins.\n");
else
printf("Sorry, c saysthat d is a stranger to it.\n");
/*
** whether str contains thestring "I love the world"
*/
if(0 == compare_two(str,"I love the world", strcmp))
printf("It's a truthI love the world.\n");
else
printf("Maybe theworld loves me\n");
return 0;
}
2. 预处理指令和多文件编程
我现在接触的比较多的有两种,一种是用#include引入函数库,还有一种就是宏定义。不过这两个貌似都用的不太好。
#include在程序比较大的时候,用起来相当给力,将程序拆分成一下,将功能函数编写到接口文件里面,主文件只需要保留必要的逻辑流程就好。显然,我这方面的意识还不是太强烈。
我记得在大四做编译原理课程设计的时候,老师让实现一种超微型的图形语言(只有if判断和for循环,只解释sin和cos函数等几个函数)。要构造那个编译器主要要实现一个词法分析器和一个语法分析器,当时,完全没有体会到#include的功用,就直接把词法分析器和语法分析器的代码各自放到一个文件里面,造成文件相当臃肿和凌乱,再加上缺少注释,简直就是一场灾难。当时写的我心力交瘁,才勉强将功能给拼凑出来,一场惨不忍睹的经历。
在书后面将数据结构那部分,作者都会将增删查改和初始化的等功能函数单独提出来,将函数原型写到.h文件里面,然后用.c文件实现。
宏也是一个很强大的特性。目前,我只用宏定义常量和定义宏函数。按照书里的建议,一般在定义宏表达式的时候,在表达式的外面加上括号,避免使用宏的时候,由于优先级的问题,得到不是自己期望的结果。显然,这条建议对我来说还是相当有意义的,因为已经出现过这方面的错误了。
预处理指令感觉是还有很多需要学习和实践的东西,但是在目前的工作中用的比较少,可能还需要平时抽时间多用用。
e.g
#include<stdio.h>
#defineIWEEKDAY 5
#defineIWEEKEND 2
/*
**recommanded define like this:
** #define IWEEK (IWEEKDAY + IWEEKEND)
** the following useage may generate someundesired result
** and it's difficult to debug
*/
#defineIWEEK IWEEKDAY + IWEEKEND
int
main(intargc, char **argv)
{
int idays = 0;
printf("Please give the days you havebeen away: ");
scanf("%d", &idays);
printf("Uh, about %d weeks.\n",idays / IWEEK);
return 0;
}
3. 文件读写
这个地方让人觉得惊艳的是,二进制方式的读写fread和fwrite。之前了解的都是字符方式的读写,fscanf,fprintf,fgets和fputs。字符处理基本都是基于行来操作,每次从文件里面取一行,或者往文件里面写一行。而且,当Windows系统下的文本拿到Unix系统下面,还需要转换之后才能使用,因为Windows文本每行的结尾会有两个看不见的符号——“回车”和“换行”,这两个符号的历史由来在《Unix大学教程》里面作了比较详细的说明。而Unix系统的文本文件每行的结尾只有一个“换行”符号,所以需要转换文本。
而fread和fwrite可以基于记录来操作,可以一次取出多行。在《Beginning Linux Programming》里面,该书的作者就是以结构作为记录项,利用二进制的读写的方式将需要存储的信息写到文件里面,之后要用到的时候,再用相同的方式进行读,将信息填充到结构体里面。
e.g
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
/*
** definethe struct to record
** thestudent scores
*/
typedefstruct
{
int math;
int english;
int chinese;
}STD_SCORE;
int
main(intargc, char **argv)
{
FILE *fp;
size_t record_operate;
size_t std_size = sizeof(STD_SCORE);
int i = 0;
STD_SCORE student_scores[10];
STD_SCORE student_tmp;
/*
** open the file to read and write
*/
if((fp = fopen("datafile","w+b")) == NULL)
{
fprintf(stderr, "Can't open the file<datafile>\n");
exit(1);
}
/*
** initialize the students' scores withrandom numbers
*/
srand(time(NULL));
for(i = 0; i < 10; i++)
{
student_scores[i].math = rand() % 101;
student_scores[i].english = rand() % 101;
student_scores[i].chinese = rand() % 101;
printf("student %02d, math: %d\n", i + 1, student_scores[i].math);
printf("student %02d, english:%d\n", i + 1, student_scores[i].english);
printf("student %02d, chinese:%d\n", i + 1, student_scores[i].chinese);
}
/*
** then write these records into the file
*/
record_operate = 0;
record_operate = fwrite(student_scores,std_size, 10, fp);
if(record_operate != 10)
{
fprintf(stderr, "Write error\n");
fclose(fp);
exit(-1);
}
#if 0
fflush(fp);
rewind(fp);
#endif
rewind(fp);
/*
** finally read the records from the file andprint
** to examine whether the contents are right
*/
i = 0;
while((record_operate =fread(&student_tmp, std_size, 1, fp)) > 0)
{
printf("math of student %02d is: %d\n", i + 1,student_tmp.math);
printf("english of student %02d is:%d\n", i + 1, student_tmp.english);
printf("chinese of student %02d is:%d\n", i + 1, student_tmp.chinese);
}
fclose(fp);
return 0;
}
把C语言基础巩固了一下,接下来可能要稍微深入一点,把数据结构和算法方面的书籍翻出来看一下,毕竟光有锄头,没有耕田的本事,也算不上一个合格的庄稼汉子。第一个脚印已然落下,后面能否坚持下来就完全看自己的了。
本文是关于《C Primer Plus》的读书体验,作者分享了对指针、预处理指令和多文件编程、文件读写的理解。书中丰富的内容帮助作者巩固了C语言基础,特别强调了指针的强大和预处理指令的运用,同时也提及了二进制文件读写的优势。

1万+

被折叠的 条评论
为什么被折叠?



