读书记之《C Primer Plus》

本文是关于《C Primer Plus》的读书体验,作者分享了对指针、预处理指令和多文件编程、文件读写的理解。书中丰富的内容帮助作者巩固了C语言基础,特别强调了指针的强大和预处理指令的运用,同时也提及了二进制文件读写的优势。

英文名:《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语言基础巩固了一下,接下来可能要稍微深入一点,把数据结构和算法方面的书籍翻出来看一下,毕竟光有锄头,没有耕田的本事,也算不上一个合格的庄稼汉子。第一个脚印已然落下,后面能否坚持下来就完全看自己的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值